I want to send keyboard input to a window in another process, without bringing that window to the foreground. I can use PostMessage to fake the WM_KEYDOWN and WM_KEYUP; all I need to know is which window handle should receive the keyboard input -- i.e., something like GetFocus, but for another, non-active application.
The GetGUIThreadInfo API looks promising -- it returns an hwndFocus for another app. But I've had no luck getting it to work from C# on my 64-bit OS. I've copied (and then further tweaked) the declarations from pinvoke.net, but all I ever get back is a generic error code (more details below).
I am setting cbSize before I call GetGUIThreadInfo, so I've avoided the most obvious potential problem.
I'm running 64-bit Vista, so I don't know whether the problem is that I'm not using the API correctly, or that it works differently in 64-bit -- I have yet to find a code sample that specifically says it works successfully in Win64.
Here's sample code. I'm using GetWindowThreadProcessId as recommended, so I don't think the problem has to do with mixing thread IDs with thread handles:
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
internal class GuiThreadInfo
{
public int cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public Rect rcCaret;
}
[DllImport("user32.dll")]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui);
IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr window)
{
var threadId = GetWindowThreadProcessId(window, IntPtr.Zero);
var info = new GuiThreadInfo();
info.cbSize = Marshal.SizeOf(info);
if (!GetGUIThreadInfo(threadId, ref info))
throw new Win32Exception();
return info.hwndFocus;
}
window is a valid window handle; GetWindowThreadProcessId returns a nonzero thread handle. But the call to GetGUIThreadInfo always returns false, and the exception message is always "The parameter is incorrect".
Just in case the problem was that GetGUIThreadInfo somehow doesn't have a 64-bit version, I tried changing all the 8-byte IntPtrs in the GuiThreadInfo declaration to 4-byte ints, but I still got the same error.
Does anyone have a working C# sample of GetGUIThreadInfo on Win64? Or, is there another way to find what the focused child-window handle would be in another app, without making that app active?
I haven't looked at it too closely but one thing jumps out. In your GetGUIThreadInfo call you pass the GUIThreadInfo structure by ref but you've defined it as a class so you are sending a reference by ref, in other words a pointer to a pointer. Either change your GUIThreadInfo to a struct or remove the ref on the parameter and add [In, Out] attributes.
Related
I am trying out WCT and I want to call GetThreadWaitChain, I had some previous questions on this topic, but I've got recently strange behavior. As I am calling GetThreadWaitChain fuction my Visual Studio hangs with prompt message:
vhost32.exe has stopped working
Output windows message:
The program '[9068] testWCT.vshost.exe' has exited with code -1073740940 (0xc0000374).
Every time I am getting to that function my visual studio hangs...
GetThreadWaitChain documentation:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679364(v=vs.85).aspx
This is my code:
internal void CollectWaitInformation(ClrThread thread)
{
var g_WctHandle = OpenThreadWaitChainSession(0, 0);
uint threadID = thread.OSThreadId;
WAITCHAIN_NODE_INFO[] NodeInfoArray = new WAITCHAIN_NODE_INFO[16];
int isCycle = 0;
int count = 16;
// Make a synchronous WCT call to retrieve the wait chain.
bool result = GetThreadWaitChain(g_WctHandle,
IntPtr.Zero,
WCTP_GETINFO_ALL_FLAGS,
threadID, ref count, NodeInfoArray, out isCycle);
if (!result)
{
//error
}
//Finaly ...
CloseSession(g_WctHandle);
}
[DllImport("Advapi32.dll")]
public static extern IntPtr OpenThreadWaitChainSession(OpenThreadChainFlags Flags, DWORD callback);
[DllImport("Advapi32.dll")]
public static extern bool GetThreadWaitChain(
IntPtr WctHandle,
IntPtr Context,
UInt32 Flags,
uint ThreadId,
ref int NodeCount,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
[In, Out]
WAITCHAIN_NODE_INFO[] NodeInfoArray,
out int IsCycle
);
[StructLayout(LayoutKind.Sequential)]
public struct WAITCHAIN_NODE_INFO
{
public WCT_OBJECT_TYPE ObjectType;
public WCT_OBJECT_STATUS ObjectStatus;
public struct LockObject
{
string ObjectName;
LARGE_INTEGER Timeout;
BOOL Alertable;
}
public struct ThreadObject
{
DWORD ProcessId;
DWORD ThreadId;
DWORD WaitTime;
DWORD ContextSwitches;
}
}
}
I've tried to run C++ code on the same process, which I took from MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681418(v=vs.85).aspx
And all I've got is: 0x57 error on all threads as a result. Which is ERROR_INVALID_PARAMETER accordingly to MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
Which is weird cause I didn't changed the C++ code..
Previous question on the same topic:
WCT GetThreadWaitChain call allways return false
I declared the WAITCHAIN_NODE_INFO struct in a wrong way (my union was wrong) this is the original structure:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681422(v=vs.85).aspx
As soon as I declared it right, the heap corruption stopped and everything worked...
I have a problem while I trying to call WinAPI functions from C# code. I have lots of imports, many of them works fine, but some of them not and leading to unexpected break main program, without any message, exception type, nothing, just fell down all its windows and exit.
I have two ways in code: via my developed library, where is more of winapi calls and I'm lazy to code specific structures, pointers, etc, and direct import from user32.dll, like this:
[DllImport(#"tradeInterop.dll")]
public static extern void ChooseInstrumentByMouse(UInt32 hwnd, int baseX, int baseY, int idx, int _isDown);
[DllImport(#"tradeInterop.dll")]
public static extern void PutNumber(int num);
[DllImport(#"tradeInterop.dll")]
public static extern void PutRefresh();
[DllImport(#"user32.dll")]
public static extern UInt32 FindWindow(string sClass, string sWindow);
[DllImport(#"user32.dll")]
public static extern int GetWindowRect(uint hwnd, out RECT lpRect);
[DllImport(#"user32.dll")]
public static extern int SetWindowPos(uint hwnd, uint nouse, int x, int y, int cx, int cy, uint flags);
[DllImport(#"user32.dll")]
public static extern int LockSetForegroundWindow(uint uLockCode);
[DllImport(#"user32.dll")]
public static extern int SetForegroundWindow(uint hwnd);
[DllImport(#"user32.dll")]
public static extern int ShowWindow(uint hwnd, int cmdShow);
[DllImport(#"tradeInterop.dll")]
public static extern ulong PixelColor(uint hwnd, int winX, int winY); //tried (signed) long and both ints as return type, same result (WINAPI says DWORD as unsigned long, what about 64-bit assembly where compiled both lib and program?
public struct RECT
{
public int Left;
public int Top; ...
As I said, many of this calls works perfectly, but have problem of last two of them: ShowWindow() and PixelColor() with following code:
extern "C" __declspec(dllexport) COLORREF __stdcall PixelColor(unsigned hwnd, int winX, int winY)
{
LPPOINT point;
point->x = winX;
point->y = winY;
ClientToScreen((HWND) hwnd, point);
HDC dc = GetDC(NULL);
COLORREF colorPx = GetPixel(dc, point->x, point->y);
ReleaseDC(NULL, dc);
return colorPx;
}
So, while I try to call directly imported ShowWindow() function, or library which calls api function(s), I got a program crash
Is there any way how to debug external libraries and its results?
What I¨m doing wrong?
Thanks a lot
You have several options for debugging issues.
Enable unmanaged code debugging in Visual Studio. Note: VS 2010 Express does not support mixed managed/unmanaged debugging. (Instructions)
Use WinDbg. This would be my personal favorite option for debugging mixed applications. It is an incredibly powerful tool. Admittedly the learning curve is a little steep, but it's well worth the effort.
Use an external/third party debugger like OllyDbg. (As suggested by MrDywar)
The P/Invoke problems:
As IInspectable pointed out HWND should be passed to unmanaged code using IntPtr.
Windows API data types are well defined. DWORD is always 32 bit. Also, LONG (all caps) is not the same as long (lower case).
The C++ Problems:
As mentioned by IInspectable, the LPPOINT is never initialized, so when you call ClientToScreen() you're accessing uninitialized stack garbage as a pointer, and assigning values. To Fix it you could:
Allocate the memory (your favorite scheme here, LocalAlloc, GlobalAlloc, malloc, calloc.
Make the declaration POINT point;, assign values using point.x & point.y, and use it in the function call as &point.
Make the first parameter's type HWND. The API types, even though they are ultimately typedefs, carry extra meaning with them.
I am trying to access Win32 APIs to install a driver on a device. I am using a bunch of functions from the setupapi.h, all of which work well. In this piece of code, I am using those to get the parameters (i.e. names of/pointers to device and driver) that are needed to call this install function (which is not part of the setupapi.h but of the newdev.h).
Following is my P/Invoke and the actual method call. I have used the debugger to investigate and I am pretty sure that the information I get from the SetupAPI is correct. (I.e., the parameters are fine, by which I mean that they do contain the desired information.)
IntPtr deviceInfoSet;
Win32SetupApi.SP_DEVINFO_DATA devInfoData;
GetDeviceHandleFromMatch(deviceInfo, out deviceInfoSet, out devInfoData);
Win32SetupApi.SP_DRVINFO_DATA drvInfoData;
GetDriverHandleFromMatch(driverInstance, deviceInfoSet, devInfoData, out drvInfoData);
try
{
bool needReboot = false;
Win32SetupApi.DiInstallDevice(
IntPtr.Zero,
deviceInfoSet,
devInfoData,
drvInfoData,
0,
ref needReboot);
}
catch (Exception ex)
{
throw;
}
[DllImport("newdev.dll", SetLastError = true)]
public static extern bool DiInstallDevice(
IntPtr hParent,
IntPtr lpInfoSet,
SP_DEVINFO_DATA DeviceInfoData,
SP_DRVINFO_DATA DriverInfoData,
UInt32 Flags,
[MarshalAs(UnmanagedType.Bool)] ref bool NeedReboot);
The exception I get is "Attempt to read/write protected memory", there is no information available via LastWin32Error.
Any thought on what might blow up here ist greatly appreciated!
Got it!
[DllImport("newdev.dll", SetLastError = true)]
public static extern bool DiInstallDevice(
IntPtr hParent,
IntPtr lpInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
ref SP_DRVINFO_DATA DriverInfoData,
UInt32 Flags,
ref bool NeedReboot);
The structs have to be passed by reference as descrided here. Not sure whether the Bool marshalling was wrong, but I removed that, too.
Can't believe this took hours to figure out again, gotta love P/Invoke. Hope this will help somebody else, too.
I'm trying to hook the creation of a windows in my C# app.
static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;
static void Main(string[] args)
{
// Dummy.exe is a form with a button that opens a MessageBox when clicking on it.
Process dummy = Process.Start(#"Dummy.exe");
try
{
hhookProc = new NativeMethods.HookProc(Hook);
IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, hwndMod, (uint)AppDomain.GetCurrentThreadId());
Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);
while (!dummy.HasExited)
dummy.WaitForExit(500);
}
finally
{
if(hhook != IntPtr.Zero)
NativeMethods.UnhookWindowsHookEx(hhook);
}
}
static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Hook()");
return NativeMethods.CallNextHookEx(hhook, nCode, wParam, lParam);
}
Problem is, when clicking on my button (in Dummy.exe), I never enter in my Hook, what am I doing wrong?
Thanks.
EDIT
Program.cs
using System;
using System.Diagnostics;
namespace Hooker
{
class Program
{
static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;
static void Main(string[] args)
{
Process dummy = Process.Start(#"Dummy.exe");
try
{
hhookProc = new NativeMethods.HookProc(Hook);
hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, IntPtr.Zero, 0);
Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);
while (!dummy.HasExited)
dummy.WaitForExit(500);
}
finally
{
if(hhook != IntPtr.Zero)
NativeMethods.UnhookWindowsHookEx(hhook);
}
}
static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Hook()");
return NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
}
}
NativeMethods.cs
namespace Hooker
{
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll")]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int pid);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
For dummy, do a new Form with :
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("CONTENT", "TITLE");
}
Like most SetWindowsHookEx hooks, WH_CBT hooks require that the hook callback lives in a separate Win32 DLL that will get loaded into the target process. This essentially requires that the hook is written in C/C++, C# won't work here.
(Low-level mouse and keyboard hooks are two exceptions to this rule. It might also be possible to use other hooks in C# but only if you are hooking one of your own threads, so dwThreadId is the id of a thread in the current process, not 0. I haven't confirmed this, though. And you need to make sure you're using the Win32 threadid, so using GetCurrentThreadId is probably the best bet here.)
If you want to watch for new windows appearing from another app, an alternative C#-friendly approach is to use the SetWinEventHook API instead, specify WINEVENT_OUTOFCONTEXT (which is the magic flag that gets the events delivered to your own process, removing the need for a DLL and making C# usable here) and hook for the EVENT_OBJECT_CREATE and EVENT_OBJECT_SHOW events. You can listen to either your own process/thread's events, or to all processes/threads on the current desktop.
This will get you all sorts of "create" and show notifications, including those for child HWNDs within dialog, and even items within listboxes and similar; so you'll need to filter to extract only those for top-level HWNDs: eg. check that idObject==OBJID_WINDOW and idChild==0; that hwnd is visible (IsVisible()) and is top-level.
Note that using WinEvents requires that the thread that calls SetWinEventHook is pumping messages - which is typically the case anyway if it's a thread with UI. If not, you may need to add a message loop (GetMessage/TranslateMessage) manually. And you'll also want to use GC.KeepAlive() with the callback here also to prevent it from getting collected until after you call UnhookWinEvents.
One issue with your code is that hhookProc can be garbage collected while your native code still needs it. Use GC.KeepAlive or put in in a static variable.
The hMod param should probably be null, since you specified a thread in your own process:
hMod [in]
Type: HINSTANCE
A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
But I think this only works for windows on the thread you specify.
In theory you can specify threads in other applications or even a global hook. The specified callback then gets called on the corresponding thread, even if that thread is in another process, in which case your dll gets injected into that process(that's the reason you need to specify the module handle in the first place).
But I believe that's not possible with .net code, because the mechanism for injecting into other processes and calling the hook method over there doesn't work with JIT compiled code.
This won't work in C#
Scope: Thread
If the application installs a hook procedure for a thread of a different application, the procedure must be in a DLL.
(Documentation of SetWindowsHookEx)
Scope: Global
To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports.
(Source)
I'm not familiar with the NativeMethod class you are referencing, but I'll make some assumptions and try to make some ground.
My guess this has to do with what handle you are hooking. The
dummy.MainWindowHandle
represents the front most window's handle, which is usually what you are looking for. However, in this case, you are opening a MessageBox.Show() which likely has a different handle than the one you have hooked to.
I'd assume that
IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
is probably going to return the same result as
dummy.Refresh();
IntPtr hwndMod = dummy.MainWindowHandle;
So I think it's safe to say that they might be giving you the handle you aren't looking for.
Perhaps try to make a test WinForm application. That way you can grab the proper handle. Just make sure to use
dummy.WaitForInputIdle();
dummy.Refresh();
before grabbing the handle to make sure you are grabbing the right handle at launch time.
I see it is a console application , so console application doesn't enter a windows messages loop.
simple solution is to include system.windows.forms
and simply type application.start() in your main
and things will be fine :)
This is not a particular function about EasyHook but about hooking in general. I want to hook a function with this signature:
public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)
This is clearly unmanaged code and I'm trying to hook it with my managed c# code using EasyHook.But I think it's not EasyHook causing problems here but my knowlegde on calling conventions etc...
This is how I define DllImport and delete:
public static int Send_Hooked(uint connection, uint size, IntPtr pDataBlock)
{
return Send(connection, size, pDataBlock);
}
[DllImport("Connection.dll", EntryPoint = "?Send#Connection_t##QAEHIIPBX#Z", CallingConvention = CallingConvention.ThisCall)]
static extern int Send(uint connection, uint size, IntPtr pDataBlock);
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate int DSend(uint connection, uint size, IntPtr pDataBlock);
But the hooked programm keeps on crashing as soon as I inject the hook - no big surprise. I supppose it's a problem of the calling convention and that my hooking-function somehow interferes with the stack of the hooked programm.
So I had a look at another project who do hook the same function but with detours in c++ (the hooking part):
Func = (int (__stdcall *)(unsigned int, unsigned short, void const ))::GetProcAddress(::GetModuleHandle("Connection.dll"), "?Send#Connection_t##QAEHIIPBX#Z");
PVOID DetourPtr;
PVOID TargetPtr;
DetourTransactionBegin();
DetourAttachEx(&Func, SendConnectionHook, &Trampoline, &TargetPtr, &DetourPtr );
DetourTransactionCommit();
And the called function:
__declspec(naked) void SendConnectionHook (CPU_CONTEXT saved_regs, void * ret_addr, WORD arg1, DWORD arg2, DWORD arg3)
{
DWORD edi_value;
DWORD old_last_error;
__asm
{
pushad; /* first "argument", which is also used to store registers */
push ecx; /* padding so that ebp+8 refers to the first "argument" */
/* set up standard prologue */
push ebp;
mov ebp, esp;
sub esp, __LOCAL_SIZE;
}
edi_value = saved_regs.edi;
old_last_error = GetLastError();
OnConnectionSend((void *) saved_regs.ecx, (unsigned char *) arg3, arg2);
SetLastError(old_last_error);
__asm
{
/* standard epilogue */
mov esp, ebp;
pop ebp;
pop ecx; /* clear padding */
popad; /* clear first "argument" */
jmp [Trampoline];
}
}
(Target assembly and c++ example are both compiled with visual c++). I guess I'll have to save some registers and repair the stack before I call the original function? Or any other idea what I'm doing wrong here?
You are trying to hook a C++ class instance method. It has a hidden argument, this. This argument is commonly passed through the ECX register with the __this calling convention. That's what you see that Detours version doing.
Getting this right is quite untrivial, the CPU register values must be preserved early, ECX in particular. That requires a stub that uses machine code, no machine code in a managed stub of course. I doubt that EasyHook has any support for it, it certainly isn't promised in the feature list.
Looks like i figured it out. #Hans Passant was right: I have to save the hidden this argument. EasyHook does actually take care for everything but this (like cleaning up the .net stuff). As this is the first argument i simply did add it to my function (connection is my this reference):
public static int Send_Hooked(IntPtr connection, uint unknown, uint size, IntPtr pDataBlock)
{
return Send(connection, unknown, size, pDataBlock);
}
[DllImport("Connection.dll", EntryPoint = "?Send#Connection_t##QAEHIIPBX#Z", CallingConvention = CallingConvention.ThisCall)]
static extern int Send(IntPtr connection, uint unknown, uint size, IntPtr pDataBlock);
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate int DSend(IntPtr connection, uint unknown, uint size, IntPtr pDataBlock);
Can't really explain why this does work (also I think I did understand most of it :) I really should go back and learn some more assembler/compiling theory.