C#到C++;使用带字符串的WM_COPYDATA传递结构进行处理

C#到C++;使用带字符串的WM_COPYDATA传递结构进行处理,c#,interop,c++-cli,marshalling,wm-copydata,C#,Interop,C++ Cli,Marshalling,Wm Copydata,在c#程序中,我想使用WM#U COPYDATA和SendMessage与传统的c++/cli MFC应用程序进行通信 我想传递一个包含字符串对象的托管结构 < >我可以找到C++应用程序的句柄,以便使用sEndoMeMel.< /P> 我不知道的一点是如何在另一端封送和读取结构及其字符串。特别是因为它包含非飞艇 人们认为这是可行的吗? 我会继续努力,但会通知做过这类事情的人告诉我它是否行不通 下面是一些演示代码,如果它是一个c++/cli程序,那么让它正常工作并不困难。 但是,我希望它位于.N

在c#程序中,我想使用WM#U COPYDATA和SendMessage与传统的c++/cli MFC应用程序进行通信

我想传递一个包含字符串对象的托管结构

< >我可以找到C++应用程序的句柄,以便使用sEndoMeMel.< /P> 我不知道的一点是如何在另一端封送和读取结构及其字符串。特别是因为它包含非飞艇

人们认为这是可行的吗? 我会继续努力,但会通知做过这类事情的人告诉我它是否行不通

下面是一些演示代码,如果它是一个c++/cli程序,那么让它正常工作并不困难。 但是,我希望它位于.Net类库中,以便可以轻松地重复使用

//Quick demonstation code only, not correctly styled
int WINAPI WinMain(HINSTANCE hInstance,
                 HINSTANCE hPrevInstance,
                 LPSTR lpCmdLine,
                 int nCmdShow)
{               
    struct MessageInfo
    {
        int     nVersion;
        char   szTest[ 10 ];        
    };

    MessageInfo sMessageInfo;

    sMessageInfo.nVersion = 100;
    strcpy( sMessageInfo.szTest, "TEST");   

    COPYDATASTRUCT CDS;

    CDS.dwData = 1; //just for test
    CDS.cbData = sizeof( sMessageInfo );
    CDS.lpData = &sMessageInfo;

    //find running processes and send them a message
    //can't just search for "MYAPP.exe" as will be called "MYAPP.exe *32" on a 64bit machine
    array<System::Diagnostics::Process^>^allProcesses = System::Diagnostics::Process::GetProcesses();

    for each (System::Diagnostics::Process^ targetProcess in allProcesses)
    {        
        if (targetProcess->ProcessName->StartsWith("MYAPP", System::StringComparison::OrdinalIgnoreCase))
        {
            HWND handle = static_cast<HWND>(targetProcess->MainWindowHandle.ToPointer());

            BOOL bReturnValue = SendMessage( handle, WM_COPYDATA, (WPARAM)0, (LPARAM)&CDS ) == TRUE;
        }
    }

    return 0;
}
//仅快速演示代码,未正确设置样式
int WINAPI WinMain(HINSTANCE HINSTANCE,
HINSTANCE HPPrevenstance,
LPSTR lpCmdLine,
国际展览(nCmdShow)
{               
结构消息信息
{
内翻;
char-szTest[10];
};
MessageInfo sMessageInfo;
sMessageInfo.Inversion=100;
strcpy(sMessageInfo.szTest,“TEST”);
复制数据结构光盘;
CDS.dwData=1;//仅用于测试
CDS.cbData=sizeof(sMessageInfo);
CDS.lpData=&sMessageInfo;
//查找正在运行的进程并向其发送消息
//不能在64位计算机上搜索名为“MYAPP.exe*32”的“MYAPP.exe”
数组^allProcesses=System::Diagnostics::Process::GetProcesses();
对于每个(所有流程中的系统::诊断::流程^targetProcess)
{        
if(targetProcess->ProcessName->StartWith(“MYAPP”,System::StringComparison::OrdinalIgnoreCase))
{
HWND handle=static_cast(targetProcess->MainWindowHandle.ToPointer());
BOOL-bReturnValue=SendMessage(handle,WM_COPYDATA,(WPARAM)0,(LPARAM)和CDS)==TRUE;
}
}
返回0;
}

来自文档:

正在传递的数据不得包含指针或对接收数据的应用程序无法访问的对象的其他引用

因此,您需要将字符串打包到COPYDATASTRUCT.lpData中。如果每个字符串都有一个最大长度,那么可以将其嵌入固定长度的结构中

typedef struct tagMYDATA
{
   char  s1[80];
   char  s2[120];
} MYDATA;
如果只有一个可变长度字符串,则可以将该字符串放在末尾,并使用后跟字符串数据的标题

typedef struct tagMYDATA
{
   int value1;
   float value2;
   int stringLen;
} MYDATAHEADER;

MyCDS.cbData = sizeof(MYDATAHEADER)+(int)stringData.size();
MyCDS.lpData = new BYTE[MyCDS.cbData];
memcpy(MyCDS.lpData,&dataHeader,sizeof*(MYDATAHEADER);
StringCbCopyA (
    ((BYTE*)MyCDS.lpData)+sizeof*(MYDATAHEADER)
    ,stringData.size()
    ,stringData.c_str());
如果您有多个可变长度字符串,您仍然可以使用一个标题,为每个字符串分配更多的空间,再加上一个双空终止符,或者将所有内容序列化为一个XML字符串。

我已经让它工作了

一种简单的方法是将结构序列化为单个字符串并传输字符串。 swhistlesoft的博客很有帮助

这可能足以提供简单的消息传递。 如果需要,可以在另一端重新构造结构

如果一个包含任意数量字符串的结构要按原样进行封送,那么它必须是固定大小的,这是我没有得到的主要信息。

基本上设置大小与C++大小匹配,在我们的情况下是C++的TCHAR SZTAST(9);p> 为了通过WM#U COPYDATA将.Net结构从c#传输到c++(/cli),我必须执行以下操作:

[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    static extern bool SetForegroundWindow(IntPtr hWnd);

public static uint WM_COPYDATA = 74;

//from swhistlesoft
public static IntPtr IntPtrAlloc<T>(T param)
    { 
        IntPtr retval = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(param)); 
        System.Runtime.InteropServices.Marshal.StructureToPtr(param, retval, false); 
        return (retval); 
    }

//from swhistlesoft
    public static void IntPtrFree(IntPtr preAllocated) 
    { 
        if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home")); 
        System.Runtime.InteropServices.Marshal.FreeHGlobal(preAllocated); 
        preAllocated = IntPtr.Zero; 
    }

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    struct COPYDATASTRUCT
    {
        public uint dwData;
        public int cbData;
        public IntPtr lpData;
    }

    /// <summary>
    /// Dot net version of AppInfo structure. Any changes to the structure needs reflecting here.
    /// struct must be a fixed size for marshalling to work, hence the SizeConst entries
    /// </summary>
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
    struct AppInfoDotNet
    {
        public int   nVersion;            

        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9)]
        public string test;
    };
要在c++中接收字符串,请执行以下操作:

else if(pCDS->dwData == 2)
    {
        //copydata message
        CString csMessage = (LPCTSTR)pCDS->lpData;
        OutputDebugString("Copydata message received: " + csMessage);
    }
要发送结构,请执行以下操作:

            AppInfoDotNet appInfo = new AppInfoDotNet();
            appInfo.test = "a test";

            COPYDATASTRUCT cds3;
            cds3.dwData = 1;
            cds3.cbData = System.Runtime.InteropServices.Marshal.SizeOf(appInfo);

            IntPtr structPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(appInfo));
            System.Runtime.InteropServices.Marshal.StructureToPtr(appInfo, structPtr, false);

            cds3.lpData = structPtr;

            IntPtr iPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(cds3));
            System.Runtime.InteropServices.Marshal.StructureToPtr(cds3, iPtr, false);

            messageReceived = ((int)SendMessage(targetProcess.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, iPtr)) != 0;

            System.Runtime.InteropServices.Marshal.FreeCoTaskMem(iPtr);
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem(structPtr);
要在c++中接收结构,请执行以下操作:

LRESULT CMainFrame::OnCopyData( WPARAM wParam, LPARAM lParam )
{
    LRESULT lResult = FALSE;

    COPYDATASTRUCT *pCDS = (COPYDATASTRUCT*)lParam;

    //Matching message type for struct
    if(pCDS->dwData == 1)
    {
        AppInfo *pAppInfo = (AppInfo*)pCDS->lpData
        lResult = true;
    }

请注意,这是演示代码,需要在样式、异常处理等方面进行工作。

谢谢。对于在WM_COPYDATA中编组自定义结构,您的示例是在该站点上找到的唯一工作。
            AppInfoDotNet appInfo = new AppInfoDotNet();
            appInfo.test = "a test";

            COPYDATASTRUCT cds3;
            cds3.dwData = 1;
            cds3.cbData = System.Runtime.InteropServices.Marshal.SizeOf(appInfo);

            IntPtr structPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(appInfo));
            System.Runtime.InteropServices.Marshal.StructureToPtr(appInfo, structPtr, false);

            cds3.lpData = structPtr;

            IntPtr iPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(cds3));
            System.Runtime.InteropServices.Marshal.StructureToPtr(cds3, iPtr, false);

            messageReceived = ((int)SendMessage(targetProcess.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, iPtr)) != 0;

            System.Runtime.InteropServices.Marshal.FreeCoTaskMem(iPtr);
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem(structPtr);
LRESULT CMainFrame::OnCopyData( WPARAM wParam, LPARAM lParam )
{
    LRESULT lResult = FALSE;

    COPYDATASTRUCT *pCDS = (COPYDATASTRUCT*)lParam;

    //Matching message type for struct
    if(pCDS->dwData == 1)
    {
        AppInfo *pAppInfo = (AppInfo*)pCDS->lpData
        lResult = true;
    }