I am sending a window message from a C# application to a C++ Win32 application. I am using a message via the RegisterWindowMessage()
API.
The string value transfers from C# to C++, but on the C++ side I could not convert it back to a string.
C#
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
_sendMessageID = RegisterWindowMessage("WM_MSG_TEST");
public void SendMessage()
{
IntPtr buffer = Marshal.StringToBSTR("Hello");
SendMessage((IntPtr)0xffff, (int)_sendMessageID, IntPtr.Zero, buffer);
}
C++
UINT WM_MSG_AA = RegisterWindowMessage("WM_MSG_TEST");
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MSG_TEST)
{
BSTR* pcds = (BSTR*)lParam;
}
}
Please let me know how to fix this issue?
I also refer below link for fix issue but it could't help.
// WindowCreationCode
BOOL ProcessNextMessage()
{
MSG msg;
GetMessage(&(msg), _hWnd, 0, 0);
TranslateMessage(&(msg));
DispatchMessage(&(msg));
return TRUE;
}
int Create(){
CoInitialize(NULL);
_hInst = GetModuleHandle(NULL);
WNDCLASS wcex = { 0 };
wcex.lpfnWndProc = WndProc;
wcex.hInstance = _hInst;
wcex.lpszClassName = c_szClassName;
if (!GetClassInfo(wcex.hInstance, wcex.lpszClassName, &wcex))
{
if (!RegisterClass(&wcex))
{
return HRESULT_FROM_WIN32(GetLastError());
}
else
{
return S_OK;
}
}
else
{
return S_OK;
}
_hWnd = CreateWindowEx(
WS_EX_TOPMOST,
c_szClassName,
"ACTXAUTODRIVER",
WS_DLGFRAME ,
1, 1, 1, 1,
NULL,
NULL, _hInst, NULL);
ShowWindow(_hWnd, SW_HIDE);
while (ProcessNextMessage())
{
}
CoUninitialize();
}
You cannot send raw memory pointers across process boundaries like you are attempting to do. Even though you are converting your C# string data to a BSTR
allocated by the OS, the allocated memory is still only valid in the address space of the process that allocated it.
Your string data must be marshaled from one process's address space to the other process's address space. COM handles that for you automatically when it passes BSTR
values over process boundaries. But with window messages, only certain messages are marshaled automatically by the OS, and messages created with RegisterWindowMessage()
are not marshaled.
For what you are attempting, use WM_COPYDATA
instead, which is marshaled. However, you should NEVER broadcast (use (IntPtr)0xffff
aka HWND_BROADCAST
as the target window) a WM_COPYDATA
message! Bad things can happen if unsuspecting apps receive WM_COPYDATA
messages they are not prepared to handle correctly.
Have your C# code find the specific window it is actually interested in for your C++ app (from FindWindow/Ex()
, etc) and then send WM_COPYDATA
to only that window and no others. You can use RegisterWindowMessage()
to create a unique value for use in the COPYDATASTRUCT::dwData
field to differentiate your use of WM_COPYDATA
from other people's use of WM_COPYDATA
. Make your C++ code ignore any WM_COPYDATA
message whose dwData
value is not recognized.
Try something more like this:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
const int WM_COPYDATA = 0x004A;
_cdsDataID = RegisterWindowMessage("WM_MSG_TEST");
public void SendMessage() {
if (_cdsDataID == IntPtr.Zero) return;
IntPtr TargetWnd = ...; // FindWindow(), etc
if (TargetWnd == IntPtr.Zero) return;
string s = "Hello";
COPYDATASTRUCT copyData = new COPYDATASTRUCT();
copyData.lpData = Marshal.StringToHGlobalUni(s);
if (copyData.lpData != IntPtr.Zero)
{
copyData.dwData = _cdsDataID;
copyData.cbData = (s.Length + 1) * 2;
IntPtr copyDataBuff = Marshal.AllocHGlobal(Marshal.SizeOf(copyData));
if (copyDataBuff != IntPtr.Zero)
{
Marshal.StructureToPtr(copyData, copyDataBuff, false);
SendMessage(TargetWnd, WM_COPYDATA, IntPtr.Zero, copyDataBuff);
Marshal.FreeHGlobal(copyDataBuff);
}
Marshal.FreeHGlobal(copyData.lpData);
}
}
const UINT uiDataID = RegisterWindowMessage("WM_MSG_TEST");
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_COPYDATA)
{
LPCOPYDATASTRUCT pcds = (LPCOPYDATASTRUCT) lParam;
if ((pcds->dwData == WM_MSG_TEST) && (WM_MSG_TEST != 0))
{
WCHAR* pstr = (WCHAR*) pcds->lpData;
...
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
You can transfer string with your custom message with global atom - see GlobalAddAtom
API. You get integer value from GlobalAddAtom (atom number) and give the string as input parameter. Then SendMessage
transmits the atom as WPARAM
or LPARAM
. The other side decodes the atom to string with GlobalGetAtomName
. Finally call GlobalDeleteAtom
to free the resource.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.