[WRITE/SETUP/RUNONCE/SERVICES/MMSYS/MSGINA/SYSSETUP]
[reactos.git] / reactos / dll / win32 / msgina / msgina.c
1 /*
2 * ReactOS GINA
3 * Copyright (C) 2003-2004, 2006 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * PROJECT: ReactOS msgina.dll
21 * FILE: dll/win32/msgina/msgina.c
22 * PURPOSE: ReactOS Logon GINA DLL
23 * PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
24 * Hervé Poussineau (hpoussin@reactos.org)
25 */
26
27 #include "msgina.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(msgina);
30
31 HINSTANCE hDllInstance;
32
33 extern GINA_UI GinaGraphicalUI;
34 extern GINA_UI GinaTextUI;
35 static PGINA_UI pGinaUI;
36
37 /*
38 * @implemented
39 */
40 BOOL WINAPI
41 WlxNegotiate(
42 IN DWORD dwWinlogonVersion,
43 OUT PDWORD pdwDllVersion)
44 {
45 TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion, pdwDllVersion);
46
47 if(!pdwDllVersion || (dwWinlogonVersion < WLX_VERSION_1_3))
48 return FALSE;
49
50 *pdwDllVersion = WLX_VERSION_1_3;
51
52 return TRUE;
53 }
54
55 static LONG
56 ReadRegSzKey(
57 IN HKEY hKey,
58 IN LPCWSTR pszKey,
59 OUT LPWSTR* pValue)
60 {
61 LONG rc;
62 DWORD dwType;
63 DWORD cbData = 0;
64 LPWSTR Value;
65
66 if (!pValue)
67 return ERROR_INVALID_PARAMETER;
68
69 *pValue = NULL;
70 rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
71 if (rc != ERROR_SUCCESS)
72 return rc;
73 if (dwType != REG_SZ)
74 return ERROR_FILE_NOT_FOUND;
75 Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
76 if (!Value)
77 return ERROR_NOT_ENOUGH_MEMORY;
78 rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
79 if (rc != ERROR_SUCCESS)
80 {
81 HeapFree(GetProcessHeap(), 0, Value);
82 return rc;
83 }
84 /* NULL-terminate the string */
85 Value[cbData / sizeof(WCHAR)] = '\0';
86
87 *pValue = Value;
88 return ERROR_SUCCESS;
89 }
90
91 static VOID
92 ChooseGinaUI(VOID)
93 {
94 HKEY ControlKey = NULL;
95 LPWSTR SystemStartOptions = NULL;
96 LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
97 BOOL ConsoleBoot = FALSE;
98 LONG rc;
99
100 rc = RegOpenKeyExW(
101 HKEY_LOCAL_MACHINE,
102 L"SYSTEM\\CurrentControlSet\\Control",
103 0,
104 KEY_QUERY_VALUE,
105 &ControlKey);
106
107 rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
108 if (rc != ERROR_SUCCESS)
109 goto cleanup;
110
111 /* Check for CONSOLE switch in SystemStartOptions */
112 CurrentOption = SystemStartOptions;
113 while (CurrentOption)
114 {
115 NextOption = wcschr(CurrentOption, L' ');
116 if (NextOption)
117 *NextOption = L'\0';
118 if (wcsicmp(CurrentOption, L"CONSOLE") == 0)
119 {
120 TRACE("Found %S. Switching to console boot\n", CurrentOption);
121 ConsoleBoot = TRUE;
122 goto cleanup;
123 }
124 CurrentOption = NextOption ? NextOption + 1 : NULL;
125 }
126
127 cleanup:
128 if (ConsoleBoot)
129 pGinaUI = &GinaTextUI;
130 else
131 pGinaUI = &GinaGraphicalUI;
132
133 if (ControlKey != NULL)
134 RegCloseKey(ControlKey);
135 HeapFree(GetProcessHeap(), 0, SystemStartOptions);
136 }
137
138 /*
139 * @implemented
140 */
141 BOOL WINAPI
142 WlxInitialize(
143 LPWSTR lpWinsta,
144 HANDLE hWlx,
145 PVOID pvReserved,
146 PVOID pWinlogonFunctions,
147 PVOID *pWlxContext)
148 {
149 PGINA_CONTEXT pgContext;
150
151 UNREFERENCED_PARAMETER(pvReserved);
152
153 pgContext = (PGINA_CONTEXT)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GINA_CONTEXT));
154 if(!pgContext)
155 {
156 WARN("LocalAlloc() failed\n");
157 return FALSE;
158 }
159
160 /* Return the context to winlogon */
161 *pWlxContext = (PVOID)pgContext;
162 pgContext->hDllInstance = hDllInstance;
163
164 /* Save pointer to dispatch table */
165 pgContext->pWlxFuncs = (PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions;
166
167 /* Save the winlogon handle used to call the dispatch functions */
168 pgContext->hWlx = hWlx;
169
170 /* Save window station */
171 pgContext->station = lpWinsta;
172
173 /* Clear status window handle */
174 pgContext->hStatusWindow = 0;
175
176 /* Notify winlogon that we will use the default SAS */
177 pgContext->pWlxFuncs->WlxUseCtrlAltDel(hWlx);
178
179 /* Locates the authentification package */
180 //LsaRegisterLogonProcess(...);
181
182 /* Check autologon settings the first time */
183 pgContext->AutoLogonState = AUTOLOGON_CHECK_REGISTRY;
184
185 ChooseGinaUI();
186 return pGinaUI->Initialize(pgContext);
187 }
188
189 /*
190 * @implemented
191 */
192 BOOL WINAPI
193 WlxStartApplication(
194 PVOID pWlxContext,
195 PWSTR pszDesktopName,
196 PVOID pEnvironment,
197 PWSTR pszCmdLine)
198 {
199 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
200 STARTUPINFOW StartupInfo;
201 PROCESS_INFORMATION ProcessInformation;
202 WCHAR CurrentDirectory[MAX_PATH];
203 HANDLE hAppToken;
204 UINT len;
205 BOOL ret;
206
207 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
208 if (len == 0 || len > MAX_PATH)
209 {
210 WARN("GetWindowsDirectoryW() failed\n");
211 return FALSE;
212 }
213
214 ret = DuplicateTokenEx(pgContext->UserToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hAppToken);
215 if (!ret)
216 {
217 WARN("DuplicateTokenEx() failed with error %lu\n", GetLastError());
218 return FALSE;
219 }
220
221 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
222 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
223 StartupInfo.cb = sizeof(StartupInfo);
224 StartupInfo.lpTitle = pszCmdLine;
225 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
226 StartupInfo.wShowWindow = SW_SHOW;
227 StartupInfo.lpDesktop = pszDesktopName;
228
229 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
230 if (len == 0 || len > MAX_PATH)
231 {
232 WARN("GetWindowsDirectoryW() failed\n");
233 return FALSE;
234 }
235 ret = CreateProcessAsUserW(
236 hAppToken,
237 pszCmdLine,
238 NULL,
239 NULL,
240 NULL,
241 FALSE,
242 CREATE_UNICODE_ENVIRONMENT,
243 pEnvironment,
244 CurrentDirectory,
245 &StartupInfo,
246 &ProcessInformation);
247 CloseHandle(ProcessInformation.hProcess);
248 CloseHandle(ProcessInformation.hThread);
249 CloseHandle(hAppToken);
250 if (!ret)
251 WARN("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
252 return ret;
253 }
254
255 /*
256 * @implemented
257 */
258 BOOL WINAPI
259 WlxActivateUserShell(
260 PVOID pWlxContext,
261 PWSTR pszDesktopName,
262 PWSTR pszMprLogonScript,
263 PVOID pEnvironment)
264 {
265 HKEY hKey;
266 DWORD BufSize, ValueType;
267 WCHAR pszUserInitApp[MAX_PATH + 1];
268 WCHAR pszExpUserInitApp[MAX_PATH];
269 DWORD len;
270 LONG rc;
271
272 TRACE("WlxActivateUserShell()\n");
273
274 UNREFERENCED_PARAMETER(pszMprLogonScript);
275
276 /* Get the path of userinit */
277 rc = RegOpenKeyExW(
278 HKEY_LOCAL_MACHINE,
279 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
280 0,
281 KEY_QUERY_VALUE,
282 &hKey);
283 if (rc != ERROR_SUCCESS)
284 {
285 WARN("RegOpenKeyExW() failed with error %lu\n", rc);
286 return FALSE;
287 }
288
289 /* Query userinit application */
290 BufSize = sizeof(pszUserInitApp) - sizeof(UNICODE_NULL);
291 rc = RegQueryValueExW(
292 hKey,
293 L"Userinit",
294 NULL,
295 &ValueType,
296 (LPBYTE)pszUserInitApp,
297 &BufSize);
298 RegCloseKey(hKey);
299 if (rc != ERROR_SUCCESS || (ValueType != REG_SZ && ValueType != REG_EXPAND_SZ))
300 {
301 WARN("RegQueryValueExW() failed with error %lu\n", rc);
302 return FALSE;
303 }
304 pszUserInitApp[MAX_PATH] = UNICODE_NULL;
305
306 len = ExpandEnvironmentStringsW(pszUserInitApp, pszExpUserInitApp, MAX_PATH);
307 if (len > MAX_PATH)
308 {
309 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len);
310 return FALSE;
311 }
312
313 /* Start userinit app */
314 return WlxStartApplication(pWlxContext, pszDesktopName, pEnvironment, pszExpUserInitApp);
315 }
316
317 /*
318 * @implemented
319 */
320 int WINAPI
321 WlxLoggedOnSAS(
322 PVOID pWlxContext,
323 DWORD dwSasType,
324 PVOID pReserved)
325 {
326 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
327 INT SasAction = WLX_SAS_ACTION_NONE;
328
329 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType);
330
331 UNREFERENCED_PARAMETER(pReserved);
332
333 switch (dwSasType)
334 {
335 case WLX_SAS_TYPE_CTRL_ALT_DEL:
336 case WLX_SAS_TYPE_TIMEOUT:
337 {
338 SasAction = pGinaUI->LoggedOnSAS(pgContext, dwSasType);
339 break;
340 }
341 case WLX_SAS_TYPE_SC_INSERT:
342 {
343 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
344 break;
345 }
346 case WLX_SAS_TYPE_SC_REMOVE:
347 {
348 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
349 break;
350 }
351 default:
352 {
353 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType);
354 break;
355 }
356 }
357
358 return SasAction;
359 }
360
361 /*
362 * @implemented
363 */
364 BOOL WINAPI
365 WlxDisplayStatusMessage(
366 IN PVOID pWlxContext,
367 IN HDESK hDesktop,
368 IN DWORD dwOptions,
369 IN PWSTR pTitle,
370 IN PWSTR pMessage)
371 {
372 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
373
374 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage);
375
376 return pGinaUI->DisplayStatusMessage(pgContext, hDesktop, dwOptions, pTitle, pMessage);
377 }
378
379 /*
380 * @implemented
381 */
382 BOOL WINAPI
383 WlxRemoveStatusMessage(
384 IN PVOID pWlxContext)
385 {
386 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
387
388 TRACE("WlxRemoveStatusMessage()\n");
389
390 return pGinaUI->RemoveStatusMessage(pgContext);
391 }
392
393 static PWSTR
394 DuplicationString(PWSTR Str)
395 {
396 DWORD cb;
397 PWSTR NewStr;
398
399 if (Str == NULL) return NULL;
400
401 cb = (wcslen(Str) + 1) * sizeof(WCHAR);
402 if ((NewStr = LocalAlloc(LMEM_FIXED, cb)))
403 memcpy(NewStr, Str, cb);
404 return NewStr;
405 }
406
407 BOOL
408 DoLoginTasks(
409 IN OUT PGINA_CONTEXT pgContext,
410 IN PWSTR UserName,
411 IN PWSTR Domain,
412 IN PWSTR Password)
413 {
414 LPWSTR ProfilePath = NULL;
415 LPWSTR lpEnvironment = NULL;
416 TOKEN_STATISTICS Stats;
417 PWLX_PROFILE_V2_0 pProfile = NULL;
418 DWORD cbStats, cbSize;
419 BOOL bResult;
420
421 if (!LogonUserW(UserName, Domain, Password,
422 LOGON32_LOGON_INTERACTIVE,
423 LOGON32_PROVIDER_DEFAULT,
424 &pgContext->UserToken))
425 {
426 WARN("LogonUserW() failed\n");
427 goto cleanup;
428 }
429
430 /* Get profile path */
431 cbSize = 0;
432 bResult = GetProfilesDirectoryW(NULL, &cbSize);
433 if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
434 {
435 ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR));
436 if (!ProfilePath)
437 {
438 WARN("HeapAlloc() failed\n");
439 goto cleanup;
440 }
441 bResult = GetProfilesDirectoryW(ProfilePath, &cbSize);
442 }
443 if (!bResult)
444 {
445 WARN("GetUserProfileDirectoryW() failed\n");
446 goto cleanup;
447 }
448
449 /* Allocate memory for profile */
450 pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0));
451 if (!pProfile)
452 {
453 WARN("HeapAlloc() failed\n");
454 goto cleanup;
455 }
456 pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
457 pProfile->pszProfile = ProfilePath;
458
459 lpEnvironment = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32 * sizeof(WCHAR));
460 if (!lpEnvironment)
461 {
462 WARN("HeapAlloc() failed\n");
463 goto cleanup;
464 }
465 wcscpy(lpEnvironment, L"LOGONSERVER=\\\\Test");
466
467 pProfile->pszEnvironment = lpEnvironment;
468
469 if (!GetTokenInformation(pgContext->UserToken,
470 TokenStatistics,
471 (PVOID)&Stats,
472 sizeof(TOKEN_STATISTICS),
473 &cbStats))
474 {
475 WARN("Couldn't get Authentication id from user token!\n");
476 goto cleanup;
477 }
478
479 *pgContext->pAuthenticationId = Stats.AuthenticationId;
480 pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName);
481 pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain);
482 pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password);
483 pgContext->pMprNotifyInfo->pszOldPassword = NULL;
484 *pgContext->pdwOptions = 0;
485 *pgContext->pProfile = pProfile;
486 return TRUE;
487
488 cleanup:
489 if (pProfile)
490 {
491 HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment);
492 }
493 HeapFree(GetProcessHeap(), 0, pProfile);
494 HeapFree(GetProcessHeap(), 0, ProfilePath);
495 return FALSE;
496 }
497
498 static BOOL
499 DoAutoLogon(
500 IN PGINA_CONTEXT pgContext)
501 {
502 HKEY WinLogonKey = NULL;
503 LPWSTR AutoLogon = NULL;
504 LPWSTR AutoCount = NULL;
505 LPWSTR IgnoreShiftOverride = NULL;
506 LPWSTR UserName = NULL;
507 LPWSTR DomainName = NULL;
508 LPWSTR Password = NULL;
509 BOOL result = FALSE;
510 LONG rc;
511
512 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
513 pgContext->AutoLogonState);
514
515 if (pgContext->AutoLogonState == AUTOLOGON_DISABLED)
516 return FALSE;
517
518 rc = RegOpenKeyExW(
519 HKEY_LOCAL_MACHINE,
520 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
521 0,
522 KEY_QUERY_VALUE,
523 &WinLogonKey);
524 if (rc != ERROR_SUCCESS)
525 goto cleanup;
526
527 if (pgContext->AutoLogonState == AUTOLOGON_CHECK_REGISTRY)
528 {
529 /* Set it by default to disabled, we might reenable it again later */
530 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
531
532 rc = ReadRegSzKey(WinLogonKey, L"AutoAdminLogon", &AutoLogon);
533 if (rc != ERROR_SUCCESS)
534 goto cleanup;
535 if (wcscmp(AutoLogon, L"1") != 0)
536 goto cleanup;
537
538 rc = ReadRegSzKey(WinLogonKey, L"AutoLogonCount", &AutoCount);
539 if (rc == ERROR_SUCCESS && wcscmp(AutoCount, L"0") == 0)
540 goto cleanup;
541 else if (rc != ERROR_FILE_NOT_FOUND)
542 goto cleanup;
543
544 rc = ReadRegSzKey(WinLogonKey, L"IgnoreShiftOverride", &UserName);
545 if (rc == ERROR_SUCCESS)
546 {
547 if (wcscmp(AutoLogon, L"1") != 0 && GetKeyState(VK_SHIFT) < 0)
548 goto cleanup;
549 }
550 else if (GetKeyState(VK_SHIFT) < 0)
551 {
552 /* User pressed SHIFT */
553 goto cleanup;
554 }
555
556 pgContext->AutoLogonState = AUTOLOGON_ONCE;
557 result = TRUE;
558 }
559 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
560 {
561 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
562
563 rc = ReadRegSzKey(WinLogonKey, L"DefaultUserName", &UserName);
564 if (rc != ERROR_SUCCESS)
565 goto cleanup;
566 rc = ReadRegSzKey(WinLogonKey, L"DefaultDomainName", &DomainName);
567 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
568 goto cleanup;
569 rc = ReadRegSzKey(WinLogonKey, L"DefaultPassword", &Password);
570 if (rc != ERROR_SUCCESS)
571 goto cleanup;
572
573 result = DoLoginTasks(pgContext, UserName, DomainName, Password);
574
575 if (result == TRUE)
576 NotifyBootConfigStatus(TRUE);
577 }
578
579 cleanup:
580 if (WinLogonKey != NULL)
581 RegCloseKey(WinLogonKey);
582 HeapFree(GetProcessHeap(), 0, AutoLogon);
583 HeapFree(GetProcessHeap(), 0, AutoCount);
584 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride);
585 HeapFree(GetProcessHeap(), 0, UserName);
586 HeapFree(GetProcessHeap(), 0, DomainName);
587 HeapFree(GetProcessHeap(), 0, Password);
588 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
589 pgContext->AutoLogonState, result);
590 return result;
591 }
592
593 /*
594 * @implemented
595 */
596 VOID WINAPI
597 WlxDisplaySASNotice(
598 IN PVOID pWlxContext)
599 {
600 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
601
602 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
603
604 if (GetSystemMetrics(SM_REMOTESESSION))
605 {
606 /* User is remotely logged on. Don't display a notice */
607 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
608 return;
609 }
610
611 if (DoAutoLogon(pgContext))
612 {
613 /* Don't display the window, we want to do an automatic logon */
614 pgContext->AutoLogonState = AUTOLOGON_ONCE;
615 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
616 return;
617 }
618 else
619 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
620
621 pGinaUI->DisplaySASNotice(pgContext);
622
623 TRACE("WlxDisplaySASNotice() done\n");
624 }
625
626 /*
627 * @implemented
628 */
629 INT WINAPI
630 WlxLoggedOutSAS(
631 IN PVOID pWlxContext,
632 IN DWORD dwSasType,
633 OUT PLUID pAuthenticationId,
634 IN OUT PSID pLogonSid,
635 OUT PDWORD pdwOptions,
636 OUT PHANDLE phToken,
637 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
638 OUT PVOID *pProfile)
639 {
640 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
641 INT res;
642
643 TRACE("WlxLoggedOutSAS()\n");
644
645 UNREFERENCED_PARAMETER(dwSasType);
646 UNREFERENCED_PARAMETER(pLogonSid);
647
648 pgContext->pAuthenticationId = pAuthenticationId;
649 pgContext->pdwOptions = pdwOptions;
650 pgContext->pMprNotifyInfo = pMprNotifyInfo;
651 pgContext->pProfile = pProfile;
652
653 if (0 == GetSystemMetrics(SM_REMOTESESSION) &&
654 DoAutoLogon(pgContext))
655 {
656 /* User is local and registry contains information
657 * to log on him automatically */
658 *phToken = pgContext->UserToken;
659 return WLX_SAS_ACTION_LOGON;
660 }
661
662 res = pGinaUI->LoggedOutSAS(pgContext);
663 *phToken = pgContext->UserToken;
664 return res;
665 }
666
667 /*
668 * @implemented
669 */
670 int WINAPI
671 WlxWkstaLockedSAS(
672 PVOID pWlxContext,
673 DWORD dwSasType)
674 {
675 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
676
677 TRACE("WlxWkstaLockedSAS()\n");
678
679 UNREFERENCED_PARAMETER(dwSasType);
680
681 return pGinaUI->LockedSAS(pgContext);
682 }
683
684 /*
685 * @implemented
686 */
687 BOOL WINAPI
688 WlxIsLogoffOk(
689 PVOID pWlxContext)
690 {
691 TRACE("WlxIsLogoffOk()\n");
692 UNREFERENCED_PARAMETER(pWlxContext);
693 return TRUE;
694 }
695
696 BOOL WINAPI
697 DllMain(
698 IN HINSTANCE hinstDLL,
699 IN DWORD dwReason,
700 IN LPVOID lpvReserved)
701 {
702 UNREFERENCED_PARAMETER(lpvReserved);
703
704 if (dwReason == DLL_PROCESS_ATTACH)
705 hDllInstance = hinstDLL;
706
707 return TRUE;
708 }