实现思路

绘制搜索框覆盖在主程序上面

uselib.exe

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define RAYGUI_IMPLEMENTATION
#include "raylib.h"

#ifndef _DEBUG
#pragma comment(lib, "raylib.lib")
#pragma comment(lib, "winmm.lib")
// #pragma comment(lib, "opengl32.lib")
// #pragma comment(lib, "gdi32.lib")
// #pragma comment(lib, "shell32.lib")
// #pragma comment(lib, "user32.lib")
#endif // DEBIG

#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址


int main() {
// 纯净的 Raylib 程序,不包含任何插件加载代码
InitWindow(800, 600, "Target Process (To be Injected)");
SetTargetFPS(60);

while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(DARKBLUE); // 换个颜色,方便区分
DrawText("I am a standalone program.", 190, 200, 20, RAYWHITE);
DrawText("I have no searchbox code in my source.", 190, 230, 20, LIGHTGRAY);
EndDrawing();
}

CloseWindow();
return 0;
}

search.exe

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "raylib.h"
#include "WindowUtils.h"
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址
int main() {
SetConfigFlags(FLAG_WINDOW_UNDECORATED | FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_TOPMOST | FLAG_WINDOW_MOUSE_PASSTHROUGH);
SetTargetFPS(60); // 必须限制帧率,不要跑太快
InitWindow(800, 600, "SearchBox");

// GetWindowHandle() 在 Raylib 中返回的就是 void*
void* handle = GetWindowHandle();

while (!WindowShouldClose()) {
SimpleFollow(handle, "Target Process (To be Injected)", "GLFW30");

BeginDrawing();
ClearBackground(BLANK);

// 绘制一个静态的搜索框 UI
int sw = GetScreenWidth();
Rectangle box = { (float)sw / 2 - 200, 50, 400, 45 };

// 绘制背景和边框
DrawRectangleRec(box, Fade(BLACK, 0.8f));
DrawRectangleLinesEx(box, 2, SKYBLUE);

// 绘制静态文字
DrawText("Search Box Active", (int)box.x + 20, (int)box.y + 12, 20, RAYWHITE);

// 模拟一个放大镜小图标
DrawCircle((int)box.x + 360, (int)box.y + 22, 8, SKYBLUE);
DrawLine((int)box.x + 365, (int)box.y + 27, (int)box.x + 375, (int)box.y + 37, SKYBLUE);

EndDrawing();
}

CloseWindow();
return 0;
}

WindowUtils.h

1
2
3
4
5
#pragma once

void SimpleFollow(void* myHandle, const char* targetTitle, const char* targetClass);
void EstablishLink(void* myHandle, void* targetHandle);

WindowUtils.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "WindowUtils.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cmath>

void SimpleFollow(void* myHandle, const char* targetTitle, const char* targetClass) {
HWND myHwnd = (HWND)myHandle;
static HWND targetHwnd = NULL;

// 定期寻找目标窗口句柄
static int findCounter = 0;
if (findCounter++ % 60 == 0) {
targetHwnd = FindWindowA(targetClass, targetTitle);
}

if (targetHwnd && IsWindow(targetHwnd)) {
// --- 核心逻辑:判断是否应该显示 ---
HWND foregroundHwnd = GetForegroundWindow();

// 只有当当前焦点在 [目标程序] 或 [搜索框本身] 时,才显示
if (foregroundHwnd == targetHwnd || foregroundHwnd == myHwnd) {
// 如果窗口之前是隐藏的,显示它
if (!IsWindowVisible(myHwnd)) {
ShowWindow(myHwnd, SW_SHOWNOACTIVATE);
}

// 同步位置
RECT rect;
if (GetWindowRect(targetHwnd, &rect)) {
static RECT lastRect = { 0 };
if (rect.left != lastRect.left || rect.top != lastRect.top) {
SetWindowPos(myHwnd, HWND_TOPMOST, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE);
lastRect = rect;
}
}
}
else {
// 如果焦点在别的程序(如浏览器)上,隐藏自己
if (IsWindowVisible(myHwnd)) {
ShowWindow(myHwnd, SW_HIDE);
}
}
}
else {
// 找不到目标程序时也隐藏
if (IsWindowVisible(myHwnd)) {
ShowWindow(myHwnd, SW_HIDE);
}
}
}
void EstablishLink(void* myHandle, HWND targetHwnd) {
HWND myHwnd = (HWND)myHandle;

// 获取当前的 Owner
HWND currentOwner = (HWND)GetWindowLongPtr(myHwnd, GWLP_HWNDPARENT);

if (currentOwner != targetHwnd) {
// 关键:通过设置 GWLP_HWNDPARENT (在窗口样式中实际表现为 Owner)
// 建立“寄生”关系,使 Search 永远浮在 UseRay 之上
SetWindowLongPtr(myHwnd, GWLP_HWNDPARENT, (LONG_PTR)targetHwnd);

// 刷新窗口样式
SetWindowPos(myHwnd, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
}