Взаимодействие между надстройкой Outlook VSTO и внешним приложением C ++ - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть приложение на C ++, и я пишу новую надстройку для Outlook, которая, я думаю, будет с VSTO.Я хочу иметь связь между тем и пытаюсь найти лучший способ сделать это.В MS docs они упоминают, как представить ваш COM-класс внешним решениям, используя RequestComAddInAutomationService.Я очень новичок в COM, но я прочитал некоторые онлайн и получил следующее решение.Я прочитал, что вы должны создать надстройку (для x86 в качестве моей версии Outlook, а не AnyCPU), взять созданный файл .tlb и преобразовать его в .tlh, используя директиву #import, а затем #include файл .tlh должен иметь соответствующие типы.

ThisAddin.cs

namespace FirstOutlookAddIn
{

public partial class ThisAddIn
{
    Outlook.Inspectors inspectors;
    private AddInUtilities gUtilities;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        inspectors = this.Application.Inspectors;
        inspectors.NewInspector +=
        new Microsoft.Office.Interop.Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
    }

    void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
    {
        Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
        if (mailItem != null)
        {
            if (mailItem.EntryID == null)
            {
                gUtilities.SetMailItem(mailItem);
                mailItem.Subject = "This text was added by using code";
                mailItem.Body = "This text was added by using code";
            }

        }
    }

    protected override object RequestComAddInAutomationService()
    {
        if (gUtilities == null)
            gUtilities = new AddInUtilities();

        return gUtilities;
    }

    private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
    {
        // Note: Outlook no longer raises this event. If you have code that 
        //    must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
    }

    #region VSTO generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InternalStartup()
    {
        this.Startup += new System.EventHandler(ThisAddIn_Startup);
        this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
    }

    #endregion
}

}

IAddInUtilities.cs

using System.Runtime.InteropServices;
namespace FirstOutlookAddIn
{
    [ComVisible(true)]
    public interface IAddInUtilities
    {
        void MyExportedFunction();
    }
}

AddInUtilities.cs

using Outlook = Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;
namespace FirstOutlookAddIn
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class AddInUtilities : StandardOleMarshalObject, IAddInUtilities
    {
        Outlook.MailItem globalMailItem;
        public void SetMailItem(Outlook.MailItem item) => globalMailItem = item;
        public void MyExportedFunction()
        {
            globalMailItem.Body = "I was called from outside!";
        }
    }
}

main.cpp

//#import "FirstOutlookAddIn.tlb" named_guids raw_interfaces_only

#include <iostream>
struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive-
#include <Objbase.h>
#include "Debug\FirstOutlookAddIn.tlh"

int main() {
    CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    FirstOutlookAddIn::IAddInUtilities* pIFace;
    // create the object and obtain a pointer to the sought interface
    auto res = CoCreateInstance(
        FirstOutlookAddIn::CLSID_AddInUtilities,
        nullptr,
        CLSCTX_LOCAL_SERVER,
        FirstOutlookAddIn::IID_IAddInUtilities,
        (LPVOID*)&pIFace);
    if (res != S_OK)
    {
        std::cout << "Failed with: " << res;
    }
    auto res1 = pIFace->MyExportedFunction(); // use the object
    std::cout << "Res: " << res1;
    pIFace->Release(); // free the object
    CoUninitialize();
}

Проблема заключается вCoCreateInstance возвращает REGDB_E_CLASSNOTREG Class not registered.Соответствующее дерево реестра выглядит следующим образом:

HKEY_LOCAL_MACHINE \ SOFTWARE \ WOW6432Node \ Classes \ CLSID {5008A102-08E5-3F59-AADD-03875524CAD0} = FirstOutlookAddIn.AddInUtilities Computer \ HKEYM_ \ WID \ WID \ WALD \ WALDWINS \ \ COW_64_W64 \ WDK \ W64 \ \ \ \ W64 \ \ \ \ \ \ W64 \ \ \ \ W64 \ \ \ W64 \ \5008A102-08E5-3F59-AADD-03875524CAD0} \ InprocServer32: Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\CLSID{5008A102-08E5-3F59-AADD-03875524CAD0}\InprocServer32 Компьютер \ HKEY_LOCAL_MACHINE \ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ \ WOW6432Node \ Classes \ CLSID {5008A102-08E5-3F59-AADD0.05 0 0 0 0 0 5 0 0 5 0 0 5 0 0 5 0 0 5 0 0 5 0 0 0 038 0: Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\CLSID{5008A102-08E5-3F59-AADD-03875524CAD0}\InprocServer32\1.0.0.0 Компьютер \ HKEY_LOCAL_MACHINE \ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ \ WOW6432Node \ Classes \ CLSID {5008A102-08E5-3F59-AADD-03875524CAD0} \ ProgId = FirstOutlookAddIn.Правильно ли я понимаю, что у меня есть возможность загрузки этой библиотеки из Outlook.exe и возможности вызывать в ней функции из внешнего приложения?Заранее спасибо !!!

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

После некоторого копания я понял это.Я использую пример CppAutomateOutlook от Microsoft

. Он имеет 2 варианта реализации, один использует интеллектуальные указатели COM (например, spMail->Subject = _bstr_t(L"Feedback of All-In-One Code Framework");), а другой - интерфейс IDispatch.Я использовал второй вариант и изменил CoCreateInstance на GetActiveObject, чтобы я мог взаимодействовать с уже запущенным экземпляром Outlook.Это мой текущий код:

DWORD WINAPI AutomateOutlookByCOMAPI(LPVOID lpParam)
{
    // Initializes the COM library on the current thread and identifies 
    // the concurrency model as single-thread apartment (STA). 
    // [-or-] CoInitialize(NULL);
    // [-or-] CoCreateInstance(NULL);
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

    // Define vtMissing for optional parameters in some calls.
    VARIANT vtMissing;
    vtMissing.vt = VT_EMPTY;

    // Get CLSID of the server
    CLSID clsid;
    HRESULT hr;

    // Option 1. Get CLSID from ProgID using CLSIDFromProgID.
    LPCOLESTR progID = L"Outlook.Application";
    hr = CLSIDFromProgID(progID, &clsid);
    if (FAILED(hr))
    {
        wprintf(L"CLSIDFromProgID(\"%s\") failed w/err 0x%08lx\n", progID, hr);
        return 1;
    }
    // Option 2. Build the CLSID directly.
    /*const IID CLSID_Application = 
    {0x0006F03A,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
    clsid = CLSID_Application;*/

    // Get the IDispatch interface of the running instance

    IUnknown *pUnk = NULL;
    IDispatch *pOutlookApp = NULL;
    hr = GetActiveObject(
        clsid, NULL, (IUnknown**)&pUnk
    );

    if (FAILED(hr))
    {
        wprintf(L"GetActiveObject failed with w/err 0x%08lx\n", hr);
        return 1;
    }

    hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pOutlookApp);
    if (FAILED(hr))
    {
        wprintf(L"QueryInterface failed with w/err 0x%08lx\n", hr);
        return 1;
    }

    _putws(L"Outlook.Application is found");

    IDispatch *comAddins = NULL;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pOutlookApp, L"COMAddins", 0);
        comAddins = result.pdispVal;
    }

    IDispatch *myAddin = NULL;
    {
        VARIANT x;
        x.vt = VT_BSTR;
        x.bstrVal = SysAllocString(L"FirstOutlookAddIn");

        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_METHOD, &result, comAddins, L"Item", 1, x);
        myAddin = result.pdispVal;

        VariantClear(&x);
    }

    IDispatch *myAddinObj = NULL;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, myAddin, L"Object", 0);
        myAddinObj = result.pdispVal;
    }

    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_METHOD, &result, myAddinObj, L"MyExportedFunction", 0);
    }

    // ... Cleanup code
}
0 голосов
/ 20 сентября 2018

Вы не должны создавать экземпляр этого класса COM из своего приложения C ++ - создайте экземпляр объекта Outlook.Application, используйте коллекцию Application.COMAddins, чтобы добраться до своего надстройки, затем используйте свойство COMAddin.Object, чтобы получитьИнтерфейс, реализованный вашим дополнением.
См., например, https://blogs.msdn.microsoft.com/andreww/2007/01/15/vsto-add-ins-comaddins-and-requestcomaddinautomationservice/

...