[WINLOGON]
[reactos.git] / reactos / dll / win32 / msgina / gui.c
1 /*
2 * PROJECT: ReactOS msgina.dll
3 * FILE: dll/win32/msgina/gui.c
4 * PURPOSE: ReactOS Logon GINA DLL
5 * PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org)
6 */
7
8 #include "msgina.h"
9
10 typedef struct _DISPLAYSTATUSMSG
11 {
12 PGINA_CONTEXT Context;
13 HDESK hDesktop;
14 DWORD dwOptions;
15 PWSTR pTitle;
16 PWSTR pMessage;
17 HANDLE StartupEvent;
18 } DISPLAYSTATUSMSG, *PDISPLAYSTATUSMSG;
19
20 static BOOL
21 GUIInitialize(
22 IN OUT PGINA_CONTEXT pgContext)
23 {
24 TRACE("GUIInitialize(%p)\n", pgContext);
25 return TRUE;
26 }
27
28 static INT_PTR CALLBACK
29 StatusMessageWindowProc(
30 IN HWND hwndDlg,
31 IN UINT uMsg,
32 IN WPARAM wParam,
33 IN LPARAM lParam)
34 {
35 UNREFERENCED_PARAMETER(wParam);
36
37 switch (uMsg)
38 {
39 case WM_INITDIALOG:
40 {
41 PDISPLAYSTATUSMSG msg = (PDISPLAYSTATUSMSG)lParam;
42 if (!msg)
43 return FALSE;
44
45 msg->Context->hStatusWindow = hwndDlg;
46
47 if (msg->pTitle)
48 SetWindowTextW(hwndDlg, msg->pTitle);
49 SetDlgItemTextW(hwndDlg, IDC_STATUSLABEL, msg->pMessage);
50 SetEvent(msg->StartupEvent);
51 return TRUE;
52 }
53 }
54 return FALSE;
55 }
56
57 static DWORD WINAPI
58 StartupWindowThread(LPVOID lpParam)
59 {
60 HDESK hDesk;
61 PDISPLAYSTATUSMSG msg = (PDISPLAYSTATUSMSG)lpParam;
62
63 /* When SetThreadDesktop is called the system closes the desktop handle when needed
64 so we have to create a new handle because this handle may still be in use by winlogon */
65 if (!DuplicateHandle ( GetCurrentProcess(),
66 msg->hDesktop,
67 GetCurrentProcess(),
68 (HANDLE*)&hDesk,
69 0,
70 FALSE,
71 DUPLICATE_SAME_ACCESS))
72 {
73 HeapFree(GetProcessHeap(), 0, lpParam);
74 return FALSE;
75 }
76
77 if(!SetThreadDesktop(hDesk))
78 {
79 HeapFree(GetProcessHeap(), 0, lpParam);
80 return FALSE;
81 }
82
83 DialogBoxParam(
84 hDllInstance,
85 MAKEINTRESOURCE(IDD_STATUSWINDOW_DLG),
86 GetDesktopWindow(),
87 StatusMessageWindowProc,
88 (LPARAM)lpParam);
89
90 HeapFree(GetProcessHeap(), 0, lpParam);
91 return TRUE;
92 }
93
94 static BOOL
95 GUIDisplayStatusMessage(
96 IN PGINA_CONTEXT pgContext,
97 IN HDESK hDesktop,
98 IN DWORD dwOptions,
99 IN PWSTR pTitle,
100 IN PWSTR pMessage)
101 {
102 PDISPLAYSTATUSMSG msg;
103 HANDLE Thread;
104 DWORD ThreadId;
105
106 TRACE("GUIDisplayStatusMessage(%ws)\n", pMessage);
107
108 if (!pgContext->hStatusWindow)
109 {
110 msg = (PDISPLAYSTATUSMSG)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DISPLAYSTATUSMSG));
111 if(!msg)
112 return FALSE;
113
114 msg->Context = pgContext;
115 msg->dwOptions = dwOptions;
116 msg->pTitle = pTitle;
117 msg->pMessage = pMessage;
118 msg->hDesktop = hDesktop;
119
120 msg->StartupEvent = CreateEventW(
121 NULL,
122 TRUE,
123 FALSE,
124 NULL);
125
126 if (!msg->StartupEvent)
127 return FALSE;
128
129 Thread = CreateThread(
130 NULL,
131 0,
132 StartupWindowThread,
133 (PVOID)msg,
134 0,
135 &ThreadId);
136 if (Thread)
137 {
138 CloseHandle(Thread);
139 WaitForSingleObject(msg->StartupEvent, INFINITE);
140 CloseHandle(msg->StartupEvent);
141 return TRUE;
142 }
143
144 return FALSE;
145 }
146
147 if (pTitle)
148 SetWindowTextW(pgContext->hStatusWindow, pTitle);
149
150 SetDlgItemTextW(pgContext->hStatusWindow, IDC_STATUSLABEL, pMessage);
151
152 return TRUE;
153 }
154
155 static BOOL
156 GUIRemoveStatusMessage(
157 IN PGINA_CONTEXT pgContext)
158 {
159 if (pgContext->hStatusWindow)
160 {
161 EndDialog(pgContext->hStatusWindow, 0);
162 pgContext->hStatusWindow = NULL;
163 }
164
165 return TRUE;
166 }
167
168 static INT_PTR CALLBACK
169 EmptyWindowProc(
170 IN HWND hwndDlg,
171 IN UINT uMsg,
172 IN WPARAM wParam,
173 IN LPARAM lParam)
174 {
175 UNREFERENCED_PARAMETER(hwndDlg);
176 UNREFERENCED_PARAMETER(uMsg);
177 UNREFERENCED_PARAMETER(wParam);
178 UNREFERENCED_PARAMETER(lParam);
179
180 return FALSE;
181 }
182
183 static VOID
184 GUIDisplaySASNotice(
185 IN OUT PGINA_CONTEXT pgContext)
186 {
187 TRACE("GUIDisplaySASNotice()\n");
188
189 /* Display the notice window */
190 pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
191 pgContext->hDllInstance,
192 MAKEINTRESOURCEW(IDD_NOTICE_DLG),
193 GetDesktopWindow(),
194 EmptyWindowProc,
195 (LPARAM)NULL);
196 }
197
198 /* Get the text contained in a textbox. Allocates memory in pText
199 * to contain the text. Returns TRUE in case of success */
200 static BOOL
201 GetTextboxText(
202 IN HWND hwndDlg,
203 IN INT TextboxId,
204 OUT LPWSTR *pText)
205 {
206 LPWSTR Text;
207 int Count;
208
209 Count = GetWindowTextLength(GetDlgItem(hwndDlg, TextboxId));
210 Text = HeapAlloc(GetProcessHeap(), 0, (Count + 1) * sizeof(WCHAR));
211 if (!Text)
212 return FALSE;
213 if (Count != GetWindowTextW(GetDlgItem(hwndDlg, TextboxId), Text, Count + 1))
214 {
215 HeapFree(GetProcessHeap(), 0, Text);
216 return FALSE;
217 }
218 *pText = Text;
219 return TRUE;
220 }
221
222
223 static INT_PTR CALLBACK
224 ChangePasswordDialogProc(
225 IN HWND hwndDlg,
226 IN UINT uMsg,
227 IN WPARAM wParam,
228 IN LPARAM lParam)
229 {
230 switch (uMsg)
231 {
232 case WM_INITDIALOG:
233 FIXME("ChangePasswordDialogProc: WM_INITDLG\n");
234 return TRUE;
235
236 case WM_COMMAND:
237 switch (LOWORD(wParam))
238 {
239 case IDOK:
240 EndDialog(hwndDlg, TRUE);
241 return TRUE;
242
243 case IDCANCEL:
244 EndDialog(hwndDlg, FALSE);
245 return TRUE;
246 }
247 break;
248
249 case WM_CLOSE:
250 EndDialog(hwndDlg, FALSE);
251 return TRUE;
252 }
253
254 return FALSE;
255 }
256
257
258 static VOID
259 OnInitSecurityDlg(HWND hwnd,
260 PGINA_CONTEXT pgContext)
261 {
262 WCHAR Buffer1[256];
263 WCHAR Buffer2[256];
264 WCHAR Buffer3[256];
265 WCHAR Buffer4[512];
266
267 LoadStringW(pgContext->hDllInstance, IDS_LOGONMSG, Buffer1, 256);
268
269 wsprintfW(Buffer2, L"%s\\%s", pgContext->Domain, pgContext->UserName);
270 wsprintfW(Buffer4, Buffer1, Buffer2);
271
272 SetDlgItemTextW(hwnd, IDC_LOGONMSG, Buffer4);
273
274 LoadStringW(pgContext->hDllInstance, IDS_LOGONDATE, Buffer1, 256);
275
276 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE,
277 (SYSTEMTIME*)&pgContext->LogonTime, NULL, Buffer2, 256);
278
279 GetTimeFormatW(LOCALE_USER_DEFAULT, 0,
280 (SYSTEMTIME*)&pgContext->LogonTime, NULL, Buffer3, 256);
281
282 wsprintfW(Buffer4, Buffer1, Buffer2, Buffer3);
283
284 SetDlgItemTextW(hwnd, IDC_LOGONDATE, Buffer4);
285 }
286
287
288 static BOOL
289 OnChangePassword(
290 IN HWND hwnd,
291 IN PGINA_CONTEXT pgContext)
292 {
293 INT res;
294
295 FIXME("OnChangePassword()\n");
296
297 res = pgContext->pWlxFuncs->WlxDialogBoxParam(
298 pgContext->hWlx,
299 pgContext->hDllInstance,
300 MAKEINTRESOURCEW(IDD_CHANGE_PASSWORD),
301 hwnd,
302 ChangePasswordDialogProc,
303 (LPARAM)pgContext);
304
305 FIXME("Result: %x\n", res);
306
307 return FALSE;
308 }
309
310
311 static INT_PTR CALLBACK
312 LoggedOnWindowProc(
313 IN HWND hwndDlg,
314 IN UINT uMsg,
315 IN WPARAM wParam,
316 IN LPARAM lParam)
317 {
318 PGINA_CONTEXT pgContext;
319
320 pgContext = (PGINA_CONTEXT)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
321
322 switch (uMsg)
323 {
324 case WM_INITDIALOG:
325 {
326 pgContext = (PGINA_CONTEXT)lParam;
327 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)pgContext);
328
329 OnInitSecurityDlg(hwndDlg, (PGINA_CONTEXT)lParam);
330 SetFocus(GetDlgItem(hwndDlg, IDNO));
331 return TRUE;
332 }
333
334 case WM_COMMAND:
335 {
336 switch (LOWORD(wParam))
337 {
338 case IDC_LOCK:
339 EndDialog(hwndDlg, WLX_SAS_ACTION_LOCK_WKSTA);
340 return TRUE;
341 case IDC_LOGOFF:
342 EndDialog(hwndDlg, WLX_SAS_ACTION_LOGOFF);
343 return TRUE;
344 case IDC_SHUTDOWN:
345 EndDialog(hwndDlg, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
346 return TRUE;
347 case IDC_CHANGEPWD:
348 if (OnChangePassword(hwndDlg, pgContext))
349 EndDialog(hwndDlg, WLX_SAS_ACTION_PWD_CHANGED);
350 return TRUE;
351 case IDC_TASKMGR:
352 EndDialog(hwndDlg, WLX_SAS_ACTION_TASKLIST);
353 return TRUE;
354 case IDCANCEL:
355 EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
356 return TRUE;
357 }
358 break;
359 }
360 case WM_CLOSE:
361 {
362 EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
363 return TRUE;
364 }
365 }
366
367 return FALSE;
368 }
369
370 static INT
371 GUILoggedOnSAS(
372 IN OUT PGINA_CONTEXT pgContext,
373 IN DWORD dwSasType)
374 {
375 INT result;
376
377 TRACE("GUILoggedOnSAS()\n");
378
379 if (dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL)
380 {
381 /* Nothing to do for WLX_SAS_TYPE_TIMEOUT ; the dialog will
382 * close itself thanks to the use of WlxDialogBoxParam */
383 return WLX_SAS_ACTION_NONE;
384 }
385
386 pgContext->pWlxFuncs->WlxSwitchDesktopToWinlogon(
387 pgContext->hWlx);
388
389 result = pgContext->pWlxFuncs->WlxDialogBoxParam(
390 pgContext->hWlx,
391 pgContext->hDllInstance,
392 MAKEINTRESOURCEW(IDD_LOGGEDON_DLG),
393 GetDesktopWindow(),
394 LoggedOnWindowProc,
395 (LPARAM)pgContext);
396
397 if (result < WLX_SAS_ACTION_LOGON ||
398 result > WLX_SAS_ACTION_SWITCH_CONSOLE)
399 {
400 result = WLX_SAS_ACTION_NONE;
401 }
402
403 if (result == WLX_SAS_ACTION_NONE)
404 {
405 pgContext->pWlxFuncs->WlxSwitchDesktopToUser(
406 pgContext->hWlx);
407 }
408
409 return result;
410 }
411
412 static INT_PTR CALLBACK
413 LoggedOutWindowProc(
414 IN HWND hwndDlg,
415 IN UINT uMsg,
416 IN WPARAM wParam,
417 IN LPARAM lParam)
418 {
419 PGINA_CONTEXT pgContext;
420
421 pgContext = (PGINA_CONTEXT)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
422
423 switch (uMsg)
424 {
425 case WM_INITDIALOG:
426 {
427 /* FIXME: take care of DontDisplayLastUserName, NoDomainUI, ShutdownWithoutLogon */
428 pgContext = (PGINA_CONTEXT)lParam;
429 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)pgContext);
430
431 if (pgContext->bDisableCAD == TRUE)
432 EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
433
434 SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME));
435
436 pgContext->hBitmap = LoadImage(hDllInstance, MAKEINTRESOURCE(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
437 return TRUE;
438 }
439 case WM_PAINT:
440 {
441 PAINTSTRUCT ps;
442 HDC hdc;
443 if (pgContext->hBitmap)
444 {
445 hdc = BeginPaint(hwndDlg, &ps);
446 DrawStateW(hdc, NULL, NULL, (LPARAM)pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
447 EndPaint(hwndDlg, &ps);
448 }
449 return TRUE;
450 }
451 case WM_DESTROY:
452 {
453 DeleteObject(pgContext->hBitmap);
454 return TRUE;
455 }
456 case WM_COMMAND:
457 {
458 switch (LOWORD(wParam))
459 {
460 case IDOK:
461 {
462 LPWSTR UserName = NULL, Password = NULL;
463 INT result = WLX_SAS_ACTION_NONE;
464
465 if (GetTextboxText(hwndDlg, IDC_USERNAME, &UserName) && *UserName == '\0')
466 break;
467 if (GetTextboxText(hwndDlg, IDC_PASSWORD, &Password) &&
468 DoLoginTasks(pgContext, UserName, NULL, Password))
469 {
470 result = WLX_SAS_ACTION_LOGON;
471 }
472 HeapFree(GetProcessHeap(), 0, UserName);
473 HeapFree(GetProcessHeap(), 0, Password);
474 EndDialog(hwndDlg, result);
475 return TRUE;
476 }
477 case IDCANCEL:
478 {
479 EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
480 return TRUE;
481 }
482 case IDC_SHUTDOWN:
483 {
484 EndDialog(hwndDlg, WLX_SAS_ACTION_SHUTDOWN);
485 return TRUE;
486 }
487 }
488 break;
489 }
490 }
491
492 return FALSE;
493 }
494
495 static INT
496 GUILoggedOutSAS(
497 IN OUT PGINA_CONTEXT pgContext)
498 {
499 int result;
500
501 TRACE("GUILoggedOutSAS()\n");
502
503 result = pgContext->pWlxFuncs->WlxDialogBoxParam(
504 pgContext->hWlx,
505 pgContext->hDllInstance,
506 MAKEINTRESOURCEW(IDD_LOGGEDOUT_DLG),
507 GetDesktopWindow(),
508 LoggedOutWindowProc,
509 (LPARAM)pgContext);
510 if (result >= WLX_SAS_ACTION_LOGON &&
511 result <= WLX_SAS_ACTION_SWITCH_CONSOLE)
512 {
513 WARN("WlxLoggedOutSAS() returns 0x%x\n", result);
514 return result;
515 }
516
517 WARN("WlxDialogBoxParam() failed (0x%x)\n", result);
518 return WLX_SAS_ACTION_NONE;
519 }
520
521 static INT
522 GUILockedSAS(
523 IN OUT PGINA_CONTEXT pgContext)
524 {
525 TRACE("GUILockedSAS()\n");
526
527 UNREFERENCED_PARAMETER(pgContext);
528
529 UNIMPLEMENTED;
530 return WLX_SAS_ACTION_UNLOCK_WKSTA;
531 }
532
533
534 static VOID
535 OnInitLockedDlg(HWND hwnd,
536 PGINA_CONTEXT pgContext)
537 {
538 WCHAR Buffer1[256];
539 WCHAR Buffer2[256];
540 WCHAR Buffer3[512];
541
542 LoadStringW(pgContext->hDllInstance, IDS_LOCKMSG, Buffer1, 256);
543
544 wsprintfW(Buffer2, L"%s\\%s", pgContext->Domain, pgContext->UserName);
545 wsprintfW(Buffer3, Buffer1, Buffer2);
546
547 SetDlgItemTextW(hwnd, IDC_LOCKMSG, Buffer3);
548 }
549
550
551 static INT_PTR CALLBACK
552 LockedWindowProc(
553 IN HWND hwndDlg,
554 IN UINT uMsg,
555 IN WPARAM wParam,
556 IN LPARAM lParam)
557 {
558 PGINA_CONTEXT pgContext;
559
560 pgContext = (PGINA_CONTEXT)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
561
562 switch (uMsg)
563 {
564 case WM_INITDIALOG:
565 {
566 pgContext = (PGINA_CONTEXT)lParam;
567 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)pgContext);
568
569 pgContext->hBitmap = LoadImage(hDllInstance, MAKEINTRESOURCE(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
570 OnInitLockedDlg(hwndDlg, pgContext);
571 return TRUE;
572 }
573 case WM_PAINT:
574 {
575 PAINTSTRUCT ps;
576 HDC hdc;
577 if (pgContext->hBitmap)
578 {
579 hdc = BeginPaint(hwndDlg, &ps);
580 DrawStateW(hdc, NULL, NULL, (LPARAM)pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
581 EndPaint(hwndDlg, &ps);
582 }
583 return TRUE;
584 }
585 case WM_DESTROY:
586 {
587 DeleteObject(pgContext->hBitmap);
588 return TRUE;
589 }
590 }
591
592 return FALSE;
593 }
594
595
596 static VOID
597 GUIDisplayLockedNotice(
598 IN OUT PGINA_CONTEXT pgContext)
599 {
600 TRACE("GUIdisplayLockedNotice()\n");
601
602 pgContext->pWlxFuncs->WlxDialogBoxParam(
603 pgContext->hWlx,
604 pgContext->hDllInstance,
605 MAKEINTRESOURCEW(IDD_LOCKED_DLG),
606 GetDesktopWindow(),
607 LockedWindowProc,
608 (LPARAM)pgContext);
609 }
610
611 GINA_UI GinaGraphicalUI = {
612 GUIInitialize,
613 GUIDisplayStatusMessage,
614 GUIRemoveStatusMessage,
615 GUIDisplaySASNotice,
616 GUILoggedOnSAS,
617 GUILoggedOutSAS,
618 GUILockedSAS,
619 GUIDisplayLockedNotice,
620 };