如何解决如何使用 SendMessage (WM_COPYDATA) 将消息从 C# 发送到 C++ (MESSAGE ONLY WINDOW)?
编辑:我已修复这里是我为新朋友设置示例的完整代码,我的原始问题也在下面。
在代码之前,让我向您介绍一些文档(按顺序):
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows
https://docs.microsoft.com/en-us/windows/win32/dataxchg/using-data-copy
http://pinvoke.net/default.aspx/Structures/COPYDATASTRUCT.html
C# 程序
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Program
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern long SendMessage(IntPtr hWnd,uint Msg,IntPtr wParam,IntPtr lParam);
[DllImport("user32.dll",CharSet = CharSet.Unicode)]
static extern IntPtr FindWindow(string classname,string windowname);
[StructLayout(LayoutKind.Sequential)]
struct copYDATASTRUCT
{
public uint dwData;
public int cbData;
public IntPtr lpData;
}
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructuretoPtr(param,retval,false);
return (retval);
}
public static void IntPtrFree(IntPtr preAllocated)
{
if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home"));
Marshal.FreeHGlobal(preAllocated); preAllocated = IntPtr.Zero;
}
const int WM_copYDATA = 0x004A;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
Thread.Sleep(3000);
string message = "This is a test";
IntPtr hWnd = FindWindow("MyClass","MyTitle");
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("Couldn't find the window");
}
else
{
copYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(message);
IntPtr cdsBuffer = IntPtrAlloc(cds);
SendMessage(hWnd,WM_copYDATA,IntPtr.Zero,cdsBuffer);
IntPtrFree(cds.lpData);
IntPtrFree(cdsBuffer);
}
}
}
}
C++ 程序
#include <iostream>
#include <Windows.h>
using namespace std;
LRESULT CALLBACK WindProc(HWND hWnd,UINT Msg,WParaM wParam,LParaM lParam)
{
if (Msg == WM_copYDATA)
{
PcopYDATASTRUCT data = (PcopYDATASTRUCT)lParam;
MessageBoxA(hWnd,(LPSTR)data->lpData,"info",0); // The character set depends on the characters you send
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,Msg,wParam,lParam);
}
int main(){
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("MyClass");
RegisterClassEx(&wcx);
HWND hWnd = CreateWindowEx(0,TEXT("MyClass"),TEXT("MyTitle"),HWND_MESSAGE,NULL,GetModuleHandle(NULL),NULL);
MSG message;
for(int i = 0; i < 1000; i++)
{
std::cout << "working" << std::endl;
Sleep(2 * 1000);
if(PeekMessage(&message,PM_norEMOVE))
{
break;
}
}
int x;
cout<<"got it!";
cin>>x;
return 0;
}
原始问题:
我有一个 C# 应用程序,我想与我在 C# 应用程序中创建的 C++ 进程通信。
我手上有一个代码,我想它应该可以工作,但它没有。该消息根本不是由 C++ 应用程序获取的。
我的 C# 程序:
namespace ScannerGUI
{
public partial class Form1 : Form
{
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd,IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
struct copYDATASTRUCT
{
public uint dwData;
public int cbData;
public IntPtr lpData;
}
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructuretoPtr(param,EventArgs e)
{
//creating child process
var prcsInfo = new processstartinfo
{
UseShellExecute=true,CreateNowindow = false,FileName = "main.exe",};
Process myProcess = Process.Start(prcsInfo);
ChildProcesstracker.AddProcess(myProcess);
Thread.Sleep(3000);
string message = "This is a test";
IntPtr hWnd = myProcess.Handle;
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("Couldn't find the process");
}
else
{
copYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(message);
IntPtr cdsBuffer = IntPtrAlloc(cds);
PostMessage(hWnd,cdsBuffer);
IntPtrFree(cds.lpData);
IntPtrFree(cdsBuffer);
}
}
}
}
我的 C++ 应用程序 (main.exe):
int main(){
MSG message;
for(int i = 0; i < 1000; i++)
{
std::cout << "working" << std::endl;
Sleep(2 * 1000);
if(PeekMessage(&message,PM_norEMOVE))
{
break;
}
}
int x;
cout<<"got it!";
cin>>x;
return 0;
}
当我启动 c# 程序时。没有错误,没有什么。 与 c++ 相同,没有错误,没有任何东西,但永远不会破坏 for 循环 :(
感谢大家的时间。
解决方法
首先,Process.Handle
是进程的句柄而不是窗口。
其次,由于你的main.exe是一个控制台应用程序,它只有一个控制台窗口,你只能通过使用MainWindowHandle
来获取控制台窗口的句柄。但是,控制台不属于main.exe
,因此您不能使用PeekMessage
来处理发送到控制台窗口的消息。 控制台窗口由控制台子系统 csrss.exe 拥有(参见 https://stackoverflow.com/a/28248281/10611792)。您应该为 C++ 应用程序创建自己的窗口,或创建一个 Message-Only 窗口。然后,您可以在 C# 中使用 FindWindow
获取窗口句柄:
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern long SendMessage(IntPtr hWnd,uint Msg,IntPtr wParam,IntPtr lParam);
[DllImport("user32.dll",CharSet = CharSet.Unicode)]
static extern IntPtr FindWindow(string classname,string windowname);
...
private void Form1_Load(object sender,EventArgs e)
{
...
Thread.Sleep(3000);
string message = "This is a test";
IntPtr hWnd = FindWindow("MyClass","MyTitle");
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("couldn't find the process");
}
else
{
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(message);
IntPtr cdsBuffer = IntPtrAlloc(cds);
SendMessage(hWnd,WM_COPYDATA,IntPtr.Zero,cdsBuffer);
IntPtrFree(cds.lpData);
IntPtrFree(cdsBuffer);
}
}
}
C++:
LRESULT CALLBACK WindProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
if (Msg == WM_COPYDATA)
{
PCOPYDATASTRUCT data = (PCOPYDATASTRUCT)lParam;
MessageBoxA(hWnd,(LPSTR)data->lpData,"info",0); // The character set depends on the characters you send
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,Msg,wParam,lParam);
}
int main() {
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("MyClass");
RegisterClassEx(&wcx);
HWND hWnd = CreateWindowEx(0,TEXT("MyClass"),TEXT("MyTitle"),HWND_MESSAGE,NULL,GetModuleHandle(NULL),NULL);
MSG msg;
for (int i = 0; i < 1000; i++)
{
std::cout << "working" << std::endl;
Sleep(2 * 1000);
if (PeekMessage(&msg,PM_NOREMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}
int x;
cout << "got it!";
cin >> x;
return 0;
}
另请注意,使用 SendMessage
而不是 PostMessage
。
此外,您还可以选择其他IPC方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。