Send Message in C#
You don't need to send messages.
Add an event to the one form and an event handler to the other. Then you can use a third project which references the other two to attach the event handler to the event. The two DLLs don't need to reference each other for this to work.
How to send message from C# to C++ (MESSAGE ONLY WINDOW) using SendMessage (WM_COPYDATA)?
First of all, Process.Handle
is the handle of the process instead of the window.
Secondly, since your main.exe is a console application and it only has a console window, you can only get the handle of the console window by using MainWindowHandle
. However, the console does not belong to the main.exe
, So you cannot use PeekMessage
to handle the message sent to the console window. Console windows are owned by the console subsystem, csrss.exe(see https://stackoverflow.com/a/28248281/10611792). You should create your own window for your C++ app, or create a Message-Only window. Then, you can use FindWindow
to get the window handle in 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;
}
Also Note that use SendMessage
instead of PostMessage
.
In addition, you can also choose other IPC methods.
SendMessage, Trying to send F4
The second parameter is the msg not the key, as: keyup (0x100) or keydown (0x101)
The third parameter is the key as 0x73 (F4)
SendMessage(whandle, 0x100, 0x73, IntPtr.Zero);
SendMessage(whandle, 0x101, 0x73, IntPtr.Zero);
SendMessage to Notepad++ in C#
You are running into a string encoding issue. Strings in .NET are UTF-16 little-endian strings. The string "Send"
in UTF-16 is actually the bytes S{0}e{0}n{0}d{0}{0}{0}
. Your declaration of SendMessage
is using the ANSI string method. There are a number of ways to solve this. Here's one: Explicitly use the UTF-16 form by changing SendMessage
to SendMessageW
.
[DllImport("User32.dll")]
public static extern int SendMessageW(IntPtr hWnd, int uMsg, int wParam, string lParam);
c# i'm unable to get SendMessage to send a message to a notepad window
Much credit to Remy. After some troubleshooting I ended up finding the code worked so it's a mystery why I was finding it didn't.
A good troubleshooting step is to try moving the window around with nircmd, so you know you have the handle.
To get the handle of the window, you can use nirsoft winlister, or winspector
You can use nircmd commands like nircmd win close handle 0x00230632
change that 0x00230632 to whatever you find the handle to be. Or better don't close it(otherwise you'll have to reopen it and the new window will have a new handle), so a command like nircmd win move handle 0x00B917AE 80 10 100 100
So you know the handle is right, regardless of any issue with the code.
Winspector also shows the child of the notepad window
Going back to the C# code, you can
skip the child and try writing into the parent, it should write into the title of the window
Try using SendMessage to specify a window directly. You write the handle in decimal rather than hex. e.g. if the handle is 3479948 then
e.g. SendMessage(new IntPtr(3479948), WM_SETTEXT, IntPtr.Zero, "abcdee");
You can also check that notepads[0].MainWindowHandle is picking up the correct value.. the handle shown in winspector.
You can look at the IntPtr child = FindWindowEx(...)
line, make sure the 'child' is picking up the child handle.
You can try writing to that one directly with SendMessage. e.g. SendMessage(new IntPtr(1234567), WM_SETTEXT, IntPtr.Zero, "abcdee");
// (if winspector shows the child window to be that handle).
Related Topics
Date Difference in Years Using C#
Serilog Mssql Sink Doesn't Write Logs to Database
Httpcontext.Current.Session Is Null in Ashx File
Sqlexception:String or Binary Data Would Be Truncated
How to Connect to Any of the Specified MySQL Hosts. C# MySQL
Simulating Keyboard with Sendinput API in Directinput Applications
How to Get the Local Network Ip Address of a Computer Programmatically
How to Display the String HTML Contents into Webbrowser Control
Get Affected Rows on Executenonquery
C# 8 Switch Expression with Multiple Cases with Same Result
C# Linq Where Date Between 2 Dates
Variable Declarations Following If Statements
How to Log a User Out When They Close Their Browser or Tab in ASP.NET MVC