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