这是我能开发的最简单的例子:
你需要Visual Studio,添加2个项目到解决方案中:
第一个项目(HookDLL)是一个 dll 项目,第二个(正在运行的应用程序)是一个 win32 控制台项目
在 main.cpp(在项目运行应用程序中)添加:
__declspec(dllimport) void RunHook();
int _tmain(int argc, _TCHAR* argv[])
{
RunHook();
return 0;
}
在 dllmain button.cpp(在 HookDLL 项目中)添加以下代码:
#include <Windows.h>
#include <stdio.h>
HINSTANCE hinstDLL;
HHOOK hhook_wndproc;
HWND b = NULL;
HBRUSH blue_brush = NULL, yellow_brush, red_brush;
int button_status = 0;
LRESULT CALLBACK DefaultWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_CREATE:
if(!blue_brush)
{
blue_brush = CreateSolidBrush(RGB(0, 0, 255));
yellow_brush = CreateSolidBrush(RGB(255, 255, 0));
red_brush = CreateSolidBrush(RGB(255, 0, 0));
}
break;
case WM_PAINT:
{
HBRUSH b;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
switch(button_status)
{
case 0:
b = blue_brush;
break;
case 1:
b = yellow_brush;
break;
default:
b = red_brush;
}
FillRect(hdc, &ps.rcPaint, b);
EndPaint(hwnd, &ps);
}
return 0;
case WM_MOUSEMOVE:
if(button_status == 0)
{
SetTimer(hwnd, 1, 100, NULL);
button_status = 1;
InvalidateRect(hwnd, NULL, false);
}
return 0;
case WM_TIMER:
{
POINT pt;
GetCursorPos(&pt);
if(button_status == 1 && WindowFromPoint(pt) != hwnd)
{
KillTimer(hwnd, 1);
button_status = 0;
InvalidateRect(hwnd, NULL, false);
}
}
return 0;
case WM_MOUSELEAVE:
button_status = 0;
InvalidateRect(hwnd, NULL, false);
return 0;
case WM_LBUTTONDOWN:
button_status = 2;
InvalidateRect(hwnd, NULL, false);
return 0;
case WM_LBUTTONUP:
if(button_status == 2) MessageBox(GetParent(hwnd), "teamviewer like button clicked", "Message", MB_OK);
button_status = 1;
InvalidateRect(hwnd, NULL, false);
return 0;
}
return DefWindowProc(hwnd, Msg, wParam, lParam);
}
void InitButton(HWND parent, int xPos, int yPos)
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = DefaultWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstDLL;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "DEFAULT_CLASS";
RegisterClass(&wc);
b = CreateWindowEx(WS_EX_TOOLWINDOW, "DEFAULT_CLASS", NULL, WS_BORDER | WS_POPUP | WS_VISIBLE, xPos, yPos, 20, 20, parent, NULL, hinstDLL, NULL);
}
LRESULT WINAPI HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode >= 0 && lParam != 0)
{
CWPRETSTRUCT *msg = (CWPRETSTRUCT*)lParam;
if(!IsWindow(msg->hwnd) || (GetWindowLong(msg->hwnd, GWL_STYLE) & WS_CHILD) != 0) return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam);
switch(msg->message)
{
case WM_SHOWWINDOW:
if(!b && msg->wParam != 0)
{
b = (HWND)1;// see NOTES 5
RECT a;
GetWindowRect(msg->hwnd, &a);
InitButton(msg->hwnd, a.right - 150, a.top);
}
break;
case WM_SIZE:
if(GetParent(b) == msg->hwnd)
{
RECT a;
GetWindowRect(msg->hwnd, &a);
SetWindowPos(b, 0, a.right - 150, a.top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
break;
case WM_SIZING:
case WM_MOVING:
if(GetParent(b) == msg->hwnd)
{
RECT* lprc = (LPRECT) msg->lParam;
SetWindowPos(b, 0, lprc->right - 150, lprc->top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
}
}
return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam);
}
__declspec(dllexport) void RunHook()
{
hhook_wndproc = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProc, hinstDLL, 0);
char aux[10];
gets_s(aux);
UnhookWindowsHookEx(hhook_wndproc);
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hinstDLL = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
现在,让 dll 项目依赖于在 project->project dependencies 中运行的 app 项目:
注意事项:
1) 我不使用 NC 绘制代码,因为并非总是有效,如果 Windows 缓冲区非客户端区域,则删除自定义的 NC 绘制按钮
2) 在 64 位环境下,您需要为 32 位应用程序运行一个 32 位挂钩,为 64 位应用程序运行其他挂钩
3) 当你的钩子连接到另一个进程时,你不能调试你的钩子,我建议你在你的应用程序和线程中使用一个窗口来调试它,并在工作时在另一个进程中测试它的后期
4) 为了简单起见,我使用类似按钮的方法
5) 这一行
b = (HWND)1;
我用它来“解决”一个多线程问题,我建议你在这个案例中编写更好的代码(同步)
这是如何工作的:
- 运行应用程序
- 开始安装挂钩时
- 打开任何其他应用程序(相同的 32/64 位,请参阅注 2)
- 您必须在标题栏左侧看到一个蓝色按钮
- 点击它会看到一个消息框
- 对于完成挂钩:只需在控制台窗口按 ENTER
代码流程:
- 运行的应用程序只需在 dll 中调用 RunHook() 过程,然后 dll 完成工作
- dll 中的 RunHook() 启动挂钩 HookCallWndProc(全局)
- HookCallWndProc 捕获所需的消息并使用 InitButton() 过程创建窗口按钮
- DefaultWindowProc 处理按钮消息