gpt4 book ai didi

c# - 如何使用 SendMessage (WM_COPYDATA) 从 C# 向 C++ (MESSAGE ONLY WINDOW) 发送消息?

转载 作者:行者123 更新时间:2023-12-04 03:41:17 25 4
gpt4 key购买 nike

编辑:我已修复这里是我的工作完整代码,可以为新 friend 树立榜样,我的原始问题也在下面。

在代码之前让我向您介绍一些文档(按顺序):

https://learn.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues#message-routing

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage

https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows

https://learn.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"), 0, 0, 0, 0, 0, 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, NULL, 0, 0, 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, uint Msg, IntPtr wParam, 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, 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)
{
//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, WM_COPYDATA, IntPtr.Zero, 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, NULL, 0, 0, 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 window 。然后,您可以使用 FindWindow 在 C# 中获取窗口句柄:

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"), 0, 0, 0, 0, 0, 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, NULL, 0, 0, PM_NOREMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}

int x;
cout << "got it!";
cin >> x;
return 0;
}

另请注意,使用 SendMessage 而不是 PostMessage

此外,您还可以选择其他IPC方法。

关于c# - 如何使用 SendMessage (WM_COPYDATA) 从 C# 向 C++ (MESSAGE ONLY WINDOW) 发送消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65985671/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com