提交c++回调到.net c++ /CLI Wrapper

Submitting C++ callback to .NET C++/CLI Wrapper

本文关键字:c++ CLI Wrapper 回调 提交 net      更新时间:2023-10-16

我一直在网上搜索以下问题的解决方案,但无法得到我的头围绕它。

我们有一个用c++编写的大型单片应用程序。为了将其"升级"到新的世界,我们将WPF视图嵌入到一个c++/CLI管理的包装器中。初始调用由c++通过一个smartpointer进行。

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

在包装器类中,接口声明为

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和我如何使用/转换它到相关的。net委托?

参见所需解决方案示意图

我们似乎没有找到这个问题的有效解决方案,所以我们最终使用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);
        }
    }