Allow native C++ components to raise CLR events

Recently I was working on a project that was based on a native C++ library. The project’s GUI was a WPF application that communicated with the native lib via a managed C++/CLI bridge library that contained CLR wrapper classes for the native ones. One major concern was the ability of the native classes to raise events and notify the GUI. An example is reporting the progress of a procedure, allowing the GUI to update a progress bar.

Native C++ does not have something like CLR events. What we need is a kind of delegate that forwards calls to the actual event in the .Net environment. This can be achieved pretty straight forward with a function pointer:

// native C++ code
typedef void tProgressDelegate(double);
typedef tProgressDelegate *ProgressDelegate;

//and somewhere in a class that should be able to notify its progress declare a field of this type:
public:
    void set_progress_delegate(ProgressDelegate);

Alternatively to setting the delegate as a class member it is also possible to pass it as an argument to the procedure whose progress is reported.

For the managed C++/CLI class we need a declaration of the delegate, an appropriate event and a redirection function that actually raises the event. This redirection method must match the function pointer:

// managed C++ code
public delegate void CLRProgressDelegate(double progress);

public ref class MyClass
{
    public:
        event CLRProgressDelegate^ ProgressChanged;
        void raiseProgressChangedEvent(double progress);
}

The implementation of the redirection function is pretty easy. The more interesting part is the creation of a function pointer for this method:

// managed C++ code
void MyClass::initialize()
{
    //Create a new delegate and point it to the member function
    CLRProgressDelegate^ prDel = gcnew CLRProgressDelegate (this, &MyClass::raiseProgressChangedEvent);
    GCHandle gch = GCHandle::Alloc(prDel);
    //Convert the delegate to a function pointer
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(prDel);
    //... and cast it to the appropriate type
    ProgressDelegate fp = static_cast<ProgressDelegate>(ip.ToPointer());
    //set the native function pointer on the native class
    wrapped_object->set_progress_delegate(fp);
}

void MyClass::raiseProgressChangedEvent(double progress)
{
    ProgressChanged(progress);
}

Now you can use the function pointer to raise the CLR event.

Advertisements

, , , , , ,

  1. #1 by Anonymous on April 4, 2014 - 2:13 pm

    Interesting.
    But how do you trig the event in the native c++ class?

  2. #2 by nicoschertler on April 4, 2014 - 2:24 pm

    Since it is a function pointer, you can use it like a regular function. Assuming that you have a field “ProgressDelegate progress” in your class, you can raise the event with “progress(0)” or whatever parameter you like.

  3. #3 by Nicolas on March 22, 2016 - 12:53 pm

    Hi
    I declare a member variable of type ProgressDelegate that is set in the method set_progress_delegate. But I want to send to event calling my variable as a function pointer, I get a violation error. Any idea ?

    An unhandled exception of type ‘System.AccessViolationException’ occurred in ACRControllerClient.dll

    Thanks
    Nicolas

  4. #4 by nicoschertler on March 22, 2016 - 11:32 pm

    Hi Nicolas, due to the brevity of comments, there are some details missing. Please ask your question in a forum or Q&A site (e.g. StackOverflow) with a detailed description and a minimal compilable example. And post a link to your question here, so I can check the question.

  5. #5 by Eirik k on August 29, 2016 - 6:40 pm

    I had a similar issue where the application was crashing with “C++ Run-Time Check failure #0”. I am not entirely sure what the issue is, but I think it has something to do with the calling convention from c# to native c++. I solved it by defining ProgressDelegate like this:

    typedef void(__stdcall *ProgressDelegate)(double value);

    Great article, thanks.

  6. #6 by JackGrinningCat on November 25, 2016 - 3:11 pm

    The implementation misses something to me or I expect something different.
    I see that a GCHandle is used to avoid garbage collection, when gone out of scope/use, of the created delegate object.

    As in this implementation the handle is not saved, it’s lost forever or is a memory leak if the interface no longer need this delegate.

    Might not be a problem as this could be part of an singelton answer to the UI, but as example of use it raises this question to me.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: