我有一个 C# 应用程序通过一些 C++/CLI 编组代码调用本机 C++ DLL:
C# --> C++/CLI --> C++(无 CLR)
我希望 DLL 在运行时将字符串更新发送回调用应用程序。目前,非托管 DLL 将输出写入 stdout。本质上我需要在 UI 中捕获此输出。
在其他情况下,如果我对非托管 exe 进行脱壳,则可以通过简单地将 stdout 从被调用者重定向到绑定到文本面板的 UI 数据中的字符串缓冲区来实现。
我无法选择使用 P/Invoke 调用 DLL 或将其脱壳为 exe,因为互操作层执行非基本类型的基本编组。非托管 DLL 没有 CLR 支持,因此必须保持这种方式。
我使用代表取得的成功有限(http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.100).aspx http://msdn.microsoft.com/en-us/library/367eeye0%28v=vs.100%29.aspx),因为托管世界和非托管世界似乎总是在某个地方发生冲突。以链接中的示例为例,从 C++/CLI 传递一个伪装成本机函数指针的托管委托到 DLL 是可行的,但回调是在 C++/CLI 类的范围之外定义的,因此无法访问从 C++/CLI 传入的托管委托调用层 (C#)。
理想情况下,我想定义一个接受非托管字符串的类,并且可以将它们转换为托管字符串并回调到 UI 层,但如果此类对托管字符串有必要的支持,则无法将其传递给非托管代码。
我可能缺少一个简单的重定向技巧,该技巧允许捕获标准输出,而无需在层之间传递字符串(例如,从通过委托接收的 C++/CLI 重定向标准输出)。如果这是不可能的,任何人都可以建议替代技术吗?
托管C++:
using namespace System::Runtime::InteropServices;
using namespace System;
namespace BusinessObjectInterop
{
typedef void (__stdcall *UnmanagedFP)(std::string);
//Callback function
public delegate void SetProgressDelegate(std::string);
void SetProgress(std::string s) {
Console::WriteLine(s);
//set m_progress - could use managed delegate passed from UI and exposed in static method in CIntermediate?
}
public ref class CIntermediate
{
public:
//Invoked by managed (C#) UI
void ^ CallBusinessObject(Object ^ data, String ^ progress)
{
//Do some data marshalling...
//...
m_progress = progress;
//Create wrapper for managed delegate
SetProgressDelegate^ fp = gcnew SetProgressDelegate(SetProgress);
GCHandle gch = GCHandle::Alloc(fp);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
UnmanagedFP cb = static_cast<UnmanagedFP>(ip.ToPointer());
//Call unmanaged DLL
BusinessObject::DoStuff(cb);
gch.Free();
}
private:
String ^ m_progress;
};
}
提前致谢。