Reputation: 1039
I would like to trigger a function call in (pure) managed code, whenever a certain trigger is received in native code. I do not specifically a specific kind of trigger, it can be a callback, virtual method override, signal, event, or something along those lines...
My software stack is a large native code base in C++, then a thin C++/CLI wrapper, and finally a C# application with WPF GUI. I can edit the full software stack. The C++ code base is event-driven using signals/slots, like libevent or Qt employ them. Now, consider a C++ slot viewUpdateRequested()
that should trigger a re-rendering in the C# WPF GUI.
I found that I can get a trigger from C++/CLI to C#, by creating an event handler in C++/CLI, that C# can subscribe to. Then I can trigger the event in C++/CLI, and even pass some arguments. However, that gets me only half the way, from C++/CLI upwards in the software stack. I still need to go from native to C++/CLI.
I'm under the impression that in pure native code, I can not emit a C# event, because that would require compiling with /clr
, and that in turn makes the class a shallow dummy that can not hold any native members, which finally breaks my signal/slot implementation. Am I somehow missing something here?
I did find some way to go from native code to C++/CLI, by passing a function pointer from C++/CLI to native code. But this leads to the following code stack, that looks ugly to me:
native code -(function pointer)-> C++/CLI -(event handler)-> C#/WPF
So what are my options to get the event or trigger all the way from pure native code all the way to C#?
Is there something I'm overlooking? What would be a "clean design" solution?
Upvotes: -1
Views: 100
Reputation: 36629
It was some time ago I coded c++/cli, and even longer since I coded pure c++. But assuming your c++/cli project references your native project you should be able to do something like this.
class MyNativeInterface{
public:
virtual void RaiseEvent() = 0;
public interface class IMyManagedInterface{
void RaiseEvent();
}
class MyNativeClass : MyNativeInterface{
gcroot<IMyManagedInterface^> managed;
public:
MyNativeClass(IMyManagedInterface^ managedReference){
managed = managedReference;
}
void RaiseEvent(){
managed->RaiseEvent();
}
}
public class MyManagedClass : IMyManagedInterface{
public event EventHandler MyEvent ;
public void RaiseEvent()=> MyEvent?.Invoke(this, EventArgs.Empty);
}
The difficult part is often how to create/connect all the objects to each other, but this depends on your overall architecture.
because that would require compiling with /clr, and that in turn makes the class a shallow dummy that can not hold any native members, which finally breaks my signal/slot implementation.
I'm not really a c++/cli expert, but I was able to turn on the /clr flag for some c++ projects with no or minimal changes. This allows both managed (ref) classes to hold pointers to native classes and native classes to hold references to managed classes (with gcroot<>
). In my experience it made interop quite a bit easier compared to our original plan with a separate c++/cli interop layer. But our goal was to migrate to C#, so the .Net dependency was not a problem. I don't know what you mean by "shallow dummy", nor your "signal/slot implementation", but it might be worth an hour or two just trying to turn on the flag and see if things break.
Upvotes: 1