C++;回调以将文本发送回C# 我是C++新手。我已经被告知使用C++的“回调”是最好的解决办法。这是我的情况 我有一个用C++编写的DLL 此DLL有一个启动服务的方法,该服务通过C#代码运行(这很好) 当DLL中的服务运行时,我希望DLL将文本传递回C代码,这只是进度代码,如“第一阶段开始”和“第一阶段完成”

C++;回调以将文本发送回C# 我是C++新手。我已经被告知使用C++的“回调”是最好的解决办法。这是我的情况 我有一个用C++编写的DLL 此DLL有一个启动服务的方法,该服务通过C#代码运行(这很好) 当DLL中的服务运行时,我希望DLL将文本传递回C代码,这只是进度代码,如“第一阶段开始”和“第一阶段完成”,c#,c++,dll,callback,C#,C++,Dll,Callback,我环顾四周,有人告诉我实现这一点的最佳方法是使用回调,我真的不知道如何实现这一点。有人有什么建议或文章可以让我看看吗?请包含C++,因为我在C++中没有经验。 干杯回调只是代表的一种特殊用法。正常模型的外观如下所示: public class MyCaller { public OtherClass otherClassInstance; public void CallbackMethod() {...} public void UsesTheCallback()


我环顾四周,有人告诉我实现这一点的最佳方法是使用回调,我真的不知道如何实现这一点。有人有什么建议或文章可以让我看看吗?请包含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()
   }
}
DWORD _declspec( dllexport ) WINAPI RegisterTheCallback
(
   DWORD (WINAPI *lpfnCallback)( DWORD param1, DWORD param2 )
)
{
// Store lpfnCallback somewhere so that it can be called later
...
}
此模型的优点在于,任何具有定义的“签名”(参数和返回类型)的方法都可以用作回调。这是一种“松散耦合”的形式,代码不依赖于知道对象是什么,只依赖于它做什么,因此可以在代码不知道差异的情况下将对象交换到另一个对象


上面的例子都是C#。当您使用C++ DLL中的外部函数时,您可能会处理一个简单的指向该方法的ItpTR类型。当定义外部方法的C#接口时,您应该能够将此指针作为委托“封送”,这样该方法看起来就像普通的C#方法。

可能有更干净的方法,但下面是我用来使其工作的一些步骤

定义委托和将其传递到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还在使用它):

然后在某个地方初始化它:

  mCmdCallback = new CallbackFn( YourCallback );
然后将其传递到您的DLL:

RegisterTheCallback( mCmdCallback );
并定义将接收调用的实际方法:

  private uint YourCallback( uint param1, uint param2 )
  {
    // report progress etc.
  }
DLL中的代码可能如下所示:

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()
   }
}
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++到C语言,

< P>可以简单地将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

这可以将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
编辑:
有关详细信息,请参见此处:



嗨,谢谢你的回复,但是我刚才提到我没有C++经验(嗯……4天!)你有一个用C++代码来显示C++的网站吗?这不显示任何C++。嗨,你能不能包括任何C++ +??:你可以添加更多的信息来澄清它的非托管端。C++代码会导致一些错误,还有什么需要添加来让它工作吗?“是什么错误?”马克·威尔金斯:是的!这是有效的……C++已经建立好了,我还没有做C部分。我可以用方法名(data)调用C++中的这个函数;我在C++中尝试过这个部分并得到了一些错误:TyPulfEffess(Sy-StDeLay*回调)(PCWSTR)。;静态回调gui;//将委托分配给函数指针u declspec(dllexport)void u stdcall CSharp_GuiWriter(void*jarg1){回调arg1=(回调)0;arg1=(回调)jarg1;gui=arg1;}//调用(*gui)(_T(“生成C#打印此文本”))对不起,这里是我的错误:错误C2065:“PCWSTR”:未声明的标识符错误C2165:“左侧修改器”:不能修改指针到数据错误C2513:‘VaC++’:在“=”错误之前没有声明变量C38 61:‘yt’:标识符没有发现错误C44:缺少类型指定符-int假设。注意:C++不支持默认int错误C271:':重新定义;不同的基本types@BenVoigt:谢谢你,我已经排除了一半的错误,我所剩下的唯一错误是:错误C38 61:‘t’:标识符没有发现错误C44:缺少类型指定符-int假设。注意:C++不支持默认int错误C271:‘GUI’:重新定义;不同的基本类型是:(*GUI)(*GUI)“让C打印这个文本));当我得到三个错误时,需要额外的东西:错误C44:缺少类型指定符-int假设。注意:C++不支持默认int错误C23 73:“GUI”:重新定义;不同类型修改器错误C2440:“初始化”:不能从“conchar(24)”转换为“int *”它定义的顶部:TyPulf无效(u stdcall*回调)(PCWSTR);静态回调gui;…你当然需要把调用放在一个函数中。这对OP一点帮助都没有。我想是的。他想做的就是从C++/C调用一个C++/C++函数。这甚至不需要回调。有一个MS支持示例如何做,他可以通过谷歌找到,上面就是他需要的str信息这个例子只处理了int型的,我添加了C++代码并建立了它,我添加了C,它是如何构建的,但是我如何从C*YEH.FUNKY中访问字符串?你成功地实现了这个问题的工作解决方案吗?你使用回调吗?也许这个线程中的一些建议的解决方案?我看到了另一个有类似PR的线程。问题:提前谢谢,很抱歉问了这么多问题:D