如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#
Posted
技术标签:
【中文标题】如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#【英文标题】:How to pass a string from C++-CLI to C# via C++-CLI callbacks and delegates 【发布时间】:2011-04-26 00:03:08 【问题描述】:我有一个围绕从 C# 调用的标准 C++ 库的 C++-CLR 包装器。为了从库中接收状态消息,我使用通过 Marshal::GetFunctionPointerForDelegate 分配给 C++ 代码中的回调的委托。
我花了很长时间才开始工作,而且我非常非常接近(我认为)。调用了 C# 委托,但字符串未正确跨边界传递。
当我从 C++ 代码中调用 TakesCallback("Test String") 时,我只会在 C# 函数中返回垃圾。
---原始C++类和回调函数---
class Solver
private:
std::string TakesCallback(const std::string message)
return cb(message);
public:
// Declare an unmanaged function type that takes a string
typedef std::string (__stdcall* ANSWERCB)(const std::string);
ANSWERCB cb;
;
--- 从托管包装器设置回调的函数----
// Set the delegate callback
void ManagedSolver::SetMessageCallback(SendMessageDelegate^ sendMessageDelegate)
_sendMessage = sendMessageDelegate;
// Use GetFunctionPointerForDelegate to get the pointer for delegate callback
IntPtr ip = Marshal::GetFunctionPointerForDelegate(sendMessageDelegate);
_solver->cb = static_cast<Solver::ANSWERCB>(ip.ToPointer());
--- C# 函数传递给 C++\CLR 包装器 SetMessageCallBack ----
private void Message(string message)
XtraMessageBox.Show(message, "Done", MessageBoxButtons.OK);
【问题讨论】:
您确定您的意思是托管 C++? (我认为)Visual Studio 2003 不再支持 C++ 的托管扩展。C++/CLI 是它的替代品,它是一种完全不同的语言...... 嗨,比利,对不起,你当然是对的。我的包装器是围绕标准 C++ 库的 C++/CLR。我已经更新了标题和正文。 好的,我已经解决了,std::string 不能与互操作一起使用,因为这里声明了多种实现***.com/questions/874551/stdstring-in-c,只要 *** 允许我,我就会回来回答这个问题到。 传递 message.c_str() 代替,与默认编组兼容。 谢谢汉斯,这对我有用。 【参考方案1】:我已经使用the code from this page 几个月了,我觉得它非常好。它只是一个可以跨项目复制的头文件,它可以快速而干净地完成工作。
你用例如
std::wstring s = clix::marshalString<E_UNICODE>(myCliString);
或
System::String^ s = clix::marshalString<E_ANSI>(mystdstring);
它可以双向工作,让您指定所需的编码(ANSI、UTF8 或 Windows 的 unicode——实际上是 UTF16)。
【讨论】:
【参考方案2】:C++ std::string
和 .NET System::String
不可互换。 C# 不能使用第一个,本地 C++ 代码不能使用第二个。您需要的是一个接受std::string
并在调用委托之前将其转换为System::String^
的C++/CLI 函数。
【讨论】:
【参考方案3】:一般来说,std c++ 类不能与 C# 进行封送处理。如果您将 C++ 代码构建为 Unicode,我建议您将代码更改为以下内容:
C++
// Declare an unmanaged function type that takes a string
typedef int (__stdcall* ANSWERCB)(LPCTSTR);
C#
private void Message([MarshalAs(UnmanagedType.LPWStr)]string message)
XtraMessageBox.Show(message, "Done", MessageBoxButtons.OK);
看看下面example from MSDN
【讨论】:
【参考方案4】:C++(非托管)
class DllContext
public:
typedef void (__stdcall *LOG_CALLBECK)(const wchar_t* LogString);
DllContext(LOG_CALLBECK WriteLog) // Constructor
this->WriteLog = WriteLog;
this->WriteLog(L"Creating сontext..."); // UNICODE string!
private:
LOG_CALLBECK WriteLog;
// Export function
SENDAUDIOCLIENT_API DllContext *CreateContext(DllContext::LOG_CALLBECK WriteLog)
return new DllContext(WriteLog);
C#
class MyClass
private delegate void WriteLog_Delegate([MarshalAs(UnmanagedType.LPWStr)]string Mess);
private WriteLog_Delegate WriteLog;
[DllImport("My.dll", EntryPoint = "?CreateContext@@YAPAVDllContext@@P6GXPB_W@Z@Z", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CreateContext(WriteLog_Delegate WriteLogProc);
private IntPtr Context = IntPtr.Zero;
public MyClass()
this.WriteLog = new WriteLog_Delegate(this.WriteLogToConsole);
this.Context = CreateContext(this.WriteLog);
private void WriteLogToConsole(string Mess)
Console.WriteLine("Message from unmanaged code: 0", Mess);
【讨论】:
以上是关于如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#的主要内容,如果未能解决你的问题,请参考以下文章