VirtualBox

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

Last change on this file since 95891 was 95891, checked in by vboxsync, 23 months ago

Add/Nt/VBoxGINA: Made it build in VBOX_WITH_NOCRT_STATIC mode. [scm fixes] bugref:10261

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

© 2023 Oracle
ContactPrivacy policyTerms of Use