-1

Hello I'm new to C++ and trying to handle an event raised by a managed class ServerApi::Request The managed class is a COM interface that I have imported into my visual studio project using the "add reference" tool to select the ServerApi.dll file. All of the methods seem to be working as expected but the event handler onDataReady() is never executed. Here is my code:

//Event receiver
ref class EventReceiver {
public:

    void OnDataReady() {

        cout << "dataReadyHandler called" << endl;

    }

    void AddHandlers(ServerApi::Request^ request) {

        request->DataReady += gcnew DataReadyDelegate(this, &EventReceiver::OnDataReady);
    }

    void RemoveHandlers(ServerApi::Request^ request) {

        request->DataReady -= gcnew DataReadyDelegate(this, &EventReceiver::OnDataReady);

    }

};

void executeEventRequest() {

    ServerApi::RequestManager^ requestManager = gcnew ServerApi::RequestManager();

    ServerApi::Request^ request = requestManager->CreateMethod("...");

    EventReceiver^ eventReceiver = gcnew EventReceiver();
    eventReceiver->AddHandlers(request);
    request->Execute();
    eventReceiver->RemoveHandlers(request);

}

The request object raises a DataReady event after the Execute() method is called on it. I know that the data is ready almost instantaneously from polling. What am I missing?

First Edit

This is how I originally waited after request->Execute() is called:

    EventReceiver^ eventReceiver = gcnew EventReceiver();
    eventReceiver->AddHandlers(request);
    request->Execute();
    clock_t beginTime = clock();

    // wait for 2 seconds
    while(clock() < beginTime + 2000) {

        // do nothing

    }

    eventReceiver->RemoveHandlers(request);

There is no blocking on the Execute method control is returned immediately.

  • 2
    A very typical reason to not get expected events is when you lie with the [STAThread] attribute on your Main() entrypoint. Which requires you to call Application::Run() and never block. Do talk to the author or owner of the component about the runtime environment you must provide to make this component behave well. – Hans Passant Mar 02 '17 at 16:21
  • 1
    Like Hans alluded to, threads using COM *must* pump messages via `GetMessage` (or `PeekMessage`), `DispatchMessage`. For .NET apps, the Framework provides two methods both named `Application::Run()` (depending on the namespace, there's one for WinForms and a different one for WPF) – Ben Voigt Mar 03 '17 at 02:47
  • What you're missing is any logic for deciding how long to wait for events. Or does Execute return only after all events? If so, it needs to pump messages. – Ben Voigt Mar 03 '17 at 14:40

1 Answers1

-1

I managed to get the DataReady event to handle by using System::Windows::Forms::Application::DoEvents() in the executeEventRequest() method:

EventReceiver^ eventReceiver = gcnew EventReceiver();
eventReceiver->AddHandlers(request);
request->Execute();
clock_t beginTime = clock();

// wait for 2 seconds
while(clock() < beginTime + 2000) {

    System::Windows:Forms::Application::DoEvents() // this line enabled events handling

}

eventReceiver->RemoveHandlers(request);