I have a cpp project, a cpp cli project and a c# win forms project. I want to fire a method from my native cpp code and catch it in c# project. How can i do this?
There can be multiple approaches to answer this question, because the dependency requirement between those projects is important. I will try to answer for the most common (i guess) case: in which you already have a native C++ library and you want to use that library in a C# application. In that scenario the C# project depends on the native library project. In such a case you can utilize a gateway cli/c++ library to transform native c++ events to .NET events.
Here is a complete code sample, but before that, please note:
It may not be the shortest solution, but it works fine. Also it can provide more control on transforming native data to .net types.
I used this approach in VS 2005. I dont know if there is a better instrument in newer versions of VS for that specific interoperability purpose.
If your native event is triggered from a thread other than the GUI thread, then beware of that.
The Native Library:
#ifndef _NATIVE_CODE_H_
#define _NATIVE_CODE_H_
//NativeCode.h
//A simple native library which emits only one event.
#include <stdlib.h>
#include <iostream>
using namespace std;
#define NATIVELIBRARY_API __declspec(dllexport)
//An argument class to wrap event parameters
class NativeEventArgs{
public:
//a 32bit integer argument
//any other primitives can be here, just be careful about the byte size
int argInt32;
//null terminated ascii string
const char* argString;
//null terminated wide/unicode string
const wchar_t* argWString;
};
//A simple mechanism to fire an event from native code.
//Your library may have a DIFFERENT triggering mechanism (e.g. function pointers)
class INativeListener
{
public:
virtual void OnEvent(const NativeEventArgs& args)=0;
};
//The actual native library code, source of native events
class NATIVELIBRARY_API NativeCode
{
public:
NativeCode()
:theListener_(NULL)
{}
//Listener registration method
void registerListener(INativeListener* listener) {
theListener_ = listener;
}
//this is the very first source of the event
//native code emits the event via the listener mechanism
void eventSourceMethod() {
//... other stuff
//fire the native event to be catched
if(theListener_){
//prepare event parameters
NativeEventArgs args;
wstring wstr(L"A wide string");
string str("A regular string");
//build-up the argument object
args.argInt32 = 15;
args.argString = str.c_str();
args.argWString = wstr.c_str();
//fire the event using argument
theListener_->OnEvent( args );
}
}
private:
//native code uses a listener object to emit events
INativeListener* theListener_;
};
#endif
Gateway Library Sample:
//GatewayCode.h
//GatewayLibrary is the tricky part,
//Here we listen events from the native library
//and propagate them to .net/clr world
#ifndef _GATEWAY_CODE_H_
#define _GATEWAY_CODE_H_
#include "../NativeLibrary/NativeCode.h" //include native library
#include <vcclr.h> //required for gcroot
using namespace System;
using namespace System::Runtime::InteropServices;
namespace GatewayLibrary{
//.net equvelant of the argument class
public ref class DotNetEventArg{
internal:
//contructor takes native version of argument to transform
DotNetEventArg(const NativeEventArgs& args) {
//assign primitives naturally
argInt32 = args.argInt32;
//convert wide string to CLR string
argWString = Marshal::PtrToStringUni( IntPtr((void*)args.argWString) );
//convert 8-bit native string to CLR string
argString = Marshal::PtrToStringAnsi( IntPtr( (void*)args.argString) );
//see Marshal class for rich set of conversion methods (e.g. buffers)
}
private:
String^ argString;
String^ argWString;
Int32 argInt32;
public:
//define properties
property String^ ArgString {
String^ get() {
return argString;
}
}
property String^ ArgWString {
String^ get() {
return argWString;
}
}
property Int32 ArgInt32 {
Int32 get() {
return argInt32;
}
}
};
//EventGateway fires .net event when a native event happens.
//It is the actual gateway class between Native C++ and .NET world.
//In other words, It RECEIVES NATIVE events, TRANSFORMS/SENDS them into CLR.
public ref class EventGateway {
public:
//ctor, its implementation placed below
EventGateway();
//required to clean native objects
~EventGateway();
!EventGateway();
//the SENDER part
//.net event stuff defined here
delegate void DotNetEventHandler(DotNetEventArg^ arg);
event DotNetEventHandler^ OnEvent;
private:
//our native library code
//notice you can have pointers to native objects in ref classes.
NativeCode* nativeCode_;
//the required device to listen events from the native library
INativeListener* nativeListener_;
internal: //hide from .net assembly
//the RECEIVER part, called when a native event received
void OnNativeEvent(const NativeEventArgs& args){
//you can make necessary transformation between native types and .net types
//create .net argument using native argument
//required conversion is done by DotNetEventArg class
DotNetEventArg^ dotNetArgs = gcnew DotNetEventArg(args);
//fire .net event
OnEvent( dotNetArgs );
}
};
}
//A concrete listener class. we need this class to register native library events.
//Its our second gateway class which connects Native C++ and CLI/C++
//It basically gets events from NativeLibary and sends them to EventGateway
class NativeListenerImp : public INativeListener {
public:
NativeListenerImp(gcroot<GatewayLibrary::EventGateway^> gatewayObj ){
dotNetGateway_ = gatewayObj;
}
//this is the first place we know that a native event has happened
virtual void OnEvent(const NativeEventArgs& args) {
//inform the .net gateway which is responsible of transforming native event to .net event
dotNetGateway_->OnNativeEvent(args);
}
private:
//class member to trigger .net gateway.
//gcroot is required to declare a CLR type as a member of native class.
gcroot<GatewayLibrary::EventGateway^> dotNetGateway_;
};
////ctor and dtors of EventGateway class
GatewayLibrary::EventGateway::EventGateway()
{
nativeCode_ = new NativeCode();
//note; using 'this' in ctor is not a good practice
nativeListener_ = new NativeListenerImp(this);
//register native listener
nativeCode_->registerListener(nativeListener_);
}
GatewayLibrary::EventGateway::~EventGateway()
{
//call the non-deterministic destructor
this->!EventGateway();
}
GatewayLibrary::EventGateway::!EventGateway()
{
//clean up native objects
delete nativeCode_;
delete nativeListener_;
}
#endif
And the final application in C# (or in any other .net language):
//Program.cs
//C# the final evet consumer application
using System;
using System.Collections.Generic;
using System.Text;
using GatewayLibrary;
namespace SharpClient
{
class Program
{
static void Main(string[] args)
{
//create the gateway
EventGateway gateway = new EventGateway();
//listen on .net events using the gateway
gateway.OnEvent += new EventGateway.DotNetEventHandler(gateway_OnEvent);
}
static void gateway_OnEvent( DotNetEventArg args )
{
//use the argument class
Console.WriteLine("On Native Event");
Console.WriteLine(args.ArgInt32);
Console.WriteLine(args.ArgString);
Console.WriteLine(args.ArgWString);
}
}
}
Related
I have written the following code that uses .net4 to run. Since I am using this code in Unity3D that doesn't support .net4 I had to convert it to native code. I am using "Unmanaged Exports" to export it to a native library.
I can call this function from Unity3D and it works fine.
Now I want to add events to my library and then access these events from another C# code in Unity3D.
My question is: How to create a callback event and register a function in my library to call when it is done? I know how to create an event in a Managed c# code. But note that here I am exporting it to native code and I need to use the event in the native code. So, My library does something as a native code and then I want it to fire a callback function to tell Unity3D that it is done.
Here is my library code:
[DllExport("SayText", CallingConvention = CallingConvention.Cdecl)]
public static void SayText()
{
var task = new Task(() =>
{
var synth = new SpeechSynthesizer();
synth.SetOutputToNull();
synth.SetOutputToWaveFile("D:\\test3.wav");
synth.SpeakCompleted += SynthOnSpeakCompleted;
synth.SpeakAsync("This is a test text");
});
task.Start();
}
private static void SynthOnSpeakCompleted(object sender, SpeakCompletedEventArgs speakCompletedEventArgs)
{
var synth = (SpeechSynthesizer)sender;
synth.SpeakCompleted -= SynthOnSpeakCompleted;
synth.SetOutputToDefaultAudioDevice();
// I want to trigger an event here so the application knows that the file has been created.
}
And here is how I'm calling this function from Unity3D:
[DllImport("mylib", EntryPoint = "SayText")]
public static extern void SayText();
I can't be sure it will solve your issue but I tried something similar with ios plugin.
Here is the C# side of the plugin:
public class CSharpWrapper
{
// Create delegate type
public delegate void TestDelegate();
// Connection with the native side
[DllImport("__Internal")]
private static extern void externMethod( TestDelegate onCompletion);
private static Action callback = null;
// This is most likely the part you are looking for.
// That method is marshalled so it will pass its address to the native side
// When native calls it we can add any code within
[MonoPInvokeCallback(typeof(TestDelegate))]
private static void ManagedTest()
{
if(callback != null) { callback(); }
callback = null;
}
#endif
public static void CallMethod(Action<string> onCompletion)
{
callback = onCompletion;
// Here we pass our own method that is marshalled for native side
externMethod(ManagedTest);
}
}
Then I have a C section in the .m file.
extern "C"
{
typedef void (*TestCallback)();
void externMethod(TestCallback testCallback)
{
// Here communication with Objective-C code
}
}
Maybe this will get you somewhere near completion. It is also possible to add parameters, just list them as usual and the marshalling attribute will do it all for you.
I was following this example to use a c# delegate as a c++ callback.
My wrapper looks like this:
// GLFWWrapper.h
#pragma once
using namespace System;
namespace GLFWWrapper {
typedef void(__stdcall *KEY_CALLBACK)(int, int, int, int);
public ref class Window {
public:
void setKeyCallback(KEY_CALLBACK fp);
static KEY_CALLBACK csharpKeyCallback;
...
};
}
// GLFWWrapper.cpp
#include "stdafx.h"
#include "GLFWWrapper.h"
namespace GLFWWrapper {
void cppKeyCallback(GLFWwindow * window, int key, int scancode, int action, int mods) {
if (Window::csharpKeyCallback) {
Window::csharpKeyCallback(key, scancode, action, mods);
}
}
void Window::setKeyCallback(KEY_CALLBACK fp) {
csharpKeyCallback = fp;
}
...
}
The cppKeyCallback function is a callback I set in another function (glfwSetKeyCallback(m_ptr, cppKeyCallback);). The csharpKeyCallback is supposed to be the delegate from my C# project. In the example I linked to above it is only explained how I can set a delegate from inside my wrapper. But how can I set the delegate from my C# project? When I try to call setKeyCallback from my C# project I get an error Window.setKeyCallback(?) is not supported by the language.
You seem to be missing the managed part of the instruction:
#pragma managed
public delegate void keyCallback(int, int, int, int);
void Window::setKeyCallback(keyCallback^ fp) {
csharpKeyCallback = fp;
}
In order to pass a reference to a function instance (delegate) from C# to C++\CLI you need to declare it i.e. declare a managed delegate. This can be done either in C# or in C++\CLI.
In your code the KEY_CALLBACK is an unmanaged function declaration. Thus it is "Not supported by the language". C# side cannot use it as a delegate declaration.
In order to avoid such a mess I myself always keep my C++\CLI projects clear of any managed declarations and provide those in an additional C# class library that is referenced from both the C++\CLI wrapper and the C# side.
Edit: Do not forget to put the ^ sign after the managed reference type in the managed method declaration or the compiler is going to bust you with an error 'A delegate type is not allowed here'.
In a c# assembly I've got a global prism CompositeCommand to subscribe to like this:
private static readonly CompositeCommand __myCommand = new CompositeCommand();
public static CompositeCommand MyCommand
{
get { return _myCommand; }
}
From c# I can subscribe to this command using:
[...].MyCommand.RegisterCommand(new DelegateCommand<MyClass>((c) => c.Something()));
My problem: I need to subscribe to the command from managed c++, and I got no idea how the function signature needs to be to be used in DelegateCommand. Most of the time I get errors like:
error C2664: 'Microsoft::Practices::Prism::Commands::DelegateCommand::DelegateCommand(System::Action ^)': conversion of parameter 1 from 'void (__clrcall *)(MyNameSpace::MyClass ^)' in 'System::Action ^' not possible.
How do I subscribe to a c# command? Or is there some other way to listen to an event (I can replace the CompositeCommand with something different).
Thanks!
I'm going to assume that you're using managed C++ - anything else, and there's bigger issues to worry about.
It looks like you're getting linking errors to your C# type. As such, I don't think the issue is related to any problems with Prism. In order for the C++ managed compiler to link to your C# assembly, you need to produce the C# assembly with an XML documentation file (see the Build tab in your properties). Is that enabled in your project?
I used the following as a very simple proof of concept, where TestObject is defined in the C# assembly referenced by the C++ DLL. This compiled without any issues.
Header file:
void __clrcall CommandCallback(Project::Infrastructure::TestObject^ param);
public ref class ManagedModule : IModule
{
public:
ManagedModule();
virtual void __clrcall Initialize();
private:
};
Implementation:
ManagedDLL::ManagedModule::ManagedModule()
{
}
void __clrcall ManagedDLL::ManagedModule::Initialize()
{
Action<Project::Infrastructure::TestObject^>^ newAction =
gcnew Action<Project::Infrastructure::TestObject^>(&CommandCallback);
DelegateCommand<Project::Infrastructure::TestObject^>^ newCommand =
gcnew DelegateCommand<Project::Infrastructure::TestObject^>(newAction);
Project::Infrastructure::Commands::ApplicationExitCommand->RegisterCommand(newCommand);
return;
}
void __clrcall CommandCallback(Project::Infrastructure::TestObject^ param)
{
return;
}
I am attempting to invoke managed events from native c++, by using a managed wrapper for a native class, and then using the managed wrapper via dll from C#. However, I receive a InvalidCastException runtime error that I don't know how to resolve, or even what it means. My implementation is as follows:
The header for ManagedClass is
#pragma once
#include "NativeClass.h"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace NativeLibrary
{
public delegate void ReportProgressDelegate(Double ^completionPercentage);
public ref class ManagedClass
{
public:
ManagedClass();
event ReportProgressDelegate ^OnReportProgress;
void RaiseReportProgress(Double ^completionPercentage);
void CallTestFunction();
private:
NativeClass *_NativeClass;
ReportProgressDelegate ^ReportProgress;
};
}
while ManagedClass source file is
#include "stdafx.h"
#include "ManagedClass.h"
#include "TestFunction.h"
using namespace NativeLibrary;
ManagedClass::ManagedClass()
{
_NativeClass = new NativeClass();
ReportProgress = gcnew ReportProgressDelegate(this, &ManagedClass::RaiseReportProgress);
_NativeClass->ProgressFunction = (void (*)(double))Marshal::GetFunctionPointerForDelegate(ReportProgress).ToPointer();
void ManagedClass::RaiseReportProgress(System::Double ^completionPercentage)
{
OnReportProgress(completionPercentage);
}
void ManagedClass::CallTestFunction()
{
TestFunction(*_NativeClass);
}
}
Here NativeClass is defined in its own header file
#pragma once
class NativeClass
{
public:
NativeClass() {};
void (*ProgressFunction)(double);
};
as is TestFunction
#pragma once
#include "NativeClass.h"
void TestFunction(NativeClass& nativeClass)
{
nativeClass.ProgressFunction(50.0);
return;
}
I set up a C# program to test the event. My C# program consists of
NativeLibrary.ManagedClass managedClass = new NativeLibrary.ManagedClass();
managedClass.OnReportProgress += new NativeLibrary.ReportProgressDelegate(managedClass_OnReportProgress);
managedClass.CallTestFunction();
where the managedClass_OnReportProgress event is defined as
void managedClass_OnReportProgress(ValueType completionPercentage)
{
MessageBox.Show("report progress event triggered");
}
The problem occurs when I call the function CallTestFunction. When I step through using the debugger, it successfully makes it inside the native TestFunction. However, when it reaches the closing brace of TestFunction, I get the runtime error:
"InvalidCastException was unhandled. No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))"
I'm really clueless as to how to resolve this problem, or what the source of it is. Suggestions?
public delegate void ReportProgressDelegate(Double ^completionPercentage);
Double is a value type. You should only use the ^ for reference types. I'm guessing it bombs when it tries to convert a boxed Double (an Object) to a native double. Delete the ^
I have an unmanaged dll with a class "MyClass" in it.
Now is there a way to create an instance of this class in C# code? To call its constructor? I tried but the visual studio reports an error with a message that this memory area is corrupted or something.
Thanks in advance
C# cannot create class instance exported from native Dll. You have two options:
Create C++/CLI wrapper. This is .NET Class Library which can be added as Reference to any other .NET project. Internally, C++/CLI class works with unmanaged class, linking to native Dll by standard C++ rules. For .NET client, this C++/CLI class looks like .NET class.
Write C wrapper for C++ class, which can be used by .NET client with PInvoke. For example, over-simplified C++ class:
class MyClass()
{
public:
MyClass(int n){data=n;}
~MyClass(){}
int GetData(){return data;}
private:
int data;
};
C API wrapper for this class:
void* CreateInstance()
{
MyClass* p = new MyClass();
return p;
}
void ReleaseInstance(void* pInstance)
{
MyClass* p = (MyClass*)pInstance;
delete p;
}
int GetData(void* pInstance)
{
MyClass* p = (MyClass*)pInstance;
return p->GetData();
}
// Write wrapper function for every MyClass public method.
// First parameter of every wrapper function should be class instance.
CreateInstance, ReleaseInstance and GetData may be declared in C# client using PInvoke, and called directly. void* parameter should be declared as IntPtr in PInvoke declaration.
The solution is create C++/CLI wrapper like:
#include "DllExportClass.h"
public ref class ManagedOperationHelper
{
public:
double Sum(double add1, double add2)
{
CDllExportClass obj;
double ret=obj.Sum(add1, add2);
return ret;
}
double Mult(double mult1, double mult2)
{
CDllExportClass obj;
double ret=obj.Mult(mult1, mult2);
return ret;
}
};
where CDllExportClass is the class exported from native code. Above is the .h of the C++/CLI. Take care to let find the lib to this dll. Put the dll and the lib in the same directory and compile the C++/CLI code.In the managed code directory put the native dll and the C++/CLI dll. In the managed project put the reference of the C++/CLI project. Instanciate in the maged code the C++/CLI class like:
ManagedOperationHelper obj = new ManagedOperationHelper();
double ret=obj.Sum(10, 20);
It's all.
You can not use unmanged C++ code directly in C#. The interoperability can be done using PInvoke. There are a lot of issues related to this topic, especially when calling functions which have pointers as arguments.
The basic procedure goes like this:
C# part
namespace MyNamespace {
public class Test {
[DllImport("TheNameOfThe.dll")]
public static extern void CreateMyClassInstance();
public void CallIt() {
CreateMyClassInstance(); // calls the unmanged function via PInvoke
}
}
}
C++ part
class MyClass {
public: MyClass() { /** Constructor */ }
};
MyClass* staticObject;
extern "C" void CreateMyObjectInstance() {
staticObject = new MyClass(); // constructor is called
}