将 C++ 回调提交给 .NET C++/CLI Wrapper
Submitting C++ callback to .NET C++/CLI Wrapper
我一直在网上搜索以下问题的解决方案,但无法解决。
我们有一个用 C++ 编写的大型单体应用程序。为了 "upgrade" 它进入新世界,我们在其中嵌入了 WPF 视图,该视图是在 C++/CLI 托管包装器中生成的。初始调用是通过智能指针从 C++ 进行的。
if (SUCCEEDED(ptr.CreateInstance(__uuidof(CloudServices))))
{
CRect rect;
pWndContainer->GetWindowRect(rect);
ptr->InitializeControl((LONG)pWndContainer->GetSafeHwnd(), ID_AIS_BALANCEMATRIX, bstr.m_str, rect.Width(), rect.Height());
}
并且在包装器中 class 接口声明为
interface ICloudServices : IDispatch{
[id(1)] HRESULT InitializeControl([in] LONG hWndParent, [in] LONG controlTypeId, [in] BSTR parameters, [in] LONG width, [in] LONG height);
并且在包装器中是这样实现的
STDMETHODIMP CCloudServices::InitializeControl(LONG hWndParent, LONG controlTypeId, BSTR parameters, LONG width, LONG height) { ... }
问题:
一切正常,wpf 视图在 C++ 应用程序中呈现。现在我们需要将信息从 .NET 代码发送回 C++。
如何将非托管回调函数作为 InitializeControl 的参数提交给包装器以及如何 use/convert 将其提交给相关的 .net 委托?
See desired solution schematic
我们似乎没有找到解决此问题的有效方法,因此我们最终使用 WM_DATACOMPY 将信息发回。不是最有效的方法,但它有效。
public void SendCommand(Command command)
{
// Find the target window handle.
IntPtr hTargetWnd = NativeMethod.FindWindow("OurAppNameInCpp", null);
if (hTargetWnd == IntPtr.Zero)
{
throw new Exception("Sending '{0}'. Unable to find the \"OurAppNameInCpp\" window".Args(command.AsXmlMessage));
}
// Prepare the COPYDATASTRUCT struct with the data to be sent.
MyStruct myStruct;
myStruct.Message = command.AsXmlMessage;
// Marshal the managed struct to a native block of memory.
int myStructSize = Marshal.SizeOf(myStruct);
IntPtr pMyStruct = Marshal.AllocHGlobal(myStructSize);
try
{
Marshal.StructureToPtr(myStruct, pMyStruct, true);
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.cbData = myStruct.Message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(myStruct.Message);
// Send the COPYDATASTRUCT struct through the WM_COPYDATA message to
// the receiving window. (The application must use SendMessage,
// instead of PostMessage to send WM_COPYDATA because the receiving
// application must accept while it is guaranteed to be valid.)
NativeMethod.SendMessage(hTargetWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
int result = Marshal.GetLastWin32Error();
if (result != 0)
throw new Exception("SendMessage(WM_COPYDATA) failed w/err 0x{0:X}".Args(result));
}
finally
{
Marshal.FreeHGlobal(pMyStruct);
}
}
我一直在网上搜索以下问题的解决方案,但无法解决。
我们有一个用 C++ 编写的大型单体应用程序。为了 "upgrade" 它进入新世界,我们在其中嵌入了 WPF 视图,该视图是在 C++/CLI 托管包装器中生成的。初始调用是通过智能指针从 C++ 进行的。
if (SUCCEEDED(ptr.CreateInstance(__uuidof(CloudServices))))
{
CRect rect;
pWndContainer->GetWindowRect(rect);
ptr->InitializeControl((LONG)pWndContainer->GetSafeHwnd(), ID_AIS_BALANCEMATRIX, bstr.m_str, rect.Width(), rect.Height());
}
并且在包装器中 class 接口声明为
interface ICloudServices : IDispatch{
[id(1)] HRESULT InitializeControl([in] LONG hWndParent, [in] LONG controlTypeId, [in] BSTR parameters, [in] LONG width, [in] LONG height);
并且在包装器中是这样实现的
STDMETHODIMP CCloudServices::InitializeControl(LONG hWndParent, LONG controlTypeId, BSTR parameters, LONG width, LONG height) { ... }
问题: 一切正常,wpf 视图在 C++ 应用程序中呈现。现在我们需要将信息从 .NET 代码发送回 C++。
如何将非托管回调函数作为 InitializeControl 的参数提交给包装器以及如何 use/convert 将其提交给相关的 .net 委托?
See desired solution schematic
我们似乎没有找到解决此问题的有效方法,因此我们最终使用 WM_DATACOMPY 将信息发回。不是最有效的方法,但它有效。
public void SendCommand(Command command)
{
// Find the target window handle.
IntPtr hTargetWnd = NativeMethod.FindWindow("OurAppNameInCpp", null);
if (hTargetWnd == IntPtr.Zero)
{
throw new Exception("Sending '{0}'. Unable to find the \"OurAppNameInCpp\" window".Args(command.AsXmlMessage));
}
// Prepare the COPYDATASTRUCT struct with the data to be sent.
MyStruct myStruct;
myStruct.Message = command.AsXmlMessage;
// Marshal the managed struct to a native block of memory.
int myStructSize = Marshal.SizeOf(myStruct);
IntPtr pMyStruct = Marshal.AllocHGlobal(myStructSize);
try
{
Marshal.StructureToPtr(myStruct, pMyStruct, true);
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.cbData = myStruct.Message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(myStruct.Message);
// Send the COPYDATASTRUCT struct through the WM_COPYDATA message to
// the receiving window. (The application must use SendMessage,
// instead of PostMessage to send WM_COPYDATA because the receiving
// application must accept while it is guaranteed to be valid.)
NativeMethod.SendMessage(hTargetWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
int result = Marshal.GetLastWin32Error();
if (result != 0)
throw new Exception("SendMessage(WM_COPYDATA) failed w/err 0x{0:X}".Args(result));
}
finally
{
Marshal.FreeHGlobal(pMyStruct);
}
}