Skip to content

Commit ad18dc9

Browse files
committed
[UI] Add WindowPicker dialog box and fix UI render issues
1 parent ca31d52 commit ad18dc9

9 files changed

Lines changed: 377 additions & 50 deletions

File tree

Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@
227227
<ClCompile Include="UI\Control\TreeView.c" />
228228
<ClCompile Include="UI\DialogBox\RectEditor.c" />
229229
<ClCompile Include="UI\DialogBox\ValueEditor.c" />
230+
<ClCompile Include="UI\DialogBox\WindowPicker.c" />
230231
<ClCompile Include="UI\DPI.c" />
231232
<ClCompile Include="UI\GDI.c" />
232233
<ClCompile Include="UI\Gdip.cpp" />

Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@
192192
<ClCompile Include="UI\Gdip.cpp">
193193
<Filter>UI</Filter>
194194
</ClCompile>
195+
<ClCompile Include="UI\DialogBox\WindowPicker.c">
196+
<Filter>UI\DialogBox</Filter>
197+
</ClCompile>
195198
</ItemGroup>
196199
<ItemGroup>
197200
<None Include="MakeLifeEasier.inl" />

Source/KNSoft.MakeLifeEasier/MakeLifeEasier.inl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "MakeLifeEasier.h"
1919

20+
#include <windowsx.h>
21+
2022
EXTERN_C_START
2123

2224
PCWSTR

Source/KNSoft.MakeLifeEasier/UI/DialogBox/DialogBox.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,17 @@ UI_ValueEditorDlg(
162162
_In_reads_(ConstantCount) UI_VALUEEDITOR_CONSTANT Constants[],
163163
_In_ ULONG ConstantCount);
164164

165+
/// <returns>
166+
/// S_OK if user confirmed selection. TargetWindow may still be NULL.
167+
/// S_FALSE if user canceled.
168+
/// </returns>
169+
MLE_API
170+
HRESULT
171+
NTAPI
172+
UI_WindowPickerDlg(
173+
_In_ LOGICAL IgnoreChild,
174+
_In_ LOGICAL IgnoreTransparent,
175+
_In_opt_ HCURSOR Cursor,
176+
_Out_ HWND * TargetWindow);
177+
165178
EXTERN_C_END
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
#include "../../MakeLifeEasier.inl"
2+
3+
#define UI_CAPTURE_WINDOW L"KNSoft.MakeLifeEasier.UI.CaptureWindow"
4+
#define UI_CAPTURE_WINDOW_BORDER -2
5+
6+
typedef struct _UI_CAPTURE_WINDOW_DATA
7+
{
8+
/* Input */
9+
UI_SNAPSHOT Snapshot;
10+
HWND TargetWindow;
11+
struct
12+
{
13+
ULONG IgnoreChild : 1;
14+
ULONG IgnoreTransparent : 1;
15+
};
16+
HCURSOR Cursor;
17+
18+
/* Internal use */
19+
HWND CaptureWindow;
20+
HWND TempTarget;
21+
POINT Position;
22+
LOGICAL Done;
23+
HRESULT Result;
24+
} UI_CAPTURE_WINDOW_DATA, *PUI_CAPTURE_WINDOW_DATA;
25+
26+
static
27+
BOOL
28+
CALLBACK
29+
CaptureWndEnumProc(
30+
HWND hWnd,
31+
LPARAM lParam)
32+
{
33+
RECT rc;
34+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)lParam;
35+
36+
if (hWnd != Data->CaptureWindow &&
37+
IsWindowVisible(hWnd) &&
38+
(!Data->IgnoreTransparent || !(GetWindowLongPtrW(hWnd, GWL_EXSTYLE) & WS_EX_TRANSPARENT)) &&
39+
!IsIconic(hWnd) &&
40+
UI_GetWindowCloackedState(hWnd) == 0 &&
41+
SUCCEEDED(UI_GetWindowRect(hWnd, &rc)) &&
42+
UI_PtInRect(&rc, &Data->Position))
43+
{
44+
Data->TempTarget = hWnd;
45+
return FALSE;
46+
}
47+
return TRUE;
48+
}
49+
50+
static BLENDFUNCTION g_BlendFunc = { AC_SRC_OVER, 0, 128, 0 };
51+
52+
static
53+
LRESULT
54+
CALLBACK
55+
CaptureWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
56+
{
57+
if (uMsg == WM_CREATE)
58+
{
59+
LPCREATESTRUCTW pCreate = (LPCREATESTRUCTW)lParam;
60+
if (pCreate->lpCreateParams == NULL ||
61+
UI_SetWindowLong(hWnd, GWLP_USERDATA, (LONG_PTR)pCreate->lpCreateParams) != ERROR_SUCCESS)
62+
{
63+
return -1;
64+
}
65+
((PUI_CAPTURE_WINDOW_DATA)pCreate->lpCreateParams)->CaptureWindow = hWnd;
66+
} else if (uMsg == WM_SETCURSOR)
67+
{
68+
if (LOWORD(lParam) == HTCLIENT)
69+
{
70+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
71+
SetCursor(Data->Cursor);
72+
return TRUE;
73+
}
74+
} else if (uMsg == WM_PAINT)
75+
{
76+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
77+
UI_BUFFEREDPAINT Paint;
78+
RECT rc;
79+
80+
if (!UI_BeginBufferedPaint(hWnd, &Paint))
81+
{
82+
return 0;
83+
}
84+
GdiAlphaBlend(Paint.hdc,
85+
0,
86+
0,
87+
Data->Snapshot.Size.cx,
88+
Data->Snapshot.Size.cy,
89+
Data->Snapshot.DC,
90+
0,
91+
0,
92+
Data->Snapshot.Size.cx,
93+
Data->Snapshot.Size.cy,
94+
g_BlendFunc);
95+
if (Data->TargetWindow != NULL &&
96+
SUCCEEDED(UI_GetRelativeRect(Data->TargetWindow, hWnd, &rc)))
97+
{
98+
BitBlt(Paint.hdc,
99+
rc.left,
100+
rc.top,
101+
rc.right - rc.left,
102+
rc.bottom - rc.top,
103+
Data->Snapshot.DC,
104+
rc.left,
105+
rc.top,
106+
SRCCOPY);
107+
UI_DrawFrameRect(Paint.hdc, &rc, UI_CAPTURE_WINDOW_BORDER, DSTINVERT);
108+
}
109+
UI_EndBufferedPaint(hWnd, &Paint);
110+
return 0;
111+
} else if (uMsg == WM_MOUSEMOVE)
112+
{
113+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
114+
HWND hWndParent;
115+
POINT pt;
116+
117+
Data->Position.x = GET_X_LPARAM(lParam);
118+
Data->Position.y = GET_Y_LPARAM(lParam);
119+
if (ClientToScreen(hWnd, &Data->Position))
120+
{
121+
hWndParent = GetDesktopWindow();
122+
Data->TempTarget = NULL;
123+
if (!Data->IgnoreChild)
124+
{
125+
while (TRUE)
126+
{
127+
pt = Data->Position;
128+
if (!ScreenToClient(hWndParent, &pt))
129+
{
130+
break;
131+
}
132+
UI_EnumChildWindows(hWndParent, CaptureWndEnumProc, (LPARAM)Data);
133+
if (Data->TempTarget == NULL)
134+
{
135+
Data->TempTarget = hWndParent;
136+
break;
137+
} else if (Data->TempTarget == hWndParent)
138+
{
139+
break;
140+
} else
141+
{
142+
hWndParent = Data->TempTarget;
143+
Data->TempTarget = NULL;
144+
}
145+
}
146+
} else
147+
{
148+
UI_EnumChildWindows(hWndParent, CaptureWndEnumProc, (LPARAM)Data);
149+
}
150+
if (Data->TargetWindow != Data->TempTarget)
151+
{
152+
Data->TargetWindow = Data->TempTarget;
153+
UI_Redraw(hWnd);
154+
}
155+
}
156+
return 0;
157+
} else if (uMsg == WM_LBUTTONUP)
158+
{
159+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
160+
Data->Result = S_OK;
161+
DestroyWindow(hWnd);
162+
return 0;
163+
} else if (uMsg == WM_KEYUP)
164+
{
165+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
166+
if (wParam == VK_CANCEL || wParam == VK_ESCAPE || wParam == VK_END || wParam == VK_RETURN)
167+
{
168+
if (wParam != VK_RETURN)
169+
{
170+
Data->TargetWindow = NULL;
171+
Data->Result = S_FALSE;
172+
Data->Done = TRUE;
173+
}
174+
if (wParam == VK_RETURN)
175+
{
176+
Data->Result = S_OK;
177+
}
178+
DestroyWindow(hWnd);
179+
}
180+
return 0;
181+
} else if (uMsg == WM_DESTROY)
182+
{
183+
PUI_CAPTURE_WINDOW_DATA Data = (PUI_CAPTURE_WINDOW_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
184+
if (Data != NULL && !Data->Done)
185+
{
186+
Data->Done = TRUE;
187+
}
188+
return 0;
189+
}
190+
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
191+
}
192+
193+
static CONST WNDCLASSEXW g_Class = {
194+
sizeof(g_Class),
195+
0,
196+
CaptureWndProc,
197+
0,
198+
0,
199+
(HINSTANCE)&__ImageBase,
200+
NULL,
201+
NULL,
202+
NULL,
203+
NULL,
204+
UI_CAPTURE_WINDOW,
205+
NULL };
206+
207+
HRESULT
208+
NTAPI
209+
UI_WindowPickerDlg(
210+
_In_ LOGICAL IgnoreChild,
211+
_In_ LOGICAL IgnoreTransparent,
212+
_In_opt_ HCURSOR Cursor,
213+
_Out_ HWND * TargetWindow)
214+
{
215+
HRESULT hr;
216+
PUI_CAPTURE_WINDOW_DATA Data;
217+
DPI_AWARENESS_CONTEXT DPIContext;
218+
ATOM atom;
219+
HWND hWnd;
220+
BOOL Ret;
221+
MSG Msg;
222+
223+
if (!Mem_AllocPtr(Data))
224+
{
225+
return E_OUTOFMEMORY;
226+
}
227+
DPIContext = UI_EnableDPIAwareContext();
228+
if (!UI_CreateSnapshot(NULL, &Data->Snapshot))
229+
{
230+
hr = E_UNEXPECTED;
231+
goto _Exit_0;
232+
}
233+
atom = RegisterClassExW(&g_Class);
234+
if (atom == 0)
235+
{
236+
hr = HRESULT_FROM_WIN32(Err_GetLastError());
237+
goto _Exit_1;
238+
}
239+
Data->Cursor = Cursor == NULL ? LoadImageW(NULL,
240+
MAKEINTRESOURCEW(OCR_NORMAL),
241+
IMAGE_CURSOR,
242+
0,
243+
0,
244+
LR_DEFAULTSIZE | LR_SHARED) : Cursor;
245+
Data->TargetWindow = NULL;
246+
Data->IgnoreChild = IgnoreChild;
247+
Data->IgnoreTransparent = IgnoreTransparent;
248+
Data->Done = FALSE;
249+
Data->Result = S_FALSE;
250+
hWnd = CreateWindowExW(WS_EX_TOOLWINDOW,
251+
MAKEINTRESOURCEW(atom),
252+
UI_CAPTURE_WINDOW,
253+
WS_POPUP | WS_VISIBLE,
254+
Data->Snapshot.Position.x,
255+
Data->Snapshot.Position.y,
256+
Data->Snapshot.Size.cx,
257+
Data->Snapshot.Size.cy,
258+
HWND_DESKTOP,
259+
NULL,
260+
(HINSTANCE)&__ImageBase,
261+
Data);
262+
if (hWnd == NULL)
263+
{
264+
hr = HRESULT_FROM_WIN32(Err_GetLastError());
265+
goto _Exit_2;
266+
}
267+
while (!Data->Done)
268+
{
269+
Ret = GetMessageW(&Msg, hWnd, 0, 0);
270+
if (Ret == -1)
271+
{
272+
hr = HRESULT_FROM_WIN32(Err_GetLastError());
273+
goto _Exit_2;
274+
} else if (Ret == 0)
275+
{
276+
PostQuitMessage((INT)Msg.wParam);
277+
hr = E_ABORT;
278+
goto _Exit_2;
279+
}
280+
TranslateMessage(&Msg);
281+
DispatchMessageW(&Msg);
282+
}
283+
hr = Data->Result;
284+
if (SUCCEEDED(hr))
285+
{
286+
*TargetWindow = Data->TargetWindow;
287+
}
288+
289+
_Exit_2:
290+
UnregisterClassW(MAKEINTRESOURCEW(atom), (HINSTANCE)&__ImageBase);
291+
_Exit_1:
292+
UI_DeleteSnapshot(&Data->Snapshot);
293+
_Exit_0:
294+
UI_RestoreDPIAwareContext(DPIContext);
295+
Mem_Free(Data);
296+
return hr;
297+
}

Source/KNSoft.MakeLifeEasier/UI/GDI.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,10 @@ UI_CreateSnapshot(
462462
goto _Error_2;
463463
}
464464
hBmpOriginal = SelectObject(hMemDC, hBmp);
465+
if (hBmpOriginal == NULL)
466+
{
467+
goto _Error_3;
468+
}
465469

466470
if (Window == NULL ||
467471
!PrintWindow(Window, hMemDC, PW_CLIENTONLY | PW_RENDERFULLCONTENT))
@@ -471,21 +475,23 @@ UI_CreateSnapshot(
471475
{
472476
bRet = TRUE;
473477
}
474-
475-
SelectObject(hMemDC, hBmpOriginal);
476478
if (!bRet)
477479
{
478-
DeleteObject(hBmp);
479-
goto _Error_2;
480+
SelectObject(hMemDC, hBmpOriginal);
481+
goto _Error_3;
480482
}
481483

482484
/* Success */
485+
ReleaseDC(Window, hDC);
483486
Snapshot->DC = hMemDC;
484487
Snapshot->Bitmap = hBmp;
485488
Snapshot->Position = pt;
486489
Snapshot->Size = size;
490+
Snapshot->OriginalBitmap = hBmpOriginal;
487491
return TRUE;
488492

493+
_Error_3:
494+
DeleteObject(hBmp);
489495
_Error_2:
490496
DeleteDC(hMemDC);
491497
_Error_1:
@@ -499,6 +505,7 @@ NTAPI
499505
UI_DeleteSnapshot(
500506
_In_ PUI_SNAPSHOT Snapshot)
501507
{
508+
SelectObject(Snapshot->DC, Snapshot->OriginalBitmap);
502509
DeleteDC(Snapshot->DC);
503510
DeleteObject(Snapshot->Bitmap);
504511
}

Source/KNSoft.MakeLifeEasier/UI/GDI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ typedef struct _UI_SNAPSHOT
180180
HBITMAP Bitmap;
181181
POINT Position;
182182
SIZE Size;
183+
184+
HBITMAP OriginalBitmap;
183185
} UI_SNAPSHOT, *PUI_SNAPSHOT;
184186

185187
MLE_API

0 commit comments

Comments
 (0)