有个进口设备由上位机控制,厂家不配合进行自动化改造,每次启动都需要人为手动操作
为了实现自动化采用外挂程序实现事件监控(hook)和运行控制(win32api)
win32api很简单可以向需要的窗口发送消息,控制点击等操作
设置hook
Process currentProcess = Process.GetCurrentProcess();
ProcessModule mainModule = currentProcess.MainModule;
IntPtr moduleHandle = Win32Api.GetModuleHandle(mainModule.ModuleName);
hHook = Win32Api.SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookDelegate, moduleHandle, 0);
SetWindowsHookEx原型
第三个参数为实例句柄,不是窗口句柄
HHOOK WINAPI SetWindowsHookEx(
__in int idHook, \\钩子类型
__in HOOKPROC lpfn, \\回调函数地址
__in HINSTANCE hMod, \\实例句柄
__in DWORD dwThreadId); \\线程ID
实例句柄和窗口句柄
通过SPY++可以看到实例句柄和窗口句柄不是同一个东西
GetModuleHandle为什么不是目标进程
那我们获取一下
IntPtr moduleHandle = IntPtr.Zero;
string tempName = "";
foreach (System.Diagnostics.Process thisProc in System.Diagnostics.Process.GetProcesses())
{
tempName = thisProc.ProcessName;
if (tempName.Contains("test2Windows"))
{
moduleHandle = GetModuleHandle(thisProc.MainModule.ModuleName);// thisProc.MainModule.BaseAddress
hookID = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, moduleHandle , 0);
if (hookID == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
Console.WriteLine(errorCode);
根据错误代码进行错误处理
}
break;
}
}
运行后发现GetModuleHandle结果为NULL(0),原来GetModuleHandle只有在当前进程的场景中,获取句柄才会有效
用其他方法获取实例句柄
GetWindowLong
IntPtr hInstance = GetWindowLong(hWnd, GWL_HINSTANCE);
运行后发现hInstance!=0,hookID=0,errorCode=126-找不到指定的模块。
把hwnd换成该进程自己的窗口句柄发现正常运行,回调函数也正常进入
SetWindowsHookEx局限
private const int WH_MIN = (-1);
private const int WH_MSGFILTER = (-1);
private const int WH_JOURNALRECORD = 0;
private const int WH_JOURNALPLAYBACK = 1;
private const int WH_KEYBOARD = 2;
private const int WH_GETMESSAGE = 3;
private const int WH_CALLWNDPROC = 4;
private const int WH_CBT = 5;
private const int WH_SYSMSGFILTER = 6;
private const int WH_MOUSE = 7;
//_WIN32_WINDOWS
private const int WH_HARDWARE = 8;
private const int WH_DEBUG = 9;
private const int WH_SHELL = 10;
private const int WH_FOREGROUNDIDLE = 11;
// (WINVER >= 0x0400)
private const int WH_CALLWNDPROCRET = 12;
//(_WIN32_WINNT >= 0x0400)
private const int WH_KEYBOARD_LL = 13;
private const int WH_MOUSE_LL = 14;
#if WINVER_0400
public const int WH_MAX = 14;
#elif WINVER_0500
public const int WH_MAX = 12;
#else
public const int WH_MAX = 11;
#endif
修改钩子类型为其他类型发现只有13、14键盘和鼠标两种类型可以成功,其他hookID和errorCode都等于0
总结:
1、GetModuleHandle只有在当前进程的场景中,获取句柄才会有效
2、GetWindowLong可以获取其他进程的实例句柄
3、SetWindowsHookEx只能设置钩子到本进程实例句柄中