Repository navigation
Expand file tree
/
Copy pathWindowControlEx.cpp
More file actions
331 lines (275 loc) · 11.2 KB
/
Copy pathWindowControlEx.cpp
File metadata and controls
331 lines (275 loc) · 11.2 KB
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#include "WindowControlEx.h"
#include "framework_base.hpp"
#include "config.h"
#include "RMenuProcessor.hpp"
#include "ScanThread.hpp"
HWND hTreeView, _hStatusBar;
HWND main_hwnd;
HMENU hPopupMenu, hWindowMenu;
HFONT hPublicFont;
//HANDLE g_quitevent;
bool gb_quitEvent = false;
HINSTANCE g_hInstance;
bool Scanning;
std::thread *scanthrd;
int windowcount, filteredwindowcount;
HTREEITEM tree_conduct;
static HTREEITEM SelectTreeItemUnderCursor(HWND treeView, LPARAM lParam)
{
if(!IsWindow(treeView)) return NULL;
if(lParam != -1) {
TVHITTESTINFO hitInfo { 0 };
hitInfo.pt.x = (SHORT)LOWORD(lParam);
hitInfo.pt.y = (SHORT)HIWORD(lParam);
ScreenToClient(treeView, &hitInfo.pt);
HTREEITEM hitItem = TreeView_HitTest(treeView, &hitInfo);
if(hitItem) {
TreeView_SelectItem(treeView, hitItem);
SetFocus(treeView);
TreeView_EnsureVisible(treeView, hitItem);
return hitItem;
}
}
HTREEITEM selected = TreeView_GetSelection(treeView);
if(selected) return selected;
HTREEITEM root = TreeView_GetRoot(treeView);
if(root) {
TreeView_SelectItem(treeView, root);
SetFocus(treeView);
TreeView_EnsureVisible(treeView, root);
}
return root;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpWCmdLine, INT nCmdShow)
{
g_hInstance = hInstance;
// 声明 Per-Monitor V2 高分屏支持(Windows 10 1607+)。
// 必须在创建任何窗口之前调用。
if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
// 旧系统(不支持 Per-Monitor V2)回退到系统级 DPI 感知
SetProcessDPIAware();
}
InitCommonControls();
// InitPropertyWindow(); // No longer valid
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = TEXT("WindowContolExClass");
wcex.hbrBackground = HBRUSH(COLOR_WINDOW);
RegisterClassEx(&wcex);
hWindowMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDW_MENU));
main_hwnd = CreateWindowEx(0,
TEXT("WindowContolExClass"), TEXT("WindowControl Ex"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 550, 550,
NULL, hWindowMenu, hInstance, NULL
);
ShowWindow(main_hwnd, nCmdShow);
// Temporary roll back to old implementation of font creation.
hPublicFont = CreateFont(19, 0, 0, 0,
FW_MEDIUM, FALSE, FALSE, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH,
"Segoe UI"
);
// Inject font into Framework
SendMessage(main_hwnd, WM_SETFONT, WPARAM(hPublicFont), TRUE);
Config.load(); // 加载配置
RuleSet.load(); // 加载黑名单 (全量)
BeginScan();
SendMessage(main_hwnd, WM_INITIALIZE, 0, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) // 主消息循环
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
RuleSet.save(); // 保存黑名单
Config.save(); // 保存配置
gb_quitEvent = true;
CloseAllSubWindows();
CloseAllThreads(); // 等待所有子线程退出
if(scanthrd->joinable()) scanthrd->join();
return (int)msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
using Framework::ChildWindow;
// 主窗口只有 TreeView 和状态栏需要单独处理,不需要通用的 ChildWindowStorage
static thread_local ChildWindow statusBarCtrl; // 用于在 DPI 变化时刷新状态栏分栏
static constexpr int TREEVIEW_ITEM_HEIGHT = 20;
switch (uMsg)
{
case WM_CREATE:
{
FRAMEWORK_INIT_WM_CREATE
auto treeView = ChildWindow(WC_TREEVIEW, "", 0, TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_SHOWSELALWAYS,
{ 20, 20, 200, 300 }, hwnd, NULL);
hTreeView = treeView.hwnd();
int SCALED_ITEM_HEIGHT = MulDiv(TREEVIEW_ITEM_HEIGHT, Framework::getDpi(hwnd), 96);
TreeView_SetItemHeight(hTreeView, SCALED_ITEM_HEIGHT);
auto statusBar = ChildWindow::createStatusBar(hwnd, 0, { 50, 170, 130 }, true);
_hStatusBar = statusBar.hwnd();
statusBarCtrl = statusBar;
// 状态栏分栏按当前 DPI 缩放(noResize,只刷新分栏)
statusBarCtrl.applyScale(Framework::getDpi(hwnd));
//1: 状态 / 2: 窗口尺寸 / 3: 窗口数
statusBar.statusSetPartText(0, "初始化");
statusBar.statusSetPartText(2, "初始化");
// Load the right click menu
HMENU hRightMenu = LoadMenu(((LPCREATESTRUCT)lParam)->hInstance, /*szMenuName*/ MAKEINTRESOURCE(IDM_MAINMENU));
hPopupMenu = GetSubMenu(hRightMenu, 0);
// 如果当前未提权,则在菜单栏右侧添加一个菜单项作为提权入口
if(!IsProcessElevated()) {
AppendMenu(hWindowMenu, MF_STRING | MF_RIGHTJUSTIFY, IDW_ELEVATE, TEXT("提权(&E)"));
DrawMenuBar(hwnd);
}
break;
}
case WM_ADDROOT: {
MsgDataPackA* data = reinterpret_cast<MsgDataPackA*>(lParam);
tree_conduct = AddRootItem(hTreeView, data->Name.c_str(), (LPARAM)data->handle);
if(TreeView_GetSelection(hTreeView) == NULL && tree_conduct != NULL) {
TreeView_SelectItem(hTreeView, tree_conduct);
TreeView_EnsureVisible(hTreeView, tree_conduct);
}
SetEvent(reinterpret_cast<HANDLE>(data->event));
break;
}
case WM_ADDCHILD: {
MsgDataPackB* data = reinterpret_cast<MsgDataPackB*>(lParam);
tree_conduct = AddChildItem(hTreeView, data->parent, data->Name.c_str(), (LPARAM)data->handle);
SetEvent(reinterpret_cast<HANDLE>(data->event));
break;
}
case WM_RESET: {
TreeView_DeleteAllItems(hTreeView);
SetEvent(reinterpret_cast<HANDLE>(lParam));
break;
}
case WM_CONTEXTMENU: {
if((HWND)wParam == hTreeView) {
SelectTreeItemUnderCursor(hTreeView, lParam);
}
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hwnd, NULL);
break;
}
case WM_INITIALIZE:
{
CheckMenuItem(hWindowMenu, IDW_FILTER_ENABLED, Config.EnableBlockList?(MF_CHECKED):(MF_UNCHECKED));
CheckMenuItem(hWindowMenu, IDW_AUTOUPDATE, Config.PropertyWindow.AutoUpdateEnabled?(MF_CHECKED):(MF_UNCHECKED));
if(!Config.PropertyWindow.AutoUpdateEnabled)
for(u_int i = IDW_AUINTERVAL50MS; i <= IDW_AUINTERVALCUSTOM; i++)
EnableMenuItem(hWindowMenu, i, MF_BYCOMMAND | MF_DISABLED);
UINT updateInterval_Handle;
switch(Config.PropertyWindow.AutoUpdateInterval) {
case 50 : updateInterval_Handle = IDW_AUINTERVAL50MS; break;
case 100 : updateInterval_Handle = IDW_AUINTERVAL100MS; break;
case 500 : updateInterval_Handle = IDW_AUINTERVAL500MS; break;
case 1000: updateInterval_Handle = IDW_AUINTERVAL1000MS; break;
case 5000: updateInterval_Handle = IDW_AUINTERVAL5000MS; break;
default: {
updateInterval_Handle = IDW_AUINTERVALCUSTOM;
std::string p = std::to_string(Config.PropertyWindow.AutoUpdateInterval) + "ms";
SetMenuText(hWindowMenu, IDW_AUINTERVALCUSTOM, p);
//EnableMenuItem(hWindowMenu, IDW_AUINTERVALCUSTOM, MF_BYCOMMAND | MF_ENABLED);
DrawMenuBar(hwnd);
break;
}
}
CheckMenuItem(hWindowMenu, updateInterval_Handle, MF_CHECKED);
HMENU hSubMenu = GetSubMenu(hWindowMenu, 4); // 加载子菜单项
EnableMenuItem(hSubMenu, 3, MF_BYPOSITION | (Config.PropertyWindow.AutoUpdateEnabled?(MF_ENABLED):(MF_DISABLED)) ); // 禁用设置
break;
}
case WM_COMMAND:
return RMenuProcessor(hwnd, uMsg, wParam, lParam);
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostMessage(hwnd, WM_QUIT, 0, 0);
break;
case WM_QUIT:
break;
case WM_SIZE: {
RECT wndRect;
GetWindowRect(hwnd, &wndRect);
// 先让状态栏贴底定位,再按它的实际高度计算 TreeView 可用的客户区
SendMessage(_hStatusBar, WM_SIZE, 0, 0);
RECT client, sb;
GetClientRect(hwnd, &client);
GetWindowRect(_hStatusBar, &sb);
int statusBarH = sb.bottom - sb.top;
// TreeView 占满客户区宽度,高度刚好到状态栏上沿(顶部不留缝)
MoveWindow(hTreeView, 0, 0, client.right, client.bottom - statusBarH, TRUE);
std::stringstream sstr;
sstr << "size: " << std::setw(4) << std::right << wndRect.left
<< ", " << std::setw(4) << std::right << wndRect.top
<< ", " << std::setw(4) << std::right << wndRect.right - wndRect.left
<< ", " << std::setw(4) << std::right << wndRect.bottom - wndRect.top;
SendMessage(_hStatusBar, SB_SETTEXT, 1, (LPARAM)sstr.str().c_str());
break;
}
case WM_MOVE: {
RECT wndRect;
GetWindowRect(hwnd, &wndRect);
std::stringstream sstr;
sstr << "size: " << std::setw(4) << std::right << wndRect.left
<< ", " << std::setw(4) << std::right << wndRect.top
<< ", " << std::setw(4) << std::right << wndRect.right - wndRect.left
<< ", " << std::setw(4) << std::right << wndRect.bottom - wndRect.top;
SendMessage(_hStatusBar, SB_SETTEXT, 1, (LPARAM)sstr.str().c_str());
break;
}
case WM_GETMINMAXINFO:
{
MINMAXINFO* mmi = (MINMAXINFO*)lParam;
UINT dpi = Framework::getDpi(hwnd);
mmi->ptMinTrackSize.x = ::MulDiv(350, dpi, 96); // 随 DPI 缩放
mmi->ptMinTrackSize.y = ::MulDiv(320, dpi, 96);
return 0;
}
case WM_DPICHANGED:
{
UINT m_dpi = LOWORD(wParam);
// 状态栏分栏按新 DPI 刷新
statusBarCtrl.applyScale(m_dpi);
// Individually adjust the treeview item height, since it is not correct.
int SCALED_ITEM_HEIGHT = MulDiv(TREEVIEW_ITEM_HEIGHT, m_dpi, 96);
TreeView_SetItemHeight(hTreeView, SCALED_ITEM_HEIGHT);
// 最后再移到系统建议的新位置/尺寸:SetWindowPos 触发 WM_SIZE,
// 由 WM_SIZE 把 TreeView 重新填满客户区(否则 applyScale 会把 TreeView 打回小尺寸)
RECT* prc = (RECT*)lParam;
SetWindowPos(hwnd, NULL, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, SWP_NOZORDER | SWP_NOACTIVATE);
break;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
HTREEITEM AddChildItem(HWND hwndTree, HTREEITEM hParent, LPCTSTR lpszItem, LPARAM lParam)
{
TVINSERTSTRUCT tvInsert;
tvInsert.hParent = hParent;
tvInsert.hInsertAfter = TVI_LAST;
tvInsert.item.mask = TVIF_TEXT | TVIF_PARAM;
tvInsert.item.pszText = (LPTSTR)lpszItem;
tvInsert.item.lParam = lParam;
return TreeView_InsertItem(hwndTree, &tvInsert);
}
HTREEITEM AddRootItem(HWND hwndTree, LPCTSTR lpszItem, LPARAM lParam)
{
TVINSERTSTRUCT tvInsert;
tvInsert.hParent = TVI_ROOT;
tvInsert.hInsertAfter = TVI_LAST;
tvInsert.item.mask = TVIF_TEXT | TVIF_PARAM;
tvInsert.item.pszText = (LPTSTR)lpszItem;
tvInsert.item.lParam = lParam;
return TreeView_InsertItem(hwndTree, &tvInsert);
}