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

时间:2011-02-17 15:27:36

标签: c# c++ dll callback

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

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


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


干杯

4 个答案:

答案 0 :(得分:4)

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

定义委托和将其传递给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 );

答案 1 :(得分:3)

您只需将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

答案 2 :(得分:1)

这很棘手,但这是代码 - 花了我一段时间才弄明白 - 赞成赞成。 Can you call a C# DLL from a C DLL?

此示例是非托管c ++到C#。

答案 3 :(得分:0)

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

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()
   }
}

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

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