I am working with an application in C# that need to send a message to a C++ application.
I imported
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(
int hWnd, // handle to destination window
uint Msg, // message
IntPtr wParam, // first message parameter
IntPtr lParam // second message parameter
);
but now, my problem is that I need to passe string to wParam and lParam. I tried unsafe code, but it seems string just doesnt work like the rest of variables. How can I achieve that? Thanks.
The declaration is wrong, the wParam and lParam arguments are IntPtr, not long.
There is a complication because you are trying to send strings. What matters if the target window is Unicode enabled or not. There are two versions of SendMessage, SendMessageA() and SendMessageW(). The former needs to be used if the program is dated and uses 8-bit character strings rather than UTF-16 encoded strings.
You can find out by using Spy++. Use the finder tool to select the window of the application. In the General property tab, you'll see "Window proc". It will say (Unicode) if the window is Unicode enabled. If you don't see it then the strings have to be translated to 8-bit characters.
To generate the string pointers you need to pass, you can use Marshal.StringToHGlobalAnsi or StringToHGlobalUni (respectively 8-bit and Unicode). You can however play a trick to let the P/Invoke marshaller translate the string for you. Saves you the hassle of having to free the strings after the call. For the Ansi version, you can declare the API function like this:
[DllImport("user32.dll", CharSet = CharSet.Ansi, EntryPoint = "SendMessageA", ExactSpelling = true)]
private static extern IntPtr SendMessageStrings(IntPtr hWnd, int msg, string wParam, string lParam);
And the Unicode version like this:
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW", ExactSpelling = true)]
private static extern IntPtr SendMessageStrings(IntPtr hWnd, int msg, string wParam, string lParam);
One final note: this will not work as-is if the window belongs to another application, you'll crash it. The pointer values you pass are only valid in your own process, not in the C++ process. To work around that, you have to allocate memory in the target process so that the pointer is valid. That requires OpenProcess to get a handle to the process, VirtualAllocEx() to allocate memory in the target process, big enough to store the string, WriteProcessMemory to write the string. Now you can call SendMessage(), use a version that is declared with IntPtr for the wParam and lParam arguments, pass the value you got from VirtualAllocEx. Next use VirtualFreeEx() to release the memory and CloseHandle to clean up. Or keep the memory around for the next time if you do this often.
Quite a lot of P/Invoke to get wrong there. Not to mention security issues, WriteProcessMemory requires admin privileges, UAC elevation is required.
Passing the address of the string would involve unsafe code,
since Win32 API calls expect addresses (in a C/C++ native envrion). What windows message are you sending that requires a string in wParam or lParam?
We ended up using "WmCpyDta_d.dll" to deal with all that.
Related
I'm using the Windows API function ReadFile() to read system metafiles. But what I'm confused about is how to actually process the data that is returned from that function. I'm assuming that it's stored in the lpBuffer parameter, and that I somehow need to decode the contents of that buffer in order to interpret the actual data.
I'm running Windows 10 and am using C# to make interop calls.
Here's my wrapper:
[DllImport("kernel32", CharSet = CharSet.Auto)]
public static extern bool ReadFile(SafeFileHandle hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, ref NativeOverlapped lpOverlapped);
And here's my call:
NativeMethods.ReadFile(_volumeHandle, (IntPtr)buffer, (uint)len, out read, ref overlapped)
//do something with the buffer???
The data contained in the buffer after the call is a pointer to an int - which is what I expected - but where is the actual file data?
You need to supply the buffer. See https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-readfile
I am currently trying to write a console application in C# with two screen buffers, which should be swapped back and forth (much like VSync on a modern GPU). Since the System.Console class does not provide a way to switch buffers, I had to P/Invoke several methods from kernel32.dll.
This is my current code, grossly simplified:
static void Main(string[] args)
{
IntPtr oldBuffer = GetStdHandle(-11); //Gets the handle for the default console buffer
IntPtr newBuffer = CreateConsoleScreenBuffer(0, 0x00000001, IntPtr.Zero, 1, 0); //Creates a new console buffer
/* Write data to newBuffer */
SetConsoleActiveScreenBuffer(newBuffer);
}
The following things occured:
The screen remains empty, even though it should be displaying newBuffer
When written to oldBuffer instead of newBuffer, the data appears immediately. Thus, my way of writing into the buffer should be correct.
Upon calling SetConsoleActiveScreenBuffer(newBuffer), the error code is now 6, which means invalid handle. This is strange, as the handle is not -1, which the documentation discribes as invalid.
I should note that I very rarely worked with the Win32 API directly and have very little understanding of common Win32-related problems. I would appreciate any sort of help.
As IInspectable points out in the comments, you're setting dwDesiredAccess to zero. That gives you a handle with no access permissions. There are some edge cases where such a handle is useful, but this isn't one of them.
The only slight oddity is that you're getting "invalid handle" rather than "access denied". I'm guessing you're running Windows 7, so the handle is a user-mode object (a "pseudohandle") rather than a kernel handle.
At any rate, you need to set dwDesiredAccess to GENERIC_READ | GENERIC_WRITE as shown in the sample code.
Also, as Hans pointed out in the comments, the declaration on pinvoke.net was incorrect, specifying the last argument as a four-byte integer rather than a pointer-sized integer. I believe the correct declaration is
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateConsoleScreenBuffer(
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwFlags,
IntPtr lpScreenBufferData
);
I am creating a c# app to send a message in a notepad using the SendMessage() function. I have successfuly passed the strings to notepad. The strings are very important and i was wondering if a keylogger program can see this message?
If yes, do you have any other ideas on how i can send the strings securely?
Below is a sample code i used.
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
Process[] notepads = Process.GetProcessesByName("notepad");
if (notepads.Length == 0) return;
if (notepads[0] != null)
{
IntPtr child = FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, TextBox1.Text);
}
What you're doing is not secure; there are multiple ways a SendMessage call can be spied on by anyone who wants to do so.
SetWindowsHookEx with WH_CALLWNDPROC or WH_CALLWNDPROCRET will let an attacker monitor all messages being sent to a given thread, or they can monitor all messages across the system and just filter out the ones headed to your SendMessage target.
Alternately, an attacker can inject themselves into your recipient process, using WriteProcessMemory to write a DLL name into the recipient process, then CreateRemoteThread and LoadLibrary to load the DLL into the target process. After that, monitoring the process's messages should be fairly trivial.
To avoid using a DLL, an attacker could also use WriteProcessMemory to write code directly into the target process's memory space, then CreateRemoteThread to call it.
All three of these monitoring methods are documented in this CodeProject article. It's admittedly a little old, but the methods should still be relevant, particularly the SetWindowsHookEx one.
An attacker could also hook various Windows APIs directly; it's difficult and somewhat risky, but depending on the sensitivity of your data an attacker might find it a worthwhile approach.
Trying to protect your data will be very difficult, honestly. You can look at how KeePass keeps passwords secure; it's got a setting (at least in the 1.x branch; KeePass 2.x is an entirely different app) to "allow pasting only once and protect against clipboard spies", which might be of some benefit to you. Taking another cue from KeePass, you can also look into Windows' Data Protection API.
As a side note, you may want to replace
SendMessage(child, 0x000C, 0, TextBox1.Text);
with
SendMessage(child, WM_SETTEXT, 0, TextBox1.Text);
for readability. Not many people will recognize 0x000C by itself, although it's possible to guess what the message is based on context.
I need to automate a third party program, and the only course of action is to simulate a click on some buttons.
I do this by finding the HWND handle of the button with EnumChildWindows. When I've found the "window" (the button), I try to send BM_CLICK to it with SendMessageW. This works, my tests show that the button indeed think it was clicked.
The problem arise in my error handling. There is no feedback given by the BM_CLICK message, so I don't really know if it has been clicked. I thought I should be diligent and check for any error codes though with Marshal.GetLastWin32Error.
This returns ERROR_PROC_NOT_FOUND, which is not really what I would expect from a successful message handling.
I import SendMessageW as follows:
[DllImport("User32.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Winapi,
SetLastError = true)]
public static extern IntPtr SendMessageW(
HandleRef hWnd,
UInt32 Msg,
UIntPtr wParam,
IntPtr lParam);
The code doing the call is:
User32.SendMessageW(
buttonHandle,
(uint)ButtonControlMessages.BM_CLICK, // value of BM_CLICK = 0x00F5.
UIntPtr.Zero,
IntPtr.Zero);
int error = Marshal.GetLastWin32Error();
if (error != ErrorCodes.ERROR_SUCCESS) // love the name of this error code.
throw new Win32Exception(error);
My tests are just using a simple Windows Forms with a button control attached. Thus, I can procure the handle through button.Handle. It gets clicked; could it be that this error is completely unrelated?
It sure would be nice to get rid of it though, I'd like some way to be sure that the call to SendMessageW at least didn't fail.
I'm on Windows 7 x86-32 with .NET 4.
The calling convention should be Stdcall, but since that is the default you can just drop it.
I think your SendMessage P/Invoke looks a bit odd but that's probably not the cause of the issue. In any case I would do it like this:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
I think what's happening here is that SendMessage() is working but isn't assigning the last error. The only thing that the documentation for SendMessage() mentions about errors is:
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
The return value for SendMessage() is dependent on the message sent. In the case of BM_CLICK there is apparently no message sent. In other words you simply do not get any feedback.
According to my research, when I run C# executable which opens WinForm, within .NET, they don't offer the function to access those WinForm object from separate c# process (separate file I mean) but win32 API does.
Then I came across 3 functions from API.
FindWindow();
GetWindowLong();
CallWindowProc()
I need to call it from top down to the bottom but then I got stuck by CallWIndowProc() because
I can't figure what I should pass for last 3 arguments.
private static extern UIntPtr CallWindowProc(IntPtr a, IntPtr b, uint c, IntPtr d, IntPtr e);
c, d and e
According to the doc, it should be some sort of "message" which is int. But where can I get such value???
http://msdn.microsoft.com/en-us/library/ms633571(v=vs.85).aspx
Code:
[DllImportAttribute("User32.dll")]
private static extern IntPtr FindWindow(String ClassName, String WindowName);
[DllImportAttribute("User32.dll")]
private static extern long GetWindowLong(IntPtr a, int b);
[DllImportAttribute("User32.dll")]
private static extern UIntPtr CallWindowProc(IntPtr a, IntPtr b, uint c, IntPtr d, IntPtr e);
[STAThread]
static void Main(string[] args)
{
IntPtr lResult;
uint lMsg = 0;
IntPtr HWND = FindWindow("WindowsFormsApplication1.Form1", "Form1");
int GWL_WNDPROC = -4;
long WNDPROC = GetWindowLong(HWND, GWL_WNDPROC);
lResult = CallWindowProc(WNDPROC, HWND, lMsg, 0, 0);
}
Clarification
OK.. I should have made it clear.. my goal is to run following chunk of code against the WebForm being executed. (I'ts WatiN)
var t = new Thread(() =>
{
Settings.AutoStartDialogWatcher = false;
var ie = new IE(form1.webBrowser1.ActiveXInstance);
ie.GoTo("http://www.google.com");
ie.TextField(Find.ByClass("lst")).TypeText("this is awesome!!");
ie.Button(Find.ByName("btnG")).Click();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
What message you are trying to send to callWinProc?
Arguments are
nProc is a value returned previously by SubClassWindow() (Source Window).
hWnd is the handle to the window that was subclassed (target window).
nMsg is the message (one of the WM_* values defined in WINDOWS.CH, basically kind of event or message like click is one message). For complete system messages see http://msdn.microsoft.com/en-us/library/ms644927(v=vs.85).aspx#system_defined
wParam depends on nMsg. For click, it takes left or right click
lParam depends on nMsg. for click it takes the location as lparam
you can see wparam and lparam defination for each message.
It looks like you're trying to call the window proc of a window from a different thread/process. I'm assuming this because you're using FindWindow, and I can't see where you created the window. If that is what you are doing, CallWindowProc won't work because you cannot call a window proc from a thread other than the one that created the window. What you need is SendMessage, which accepts the same last four parameters (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - to interpret them you need to know what message you're sending.
I recommand to use the parameter names from the native methode just for clearness. You can get those pinvoke signatures from pinvoke.net so you don't have to do it on your own all the time. These messages are definded in header files and documented in the msdn. Its quiete hard to use the right message in the correct manner if you're new to win32 and/or C#.
If you want to intercept the windows messages of your form you need a windows message hook, but this doesn't work in .Net. You can also read this article which cover this topic.
Maybe you should try to find a complete different solution for your problem. Other IPC methodes etc.
EDIT: The CLR type of your form (WindowsFormsApplication1.Form1) is not the class name you have to put in FindWindow, FindWindow is an unmanaged api and isn't aware of the CLR typesystem. Try out Spy++ to investigate some windows on your PC.