Ho funzionato.
Un approccio semplice consiste nel serializzare la struttura in una stringa singola e trasferire una stringa. Il blog di swhistlesoft era utile http://www.swhistlesoft.com/blog/2011/11/19/1636-wm_copydata-with-net-and-c
Questo potrebbe essere sufficiente per fornire la semplice messaggistica. La struttura può essere ricostruita all'altra estremità se necessario.
Se una struttura con qualsiasi numero di stringhe deve essere dichiarata come-è, allora deve essere una dimensione fissa, questa è la cosa principale che non stavo ottenendo. Il
MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9)
definisce sostanzialmente la dimensione corrisponda alla dimensione C++ che nel nostro caso è un TCHAR szTest [9];
Per trasferire a.struct Net tramite WM_COPYDATA da C# a C++ (/ CLI) ho dovuto fare come segue:
[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;
};
Per inviare una stringa:
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;
Per ricevere stringa in C++:
else if(pCDS->dwData == 2)
{
//copydata message
CString csMessage = (LPCTSTR)pCDS->lpData;
OutputDebugString("Copydata message received: " + csMessage);
}
Per inviare la struttura:
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);
Per re ceive struct in 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;
}
Si prega di notare che questo è il codice demo e esigenze di lavoro in termini di stile, gestione delle eccezioni, ecc, ecc ...
Grazie. Per il marshalling della struttura personalizzata in WM_COPYDATA, il tuo esempio è stato l'unico lavoro trovato su questo sito. –