在C++中处理C# COM事件

6
我已成功创建了一个带有事件的C# COM对象。请查看以下代码,
    [Guid("1212674-38748-45434")]
    public interface ICalculator
    {
        int Add(int Num1, int Num2);
    }

    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [Guid("3453674234-84444-84784")]
    public interface ICalculatorEvents
    {
        [DispId(1)]
        void Completed(int Result);
    }

    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(ICalculatorEvents))]
    [Guid("87457845-945u48-4954")]
    public class Calculator : ICalculator
    {
        public delegate void CompletedDelegate(int result);
        public event CompletedDelegate Completed;
        public Add(int Num1, int Num2)
        {
            int Result = Num1 + Num2;
            if(Completed != null)
                Completed(Result);
        }
    }

我已经在C++控制台应用程序中导入了这个COM对象,并可以调用“Add()”方法。但我不确定如何在我的C++应用程序中处理“Completed”事件。您能否给予建议?我希望在该事件发生时在控制台上显示结果值。
请看下面的C ++应用程序代码。此处永远无法处理“Completed”事件,进入无限循环状态。
    #import "Calculator.tlb"
    using namespace Calculator;
    int Flag = 0;
    class HandleEvent : public ICalculatorEvent
    {
        public:
            HandleEvent(void);
            ~HandleEvent(void);
            HRESULT __stdcall QueryInterface(const IID &, void **);
            ULONG __stdcall AddRef(void) { return 1; }
            ULONG __stdcall Release(void) { return 1; }
            HRESULT __stdcall Completed(int Result);
    };

    HandleEvent::HandleEvent(void)
    {
    }

    HRESULT HandleEvent::Completed(int Result)
    {
        printf("Addition Completed, Result: %d", Result);
        Flag = 1;
    }

    HRESULT HandleEvent::QueryInterface(const IID & iid,void ** pp)
    {
        if (iid == __uuidof(ICalculatorEvent) || iid == __uuidof(IUnknown))
        {
            *pp = this;
            AddRef();
            return S_OK;
        }
        return E_NOINTERFACE;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        CoInitialize(NULL);
        Flag = 0;
        ICalculatorPtr pCalc(__uuidof(Calculator));
        pCalc->Add(5, 6);

        do
        {
        }while(Flag == 0);

        CoUninitialize ();
        return 0;
    }

感谢您提前的支持。
谢谢。

我认为你的Completed事件对象不会被调用,因为它始终为空。哪个类实现了ICalculatorEvents接口? - Kamran Amini
ICalculatorEvents 在 C++ 应用程序中实现。请查看以下 C++ 代码: - GeekCandy
抱歉我无法在评论中添加代码。所以我已经将其添加到我的第一篇帖子中。谢谢。 - GeekCandy
在 _tmain() 函数中,pCalc->Add() 应该如何知道调用哪个 ICalculatorEvent 实现对象?这里没有 EventHandler 对象。如果有的话,在 Add() 方法中,Completed 委托不指向任何方法。 - Kamran Amini
我假设当在Add方法中调用事件时,HandleEvent::Completed(int Result)方法会被调用?我完全是COM的新手,我觉得我可能没有理解到某些东西。 - GeekCandy
2个回答

0

我发现在C++客户端中进行COM初始化应该使用

    CoInitializeEx(NULL, COINIT_MULTITHREADED);

针对来自C# (.NET) COM服务器的异步事件处理,否则C++客户端只能在CoUninitialize()调用后接收事件。

事件处理类:

    class EventWrapper : public IDispEventSimpleImpl<1, EventWrapper, &DIID_RumCardCOMEvents >
    {
    public:
        // now you need to declare a sink map - a map of methods handling the events
        BEGIN_SINK_MAP(EventWrapper)
            SINK_ENTRY_INFO(1, DIID_RumCardCOMEvents, 0x1, isCardInserted, &cardInserted)
            SINK_ENTRY_INFO(1, DIID_RumCardCOMEvents, 0x2, isCardRemoved, &cardRemoved)
            // event interface id (can be more than 1)---+      |      |                   |
            // must match dispid of your event -----------------+      |                   |
            // method which handles the event  ------------------------+                   |
            // type information for event, see below --------------------------------------+
        END_SINK_MAP()

    // declare the type info object. You will need one for each method with different signature.
        // it will be defined in the .cpp file, as it is a static member
        static _ATL_FUNC_INFO cardInserted;  // 'placeholder' object to carry event information (see below)
        static _ATL_FUNC_INFO cardRemoved;  // 'placeholder' object to carry event information (see below)

        // method which handles the event
        STDMETHOD (isCardInserted)(unsigned char type)
        { 
            // usually it is defined it in the .cpp file
            cout << "isCardInserted: " << (int)type << endl;
            return 0;
        }

        STDMETHOD (isCardRemoved)()
        { 
            // usually it is defined it in the .cpp file
            cout << "isCardRemoved" << endl;
            return 0;
        }
    };

主函数:

    int main()
    {
        CoInitializeEx(NULL, COINIT_MULTITHREADED);
        try
        {
            EventWrapper ev;
            ev.DispEventAdvise(/*COM interface*/);
            // receiving events
            ev.DispEventUnadvise(/*COM interface*/);
        }
        catch (_com_error& e)
        {
            cout << "Exception: " << e.ErrorMessage() << endl;
        }

        CoUninitialize();
        return 0;
    }

"&DIID_RumCardCOMEvents"是什么?RumCardCOMEvents是你的COM事件接口吗?"DIID"部分从哪里来? - taiteilijaumbra
是的,这是COM事件接口,抱歉我不记得细节了,因为那是很久以前的事情。 - Aliaksei Plashchanski

0
如果你想使用委托,你不需要声明一个接口。将_tmain()函数更改为以下内容:
int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    Flag = 0;

    EventHandler evh ;
    ICalculatorPtr pCalc(__uuidof(Calculator));
    pCalc->Completed = &evh.Completed() ;
    pCalc->Add(5, 6);

    do
    {
    }while(Flag == 0);

    CoUninitialize ();
    return 0;
}

如果你想使用一个接口,请尝试这个。
 [ClassInterface(ClassInterfaceType.None)]
 [ComSourceInterfaces(typeof(ICalculatorEvents))]
 [Guid("87457845-945u48-4954")]
 public class Calculator : ICalculator
 {
     public ICalculatorEvents callbackObject ;

     public Add(int Num1, int Num2)
     {
         int Result = Num1 + Num2;
         if(callbackObject != null)
             callbackObject.Completed(Result);
     }
 }

并将_tmain()方法更改为以下内容。

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    Flag = 0;

    EventHandler evh ;
    ICalculatorPtr pCalc(__uuidof(Calculator));
    pCalc->callbackObject = &evh ;
    pCalc->Add(5, 6);

    do
    {
    }while(Flag == 0);

    CoUninitialize ();
    return 0;
}

“EventHandler”应该是一个全局类还是你自己定义的类?VS2019告诉我“标识符未定义”。我需要包含一些头文件吗? - taiteilijaumbra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接