VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxGINA/Dialog.cpp@ 96686

Last change on this file since 96686 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/* $Id: Dialog.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxGINA - Windows Logon DLL for VirtualBox, Dialog Code.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/win/windows.h>
33
34#include <VBox/VBoxGuestLib.h>
35#include <iprt/errcore.h>
36#include <iprt/utf16.h>
37
38#include "Dialog.h"
39#include "WinWlx.h"
40#include "Helper.h"
41#include "VBoxGINA.h"
42
43
44/*********************************************************************************************************************************
45* Defined Constants And Macros *
46*********************************************************************************************************************************/
47/*
48 * Dialog IDs for legacy Windows OSes (e.g. NT 4.0).
49 */
50#define IDD_WLXDIAPLAYSASNOTICE_DIALOG 1400
51#define IDD_WLXLOGGEDOUTSAS_DIALOG 1450
52/** Change password dialog: To change the current
53 * account password. */
54#define IDD_CHANGE_PASSWORD_DIALOG 1550
55#define IDD_WLXLOGGEDONSAS_DIALOG 1650
56/** Security dialog: To lock the workstation, log off
57 * change password, ... */
58#define IDD_SECURITY_DIALOG 1800
59/** Locked dialog: To unlock the currently lockted
60 * workstation. */
61#define IDD_WLXWKSTALOCKEDSAS_DIALOG 1850
62/** Shutdown dialog: To either restart, logoff current
63 * user or shutdown the workstation. */
64#define IDD_SHUTDOWN_DIALOG 2200
65/** Logoff dialog: "Do you really want to logoff?". */
66#define IDD_LOGOFF_DIALOG 2250
67
68
69/*
70 * Dialog IDs for Windows 2000 and up.
71 */
72#define IDD_WLXLOGGEDOUTSAS_DIALOG2 1500
73/** Change password dialog: To change the current
74 * account password. */
75#define IDD_CHANGE_PASSWORD_DIALOG2 1700
76/** Locked dialog: To unlock the currently lockted
77 * workstation. */
78#define IDD_WLXWKSTALOCKEDSAS_DIALOG2 1950
79
80
81/*
82 * Control IDs.
83 */
84#define IDC_WLXLOGGEDOUTSAS_USERNAME 1453
85#define IDC_WLXLOGGEDOUTSAS_USERNAME2 1502
86#define IDC_WLXLOGGEDOUTSAS_PASSWORD 1454
87#define IDC_WLXLOGGEDOUTSAS_PASSWORD2 1503
88#define IDC_WLXLOGGEDOUTSAS_DOMAIN 1455
89#define IDC_WLXLOGGEDOUTSAS_DOMAIN2 1504
90
91#define IDC_WKSTALOCKED_USERNAME 1953
92#define IDC_WKSTALOCKED_PASSWORD 1954
93#define IDC_WKSTALOCKEd_DOMAIN 1856
94#define IDC_WKSTALOCKED_DOMAIN2 1956
95
96
97/*
98 * Own IDs.
99 */
100#define IDT_BASE WM_USER + 1100 /* Timer ID base. */
101#define IDT_LOGGEDONDLG_POLL IDT_BASE + 1
102#define IDT_LOCKEDDLG_POLL IDT_BASE + 2
103
104
105/*********************************************************************************************************************************
106* Global Variables *
107*********************************************************************************************************************************/
108static DLGPROC g_pfnWlxLoggedOutSASDlgProc = NULL;
109static DLGPROC g_pfnWlxLockedSASDlgProc = NULL;
110
111static PWLX_DIALOG_BOX_PARAM g_pfnWlxDialogBoxParam = NULL;
112
113
114/*********************************************************************************************************************************
115* Internal Functions *
116*********************************************************************************************************************************/
117int WINAPI MyWlxDialogBoxParam (HANDLE, HANDLE, LPWSTR, HWND, DLGPROC, LPARAM);
118
119
120void hookDialogBoxes(PVOID pWinlogonFunctions, DWORD dwWlxVersion)
121{
122 if (!pWinlogonFunctions) /* Needed for testcase. */
123 return;
124
125 VBoxGINAVerbose(0, "VBoxGINA::hookDialogBoxes\n");
126
127 /* this is version dependent */
128 switch (dwWlxVersion)
129 {
130 case WLX_VERSION_1_0:
131 {
132 g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_0)pWinlogonFunctions)->WlxDialogBoxParam;
133 ((PWLX_DISPATCH_VERSION_1_0)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
134 break;
135 }
136
137 case WLX_VERSION_1_1:
138 {
139 g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_1)pWinlogonFunctions)->WlxDialogBoxParam;
140 ((PWLX_DISPATCH_VERSION_1_1)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
141 break;
142 }
143
144 case WLX_VERSION_1_2:
145 {
146 g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_2)pWinlogonFunctions)->WlxDialogBoxParam;
147 ((PWLX_DISPATCH_VERSION_1_2)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
148 break;
149 }
150
151 case WLX_VERSION_1_3:
152 {
153 g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions)->WlxDialogBoxParam;
154 ((PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
155 break;
156 }
157
158 case WLX_VERSION_1_4:
159 {
160 g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_4)pWinlogonFunctions)->WlxDialogBoxParam;
161 ((PWLX_DISPATCH_VERSION_1_4)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
162 break;
163 }
164
165 default:
166 {
167 VBoxGINAVerbose(0, "VBoxGINA::hookDialogBoxes: unrecognized version '%d', nothing hooked!\n", dwWlxVersion);
168 /* not good, don't do anything */
169 break;
170 }
171 }
172}
173
174/**
175 * Enters credentials into the given text fields.
176 *
177 * @return IPRT status code.
178 * @param hwndDlg Handle of dialog to enter credentials into.
179 * @param hwndUserId Handle of username text field. Optional.
180 * @param hwndPassword Handle of password text field. Optional.
181 * @param hwndDomain Handle of domain text field. Optional.
182 * @param pwszUser Username to enter into username text field.
183 * @param pwszPassword Password to enter into password text field.
184 * @param pwszDomain Domain to enter into domain text field.
185 */
186int credentialsToUI(HWND hwndDlg,
187 HWND hwndUserId, HWND hwndPassword, HWND hwndDomain,
188 PCRTUTF16 pwszUser, PCRTUTF16 pwszPassword, PCRTUTF16 pwszDomain)
189{
190 RT_NOREF(hwndDlg);
191 BOOL bIsFQDN = FALSE;
192 wchar_t szUserFQDN[512]; /* VMMDEV_CREDENTIALS_STRLEN + 255 bytes max. for FQDN */
193 if (hwndDomain)
194 {
195 /* search the domain combo box for our required domain and select it */
196 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Trying to find domain entry in combo box ...\n");
197 DWORD dwIndex = (DWORD) SendMessage(hwndDomain, CB_FINDSTRING,
198 0, (LPARAM)pwszDomain);
199 if (dwIndex != CB_ERR)
200 {
201 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Found domain at combo box pos %ld\n", dwIndex);
202 SendMessage(hwndDomain, CB_SETCURSEL, (WPARAM) dwIndex, 0);
203 EnableWindow(hwndDomain, FALSE);
204 }
205 else
206 {
207 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Domain not found in combo box ...\n");
208
209 /* If the domain value has a dot (.) in it, it is a FQDN (Fully Qualified Domain Name)
210 * which will not work with the combo box selection because Windows only keeps the
211 * NETBIOS names to the left most part of the domain name there. Of course a FQDN
212 * then will not be found by the search in the block above.
213 *
214 * To solve this problem the FQDN domain value will be appended at the user name value
215 * (Kerberos style) using an "@", e.g. "<user-name>@full.qualified.domain".
216 *
217 */
218 size_t l = RTUtf16Len(pwszDomain);
219 if (l > 255)
220 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Warning! FQDN (domain) is too long (max 255 bytes), will be truncated!\n");
221
222 if (*pwszUser) /* We need a user name that we can use in caes of a FQDN */
223 {
224 if (l > 16) /* Domain name is longer than 16 chars, cannot be a NetBIOS name anymore */
225 {
226 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Domain seems to be a FQDN (length)!\n");
227 bIsFQDN = TRUE;
228 }
229 else if ( l > 0
230 && RTUtf16Chr(pwszDomain, L'.') != NULL) /* if we found a dot (.) in the domain name, this has to be a FQDN */
231 {
232 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Domain seems to be a FQDN (dot)!\n");
233 bIsFQDN = TRUE;
234 }
235
236 if (bIsFQDN)
237 {
238 RTUtf16Printf(szUserFQDN, sizeof(szUserFQDN) / sizeof(wchar_t), "%ls@%ls", pwszUser, pwszDomain);
239 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: FQDN user name is now: %s!\n", szUserFQDN);
240 }
241 }
242 }
243 }
244 if (hwndUserId)
245 {
246 if (!bIsFQDN)
247 SendMessage(hwndUserId, WM_SETTEXT, 0, (LPARAM)pwszUser);
248 else
249 SendMessage(hwndUserId, WM_SETTEXT, 0, (LPARAM)szUserFQDN);
250 }
251 if (hwndPassword)
252 SendMessage(hwndPassword, WM_SETTEXT, 0, (LPARAM)pwszPassword);
253
254 return VINF_SUCCESS; /** @todo */
255}
256
257/**
258 * Tries to retrieve credentials and enters them into the specified windows,
259 * optionally followed by a button press to confirm/abort the dialog.
260 *
261 * @return IPRT status code.
262 * @param hwndDlg Handle of dialog to enter credentials into.
263 * @param hwndUserId Handle of username text field. Optional.
264 * @param hwndPassword Handle of password text field. Optional.
265 * @param hwndDomain Handle of domain text field. Optional.
266 * @param wButtonToPress Button ID of dialog to press after successful
267 * retrieval + storage. If set to 0 no button will
268 * be pressed.
269 */
270int credentialsHandle(HWND hwndDlg,
271 HWND hwndUserId, HWND hwndPassword, HWND hwndDomain,
272 WORD wButtonToPress)
273{
274 int rc = VINF_SUCCESS;
275
276 if (!VBoxGINAHandleCurrentSession())
277 rc = VERR_NOT_FOUND;
278
279 if (RT_SUCCESS(rc))
280 {
281 rc = VbglR3CredentialsQueryAvailability();
282 if (RT_FAILURE(rc))
283 {
284 if (rc != VERR_NOT_FOUND)
285 VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: error querying for credentials, rc=%Rrc\n", rc);
286 }
287 }
288
289 if (RT_SUCCESS(rc))
290 {
291 VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: credentials available\n");
292
293 /*
294 * Set status to "terminating" to let the host know this module now
295 * tries to receive and use passed credentials so that credentials from
296 * the host won't be sent twice.
297 */
298 VBoxGINAReportStatus(VBoxGuestFacilityStatus_Terminating);
299
300 PRTUTF16 pwszUser, pwszPassword, pwszDomain;
301 rc = VbglR3CredentialsRetrieveUtf16(&pwszUser, &pwszPassword, &pwszDomain);
302 if (RT_SUCCESS(rc))
303 {
304#ifdef DEBUG
305 VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: retrieved credentials: user=%ls, password=%ls, domain=%ls\n",
306 pwszUser, pwszPassword, pwszDomain);
307#else
308 VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: retrieved credentials: user=%ls, password=XXX, domain=%ls\n",
309 pwszUser, pwszDomain);
310#endif
311 /* Fill in credentials to appropriate UI elements. */
312 rc = credentialsToUI(hwndDlg,
313 hwndUserId, hwndPassword, hwndDomain,
314 pwszUser, pwszPassword, pwszDomain);
315 if (RT_SUCCESS(rc))
316 {
317 /* Confirm/cancel the dialog by pressing the appropriate button. */
318 if (wButtonToPress)
319 {
320 WPARAM wParam = MAKEWPARAM(wButtonToPress, BN_CLICKED);
321 PostMessage(hwndDlg, WM_COMMAND, wParam, 0);
322 }
323 }
324
325 VbglR3CredentialsDestroyUtf16(pwszUser, pwszPassword, pwszDomain,
326 3 /* Passes */);
327 }
328 }
329
330#ifdef DEBUG
331 VBoxGINAVerbose(3, "VBoxGINA::credentialsHandle: returned with rc=%Rrc\n", rc);
332#endif
333 return rc;
334}
335
336INT_PTR CALLBACK MyWlxLoggedOutSASDlgProc(HWND hwndDlg, // handle to dialog box
337 UINT uMsg, // message
338 WPARAM wParam, // first message parameter
339 LPARAM lParam) // second message parameter
340{
341 BOOL bResult;
342 static HWND s_hwndUserId, s_hwndPassword, s_hwndDomain = 0;
343
344 /*VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc\n");*/
345
346 //
347 // Pass on to MSGINA first.
348 //
349 bResult = g_pfnWlxLoggedOutSASDlgProc(hwndDlg, uMsg, wParam, lParam);
350
351 //
352 // We are only interested in the WM_INITDIALOG message.
353 //
354 switch (uMsg)
355 {
356 case WM_INITDIALOG:
357 {
358 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: got WM_INITDIALOG\n");
359
360 /* get the entry fields */
361 s_hwndUserId = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_USERNAME);
362 if (!s_hwndUserId)
363 s_hwndUserId = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_USERNAME2);
364 s_hwndPassword = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_PASSWORD);
365 if (!s_hwndPassword)
366 s_hwndPassword = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_PASSWORD2);
367 s_hwndDomain = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_DOMAIN);
368 if (!s_hwndDomain)
369 s_hwndDomain = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_DOMAIN2);
370
371 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: hwndUserId: %x, hwndPassword: %d, hwndDomain: %d\n",
372 s_hwndUserId, s_hwndPassword, s_hwndDomain);
373
374 /* terminate the credentials poller thread, it's done is job */
375 VBoxGINACredentialsPollerTerminate();
376
377 int rc = credentialsHandle(hwndDlg,
378 s_hwndUserId, s_hwndPassword, s_hwndDomain,
379 IDOK /* Button */);
380 if (RT_FAILURE(rc))
381 {
382 /*
383 * The dialog is there but we don't have any credentials.
384 * Create a timer and poll for them.
385 */
386 UINT_PTR uTimer = SetTimer(hwndDlg, IDT_LOGGEDONDLG_POLL, 200, NULL);
387 if (!uTimer)
388 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: failed creating timer! Last error: %ld\n",
389 GetLastError());
390 }
391 break;
392 }
393
394 case WM_TIMER:
395 {
396 /* is it our credentials poller timer? */
397 if (wParam == IDT_LOGGEDONDLG_POLL)
398 {
399 int rc = credentialsHandle(hwndDlg,
400 s_hwndUserId, s_hwndPassword, s_hwndDomain,
401 IDOK /* Button */);
402 if (RT_SUCCESS(rc))
403 {
404 /* we don't need the timer any longer */
405 KillTimer(hwndDlg, IDT_LOGGEDONDLG_POLL);
406 }
407 }
408 break;
409 }
410
411 case WM_DESTROY:
412 KillTimer(hwndDlg, IDT_LOGGEDONDLG_POLL);
413 break;
414 }
415 return bResult;
416}
417
418
419INT_PTR CALLBACK MyWlxLockedSASDlgProc(HWND hwndDlg, // handle to dialog box
420 UINT uMsg, // message
421 WPARAM wParam, // first message parameter
422 LPARAM lParam) // second message parameter
423{
424 BOOL bResult;
425 static HWND s_hwndPassword = 0;
426
427 /*VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc\n");*/
428
429 //
430 // Pass on to MSGINA first.
431 //
432 bResult = g_pfnWlxLockedSASDlgProc(hwndDlg, uMsg, wParam, lParam);
433
434 //
435 // We are only interested in the WM_INITDIALOG message.
436 //
437 switch (uMsg)
438 {
439 case WM_INITDIALOG:
440 {
441 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: WM_INITDIALOG\n");
442
443 /* get the entry fields */
444 s_hwndPassword = GetDlgItem(hwndDlg, IDC_WKSTALOCKED_PASSWORD);
445 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: hwndPassword: %d\n", s_hwndPassword);
446
447 /* terminate the credentials poller thread, it's done is job */
448 VBoxGINACredentialsPollerTerminate();
449
450 int rc = credentialsHandle(hwndDlg,
451 NULL /* Username */, s_hwndPassword, NULL /* Domain */,
452 IDOK /* Button */);
453 if (RT_FAILURE(rc))
454 {
455 /*
456 * The dialog is there but we don't have any credentials.
457 * Create a timer and poll for them.
458 */
459 UINT_PTR uTimer = SetTimer(hwndDlg, IDT_LOCKEDDLG_POLL, 200, NULL);
460 if (!uTimer)
461 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: failed creating timer! Last error: %ld\n",
462 GetLastError());
463 }
464 break;
465 }
466
467 case WM_TIMER:
468 {
469 /* is it our credentials poller timer? */
470 if (wParam == IDT_LOCKEDDLG_POLL)
471 {
472 int rc = credentialsHandle(hwndDlg,
473 NULL /* Username */, s_hwndPassword, NULL /* Domain */,
474 IDOK /* Button */);
475 if (RT_SUCCESS(rc))
476 {
477 /* we don't need the timer any longer */
478 KillTimer(hwndDlg, IDT_LOCKEDDLG_POLL);
479 }
480 }
481 break;
482 }
483
484 case WM_DESTROY:
485 {
486 VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: WM_DESTROY\n");
487
488 /* Because this is the only point where we know within our module that the locked
489 * dialog has been closed by a valid unlock password we have to set the appropriate
490 * facility status here. */
491 VBoxGINAReportStatus(VBoxGuestFacilityStatus_Terminated);
492
493 KillTimer(hwndDlg, IDT_LOCKEDDLG_POLL);
494 break;
495 }
496 }
497 return bResult;
498}
499
500
501int WINAPI MyWlxDialogBoxParam(HANDLE hWlx,
502 HANDLE hInst,
503 LPWSTR pszTemplate,
504 HWND hwndOwner,
505 DLGPROC dlgprc,
506 LPARAM dwInitParam)
507{
508 VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: pszTemplate=%ls\n", pszTemplate);
509
510 VBoxGINAReportStatus(VBoxGuestFacilityStatus_Active);
511
512 //
513 // We only know MSGINA dialogs by identifiers.
514 //
515 if (((uintptr_t)pszTemplate >> 16) == 0)
516 {
517 //
518 // Hook appropriate dialog boxes as necessary.
519 //
520 switch ((DWORD)(uintptr_t)pszTemplate)
521 {
522 case IDD_WLXDIAPLAYSASNOTICE_DIALOG:
523 VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: SAS notice dialog displayed; not handled\n");
524 break;
525
526 case IDD_WLXLOGGEDOUTSAS_DIALOG: /* Windows NT 4.0. */
527 case IDD_WLXLOGGEDOUTSAS_DIALOG2: /* Windows 2000 and up. */
528 {
529 VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: returning hooked SAS logged out dialog\n");
530 g_pfnWlxLoggedOutSASDlgProc = dlgprc;
531 return g_pfnWlxDialogBoxParam(hWlx, hInst, pszTemplate, hwndOwner,
532 MyWlxLoggedOutSASDlgProc, dwInitParam);
533 }
534
535 case IDD_SECURITY_DIALOG:
536 VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: Security dialog displayed; not handled\n");
537 break;
538
539 case IDD_WLXWKSTALOCKEDSAS_DIALOG: /* Windows NT 4.0. */
540 case IDD_WLXWKSTALOCKEDSAS_DIALOG2: /* Windows 2000 and up. */
541 {
542 VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: returning hooked SAS locked dialog\n");
543 g_pfnWlxLockedSASDlgProc = dlgprc;
544 return g_pfnWlxDialogBoxParam(hWlx, hInst, pszTemplate, hwndOwner,
545 MyWlxLockedSASDlgProc, dwInitParam);
546 }
547
548 /** @todo Add other hooking stuff here. */
549
550 default:
551 VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: dialog %p (%u) not handled\n",
552 pszTemplate, (DWORD)(uintptr_t)pszTemplate);
553 break;
554 }
555 }
556
557 /* The rest will be redirected. */
558 return g_pfnWlxDialogBoxParam(hWlx, hInst, pszTemplate, hwndOwner, dlgprc, dwInitParam);
559}
560
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette