C ++回调将文本发送回C#

我是C ++的新手。 我被告知使用C ++的“回调”是最好的解决方案。 这是我的情况。

我有一个用C ++编写的DLL
这个DLL有一个方法来启动通过C#代码运行的服务(这很好)
当DLL中的服务运行时,我希望DLL将文本传回C#代码,这只是进度代码,例如“第一阶段开始”和“第一阶段完成”

我环顾四周,并被告知实现这一点的最好方法是使用回调,我真的不知道如何实现这一点。 有没有人有任何建议或文章我可以看看? 请包含C ++,因为我没有C ++经验。

干杯

您只需将C#字符串传递回C ++,将C ++字符串传递给C#即可。 要求是字符串是unicode,分配方法是SysAllocString而不是malloc。 您需要转换为unicode的任何ASCII字符串。

const wchar_t* theString = L"hello"; BSTR bstr = SysAllocString(theString); DoSomething(bstr); SysFreeString(bstr); 

这就是注册C#dll

 Assembly asm = Assembly.LoadFile (@"c:\temp\ImageConverter.dll"); RegistrationServices regAsm = new RegistrationServices(); bool bResult = regAsm.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase); 

这将Unicode转换为ASCII,反之亦然。

 inline BSTR Cstring2VBstring(char *szString) { WCHAR* res = NULL; BSTR bs; DWORD n; char *sz = NULL; if (*szString && szString) { sz = strdup(szString); n = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, NULL, 0); if (n) { res = (WCHAR*) malloc(n * sizeof(char) ); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, res, n); } } bs = SysAllocString( (const OLECHAR*) res); free(sz); return bs; } // C String to BSTR conversion (2) BSTR Cstringn2VBstring(char *szString, int dwSize) { WCHAR* res = NULL; BSTR bs; DWORD n = (DWORD) dwSize; char *sz = NULL; if (*szString) { sz = (char*) malloc(dwSize); memcpy(sz, szString, dwSize); n = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, n, NULL, 0); if(n) { res = (WCHAR*) malloc(n * sizeof(char) ); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, res, n); } } bs = SysAllocStringLen( (const OLECHAR*) res, n); free(sz); return bs; } 

和.NET代码:

 Namespace TestLibrary2 ' Interface declaration. ' Public Interface ICalculator Function Add(ByVal Number1 As Integer, ByVal Number2 As Integer) As Integer Function Subtract(ByVal Number1 As Long, ByVal Number2 As Long) As Long Function ReturnValue() As String Function Concat(ByVal Number1 As String, ByVal Number2 As String) As String Sub Concat2(ByVal Number1 As String, ByVal Number2 As String) Function isTrue(ByVal bInputvalue As Boolean) As Boolean Function isTrue2(ByRef bInputvalue As Boolean) As Boolean End Interface ' Interface implementation. ' Public Class ManagedClass Implements ICalculator Public Function Add(ByVal Number1 As Integer, ByVal Number2 As Integer) As Integer Implements ICalculator.Add Return Number1 + Number2 End Function Public Function Subtract(ByVal Number1 As Long, ByVal Number2 As Long) As Long Implements ICalculator.Subtract Try System.IO.File.WriteAllText("c:\temp\subtract.txt", "Subtracted: ") Catch ex As Exception MsgBox(ex.Message) End Try Return Number1 - Number2 End Function Public Function Concat(ByVal Number1 As String, ByVal Number2 As String) As String Implements ICalculator.Concat Try System.IO.File.WriteAllText("c:\temp\Concat.txt", "Nummer1: " + Number1 + vbCrLf + "Nummer2:" + Number2) Catch ex As Exception MsgBox(ex.Message) End Try Dim strReturnValue As String = Number1 + Number2 Return strReturnValue End Function Public Sub Concat2(ByVal Number1 As String, ByVal Number2 As String) Implements ICalculator.Concat2 Console.WriteLine("moo") End Sub Public Function ReturnValue() As String Implements ICalculator.ReturnValue Dim x As String = "moooooo" Return x End Function Public Function isTrue(ByVal bInputvalue As Boolean) As Boolean Implements ICalculator.isTrue If bInputvalue = True Then Return True End If Return False End Function Public Function isTrue2(ByRef bInputvalue As Boolean) As Boolean Implements ICalculator.isTrue2 If bInputvalue = True Then Return True End If Return False End Function End Class End Namespace 

编辑:
请点击此处了解更多信息:

http://support.microsoft.com/kb/828736
http://msdn.microsoft.com/en-us/library/ms734686.aspx

可能有更简洁的方法,但这里有一些我用来使它工作的步骤。

定义委托和将其传递给DLL的函数。 参数将被发送回C#委托:

  public delegate uint CallbackFn( uint param1, uint param2 ); [DllImport("yourdll.dll", CallingConvention=CallingConvention.Winapi, EntryPoint="RegisterTheCallback" )] private static extern uint RegisterTheCallback( CallbackFn pfn ); 

创建一个变量来存储委托。 确保这不会超出范围。 在我的测试中,我发现GC会回收它(它没有“意识到”我的DLL仍在使用它):

  CallbackFn mCmdCallback = null; 

然后在某处初始化它:

  mCmdCallback = new CallbackFn( YourCallback ); 

然后将其传递给您的DLL:

 RegisterTheCallback( mCmdCallback ); 

并定义将接收调用的实际方法:

  private uint YourCallback( uint param1, uint param2 ) { // report progress etc. } 

DLL中的代码可能如下所示:

 DWORD _declspec( dllexport ) WINAPI RegisterTheCallback ( DWORD (WINAPI *lpfnCallback)( DWORD param1, DWORD param2 ) ) { // Store lpfnCallback somewhere so that it can be called later ... } 

然后,DLL中的代码可以在需要时使用适当的数据调用它:

 ret = (lpfnCallback)( 234, 456 ); 

这很棘手,但这是代码 – 花了我一段时间才弄明白 – 赞成赞成。 你能从C DLL调用C#DLL吗?

这个例子是非托管的c ++到C#。

回调只是委托的特定用途。 普通模型看起来像这样:

 public class MyCaller { public OtherClass otherClassInstance; public void CallbackMethod() {...} public void UsesTheCallback() { //The callback method itself is being passed otherClassInstance.MethodWithCallback(CallbackMethod); } } public class OtherClass { public delegate void CallbackDelegate() public void MethodWithCallback(CallbackDelegate callback) { //do some work, then... callback(); //invoke the delegate, "calling back" to MyCaller.CallbackMethod() } } 

这个模型的优点是任何具有定义的“签名”(参数和返回类型)的方法都可以用作回调。 它是一种“松散耦合”forms,其中代码不依赖于知道对象是什么,只是它所做的事情,因此对象可以换成另一个对象,而代码不知道差异。

上面的例子都在C#中。 当您使用C ++ DLL中的extern函数时,您可能正在处理IntPtr类型,该类型是指向该方法的简单指针。 在定义该extern方法的C#接口时,您应该能够将此指针“编组”为委托,因此该方法看起来像普通的C#方法。