2012-10-05 118 views
8

C#プログラムから、SendMessageでWM_COPYDATAを使用して、従来のC++/cli MFCアプリケーションと通信したいとします。C#からC++へWM_COPYDATAで処理して文字列でstructを渡す

文字列オブジェクトを含む管理構造体を渡したいと思います。

私は、SendMessageで使用するためのC++アプリケーションのハンドルを見つけることができます。

私が知りたくないビットは、構造体とその文字列がマーシャリングされ、もう一方の端で読み取られる方法です。特にそれは非blittablesを含んでいるので。

これは実現可能だと人々は考えていますか? 私はそれに取り組むつもりですが、この種のことをやってくれた人に感謝します。

これは、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; 
} 

答えて

9

私はそれを働かせています。

単純なアプローチは、構造体を単一の文字列にシリアル化して文字列を転送することです。 swhistlesoftのブログは役に立ちましたhttp://www.swhistlesoft.com/blog/2011/11/19/1636-wm_copydata-with-net-and-c

これは単純なメッセージを提供するのに十分かもしれません。 構造体は、必要に応じてもう一方の端で再構築できます。

文字列の任意の数の構造体をそのまま整列させる場合は、固定サイズでなければなりません。それは私が得られなかった主なものです。

MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9) 

は、基本的に私達の場合にTCHAR szTestされたC++サイズに合わせてサイズを設定する[9]。

C++からC#からWM_COPYDATAを介したネット構造体は、(/ 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の++で文字列を受信するには

COPYDATASTRUCT cd = new COPYDATASTRUCT(); 
    cd.dwData = 2; 

    cd.cbData = parameters.Length + 1; 
    cd.lpData = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(parameters); 

    IntPtr cdBuffer = IntPtrAlloc(cd); 

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

を:

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++でceive構造体:

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

+0

...など、これはデモコードで、スタイリングの面で作業を必要とし、例外などの取り扱いに注意してくださいありがとうございました。 WM_COPYDATAのカスタム構造体をマーシャリングするために、あなたのサンプルはこのサイトで見つかった唯一のものでした。 –

1

渡されるデータは、データを受信するアプリケーションにアクセス可能なオブジェクトではないにポインタまたは他の参照を含めることはできません。

したがって、文字列をCOPYDATASTRUCT.lpDataにパックする必要があります。あなたは各文字列の最大長さを持っているなら、あなたは固定長の構造に埋め込むことができます

typedef struct tagMYDATA 
{ 
    char s1[80]; 
    char s2[120]; 
} MYDATA; 

あなたが唯一の可変長文字列を持っている場合は、最後に、文字列を入れて、文字列データに続くヘッダを使用することができますあなたは、複数の可変長文字列を使用している場合

​​

あなたはまだ、ヘッダーを使用して、すべての文字列のためのより多くのスペースを加えたダブルヌルターミネータを割り当てる、または1羽のXML列にすべてをシリアライズすることができます。

関連する問題