#include "winlogon.h"
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(winlogon);
+#include <ndk/cmfuncs.h>
/* GLOBALS ******************************************************************/
/* FUNCTIONS *****************************************************************/
-static BOOL
+static
+BOOL
StartServicesManager(VOID)
{
- STARTUPINFOW StartupInfo;
- PROCESS_INFORMATION ProcessInformation;
- LPCWSTR ServiceString = L"services.exe";
- BOOL res;
-
- /* Start the service control manager (services.exe) */
- ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
- StartupInfo.cb = sizeof(StartupInfo);
- StartupInfo.lpReserved = NULL;
- StartupInfo.lpDesktop = NULL;
- StartupInfo.lpTitle = NULL;
- StartupInfo.dwFlags = 0;
- StartupInfo.cbReserved2 = 0;
- StartupInfo.lpReserved2 = 0;
-
- TRACE("WL: Creating new process - %S\n", ServiceString);
-
- res = CreateProcessW(
- ServiceString,
- NULL,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &StartupInfo,
- &ProcessInformation);
- if (!res)
- {
- ERR("WL: Failed to execute services (error %lu)\n", GetLastError());
- return FALSE;
- }
-
- TRACE("WL: Created new process - %S\n", ServiceString);
-
- CloseHandle(ProcessInformation.hThread);
- CloseHandle(ProcessInformation.hProcess);
-
- TRACE("WL: StartServicesManager() done.\n");
-
- return TRUE;
+ STARTUPINFOW StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ LPCWSTR ServiceString = L"services.exe";
+ BOOL res;
+
+ /* Start the service control manager (services.exe) */
+ ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
+ StartupInfo.cb = sizeof(StartupInfo);
+ StartupInfo.lpReserved = NULL;
+ StartupInfo.lpDesktop = NULL;
+ StartupInfo.lpTitle = NULL;
+ StartupInfo.dwFlags = 0;
+ StartupInfo.cbReserved2 = 0;
+ StartupInfo.lpReserved2 = 0;
+
+ TRACE("WL: Creating new process - %S\n", ServiceString);
+
+ res = CreateProcessW(ServiceString,
+ NULL,
+ NULL,
+ NULL,
+ FALSE,
+ DETACHED_PROCESS,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation);
+ if (!res)
+ {
+ ERR("WL: Failed to execute services (error %lu)\n", GetLastError());
+ return FALSE;
+ }
+
+ TRACE("WL: Created new process - %S\n", ServiceString);
+
+ CloseHandle(ProcessInformation.hThread);
+ CloseHandle(ProcessInformation.hProcess);
+
+ TRACE("WL: StartServicesManager() done.\n");
+
+ return TRUE;
}
-static BOOL
+static
+BOOL
StartLsass(VOID)
{
- STARTUPINFOW StartupInfo;
- PROCESS_INFORMATION ProcessInformation;
- LPCWSTR ServiceString = L"lsass.exe";
- BOOL res;
-
- /* Start the local security authority subsystem (lsass.exe) */
- ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
- StartupInfo.cb = sizeof(StartupInfo);
- StartupInfo.lpReserved = NULL;
- StartupInfo.lpDesktop = NULL;
- StartupInfo.lpTitle = NULL;
- StartupInfo.dwFlags = 0;
- StartupInfo.cbReserved2 = 0;
- StartupInfo.lpReserved2 = 0;
-
- TRACE("WL: Creating new process - %S\n", ServiceString);
-
- res = CreateProcessW(
- ServiceString,
- NULL,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &StartupInfo,
- &ProcessInformation);
-
- TRACE("WL: Created new process - %S\n", ServiceString);
-
- CloseHandle(ProcessInformation.hThread);
- CloseHandle(ProcessInformation.hProcess);
-
- return res;
+ STARTUPINFOW StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ LPCWSTR ServiceString = L"lsass.exe";
+ BOOL res;
+
+ /* Start the local security authority subsystem (lsass.exe) */
+ ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
+ StartupInfo.cb = sizeof(StartupInfo);
+ StartupInfo.lpReserved = NULL;
+ StartupInfo.lpDesktop = NULL;
+ StartupInfo.lpTitle = NULL;
+ StartupInfo.dwFlags = 0;
+ StartupInfo.cbReserved2 = 0;
+ StartupInfo.lpReserved2 = 0;
+
+ TRACE("WL: Creating new process - %S\n", ServiceString);
+
+ res = CreateProcessW(ServiceString,
+ NULL,
+ NULL,
+ NULL,
+ FALSE,
+ DETACHED_PROCESS,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation);
+
+ TRACE("WL: Created new process - %S\n", ServiceString);
+
+ CloseHandle(ProcessInformation.hThread);
+ CloseHandle(ProcessInformation.hProcess);
+
+ return res;
}
-static VOID
+static
+VOID
WaitForLsass(VOID)
{
HANDLE hEvent;
if (hEvent == NULL)
{
dwError = GetLastError();
- TRACE("WL: Failed to create the notication event (Error %lu)\n", dwError);
+ TRACE("WL: Failed to create the notification event (Error %lu)\n", dwError);
if (dwError == ERROR_ALREADY_EXISTS)
{
}
-static BOOL
-InitKeyboardLayouts()
+static
+BOOL
+InitKeyboardLayouts(VOID)
{
WCHAR wszKeyName[12], wszKLID[10];
- DWORD dwSize = sizeof(wszKLID), dwType, i = 1;
+ DWORD dwSize = sizeof(wszKLID), dwType, i = 1;
HKEY hKey;
UINT Flags;
BOOL bRet = FALSE;
/* Open registry key with preloaded layouts */
- if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
- {
- while(TRUE)
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ while (TRUE)
{
/* Read values with integer names only */
swprintf(wszKeyName, L"%d", i++);
/* Close the key now */
RegCloseKey(hKey);
- }
- else
- WARN("RegOpenKeyExW(Keyboard Layout\\Preload) failed!\n");
+ }
+ else
+ WARN("RegOpenKeyExW(Keyboard Layout\\Preload) failed!\n");
if (!bRet)
{
BOOL
DisplayStatusMessage(
- IN PWLSESSION Session,
- IN HDESK hDesktop,
- IN UINT ResourceId)
+ IN PWLSESSION Session,
+ IN HDESK hDesktop,
+ IN UINT ResourceId)
{
- WCHAR StatusMsg[MAX_PATH];
+ WCHAR StatusMsg[MAX_PATH];
- if (Session->Gina.Version < WLX_VERSION_1_3)
- return TRUE;
+ if (Session->Gina.Version < WLX_VERSION_1_3)
+ return TRUE;
- if (Session->SuppressStatus)
- return TRUE;
+ if (Session->SuppressStatus)
+ return TRUE;
- if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
- return FALSE;
+ if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
+ return FALSE;
- return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
+ return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
}
+
BOOL
RemoveStatusMessage(
- IN PWLSESSION Session)
+ IN PWLSESSION Session)
{
- if (Session->Gina.Version < WLX_VERSION_1_3)
- return TRUE;
+ if (Session->Gina.Version < WLX_VERSION_1_3)
+ return TRUE;
- return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
+ return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
}
-static INT_PTR CALLBACK
+
+static
+INT_PTR
+CALLBACK
GinaLoadFailedWindowProc(
- IN HWND hwndDlg,
- IN UINT uMsg,
- IN WPARAM wParam,
- IN LPARAM lParam)
+ IN HWND hwndDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam)
{
- switch (uMsg)
- {
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDOK:
- EndDialog(hwndDlg, IDOK);
- return TRUE;
- }
- break;
- }
- case WM_INITDIALOG:
- {
- int len;
- WCHAR templateText[MAX_PATH], text[MAX_PATH];
-
- len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
- if (len)
- {
- wsprintfW(text, templateText, (LPWSTR)lParam);
- SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
- }
- SetFocus(GetDlgItem(hwndDlg, IDOK));
- return TRUE;
- }
- case WM_CLOSE:
- {
- EndDialog(hwndDlg, IDCANCEL);
- return TRUE;
- }
- }
-
- return FALSE;
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ EndDialog(hwndDlg, IDOK);
+ return TRUE;
+ }
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ int len;
+ WCHAR templateText[MAX_PATH], text[MAX_PATH];
+
+ len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
+ if (len)
+ {
+ wsprintfW(text, templateText, (LPWSTR)lParam);
+ SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
+ }
+
+ SetFocus(GetDlgItem(hwndDlg, IDOK));
+ return TRUE;
+ }
+
+ case WM_CLOSE:
+ {
+ EndDialog(hwndDlg, IDCANCEL);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
-int WINAPI
+
+int
+WINAPI
WinMain(
- IN HINSTANCE hInstance,
- IN HINSTANCE hPrevInstance,
- IN LPSTR lpCmdLine,
- IN int nShowCmd)
+ IN HINSTANCE hInstance,
+ IN HINSTANCE hPrevInstance,
+ IN LPSTR lpCmdLine,
+ IN int nShowCmd)
{
#if 0
- LSA_STRING ProcessName, PackageName;
- HANDLE LsaHandle;
- LSA_OPERATIONAL_MODE Mode;
- BOOLEAN Old;
- ULONG AuthenticationPackage;
- NTSTATUS Status;
+ LSA_STRING ProcessName, PackageName;
+ HANDLE LsaHandle;
+ LSA_OPERATIONAL_MODE Mode;
+ BOOLEAN Old;
+ ULONG AuthenticationPackage;
+ NTSTATUS Status;
#endif
- ULONG HardErrorResponse;
- MSG Msg;
-
- UNREFERENCED_PARAMETER(hPrevInstance);
- UNREFERENCED_PARAMETER(lpCmdLine);
- UNREFERENCED_PARAMETER(nShowCmd);
-
- hAppInstance = hInstance;
-
- if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
- {
- ERR("WL: Could not register logon process\n");
- NtShutdownSystem(ShutdownNoReboot);
- ExitProcess(0);
- }
-
- WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
- if (!WLSession)
- {
- ERR("WL: Could not allocate memory for winlogon instance\n");
- NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
- ExitProcess(1);
- }
- ZeroMemory(WLSession, sizeof(WLSESSION));
- WLSession->DialogTimeout = 120; /* 2 minutes */
-
- if (!CreateWindowStationAndDesktops(WLSession))
- {
- ERR("WL: Could not create window station and desktops\n");
- NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
- ExitProcess(1);
- }
- LockWorkstation(WLSession);
+ ULONG HardErrorResponse;
+ MSG Msg;
+
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+ UNREFERENCED_PARAMETER(nShowCmd);
+
+ hAppInstance = hInstance;
+
+ /* Make us critical */
+ RtlSetProcessIsCritical(TRUE, NULL, FALSE);
+ RtlSetThreadIsCritical(TRUE, NULL, FALSE);
+
+ if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
+ {
+ ERR("WL: Could not register logon process\n");
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
+ }
+
+ WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
+ if (!WLSession)
+ {
+ ERR("WL: Could not allocate memory for winlogon instance\n");
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
+ }
+
+ ZeroMemory(WLSession, sizeof(WLSESSION));
+ WLSession->DialogTimeout = 120; /* 2 minutes */
+
+ /* Initialize the dialog tracking list */
+ InitDialogListHead();
+
+ if (!CreateWindowStationAndDesktops(WLSession))
+ {
+ ERR("WL: Could not create window station and desktops\n");
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
+ }
+
+ LockWorkstation(WLSession);
/* Load default keyboard layouts */
if (!InitKeyboardLayouts())
{
ERR("WL: Could not preload keyboard layouts\n");
- NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
- ExitProcess(1);
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
}
- if (!StartServicesManager())
- {
- ERR("WL: Could not start services.exe\n");
- NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
- ExitProcess(1);
- }
+ if (!StartRpcServer())
+ {
+ ERR("WL: Could not start the RPC server\n");
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
+ }
- if (!StartLsass())
- {
- ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
- NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, OptionOk, &HardErrorResponse);
- ExitProcess(1);
- }
+ if (!StartServicesManager())
+ {
+ ERR("WL: Could not start services.exe\n");
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
+ }
- /* Load and initialize gina */
- if (!GinaInit(WLSession))
- {
- ERR("WL: Failed to initialize Gina\n");
- DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"");
- HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
- ExitProcess(1);
- }
+ if (!StartLsass())
+ {
+ ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
+ NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
+ ExitProcess(1);
+ }
- DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
+ /* Wait for the LSA server */
+ WaitForLsass();
+ /* Init Notifications */
+ InitNotifications();
- /* Wait for the LSA server */
- WaitForLsass();
+ /* Load and initialize gina */
+ if (!GinaInit(WLSession))
+ {
+ ERR("WL: Failed to initialize Gina\n");
+ // FIXME: Retrieve the real name of the GINA DLL we were trying to load.
+ // It is known only inside the GinaInit function...
+ DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"msgina.dll");
+ HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
+ ExitProcess(1);
+ }
+
+ DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
#if 0
- /* Connect to NetLogon service (lsass.exe) */
- /* Real winlogon uses "Winlogon" */
- RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
- Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
- if (Status == STATUS_PORT_CONNECTION_REFUSED)
- {
- /* Add the 'SeTcbPrivilege' privilege and try again */
- Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
- if (!NT_SUCCESS(Status))
- {
- ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
- return 1;
- }
- Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
- }
- if (!NT_SUCCESS(Status))
- {
- ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
- return 1;
- }
-
- RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
- Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
- if (!NT_SUCCESS(Status))
- {
- ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
- LsaDeregisterLogonProcess(LsaHandle);
- return 1;
- }
+ /* Connect to NetLogon service (lsass.exe) */
+ /* Real winlogon uses "Winlogon" */
+ RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
+ Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
+ if (Status == STATUS_PORT_CONNECTION_REFUSED)
+ {
+ /* Add the 'SeTcbPrivilege' privilege and try again */
+ Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
+ return 1;
+ }
+
+ Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
+ return 1;
+ }
+
+ RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
+ Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
+ LsaDeregisterLogonProcess(LsaHandle);
+ return 1;
+ }
#endif
- /* Create a hidden window to get SAS notifications */
- if (!InitializeSAS(WLSession))
- {
- ERR("WL: Failed to initialize SAS\n");
- ExitProcess(2);
- }
-
- //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
- //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
-
- /* Display logged out screen */
- WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
- RemoveStatusMessage(WLSession);
-
- /* Check for pending setup */
- if (GetSetupType() != 0)
- {
- TRACE("WL: Setup mode detected\n");
-
- /* Run setup and reboot when done */
- SwitchDesktop(WLSession->ApplicationDesktop);
- RunSetup();
- }
- else
- PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
-
- /* Tell kernel that CurrentControlSet is good (needed
- * to support Last good known configuration boot) */
- NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
-
- /* Message loop for the SAS window */
- while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
- {
- TranslateMessage(&Msg);
- DispatchMessageW(&Msg);
- }
-
- /* We never go there */
-
- return 0;
+ CallNotificationDlls(WLSession, StartupHandler);
+
+ /* Create a hidden window to get SAS notifications */
+ if (!InitializeSAS(WLSession))
+ {
+ ERR("WL: Failed to initialize SAS\n");
+ ExitProcess(2);
+ }
+
+ // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
+ // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
+
+ /* Display logged out screen */
+ WLSession->LogonState = STATE_INIT;
+ RemoveStatusMessage(WLSession);
+
+ /* Check for pending setup */
+ if (GetSetupType() != 0)
+ {
+ /* Run setup and reboot when done */
+ TRACE("WL: Setup mode detected\n");
+ RunSetup();
+ }
+ else
+ {
+ PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
+ }
+
+ (void)LoadLibraryW(L"sfc_os.dll");
+
+ /* Tell kernel that CurrentControlSet is good (needed
+ * to support Last good known configuration boot) */
+ NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
+
+ /* Message loop for the SAS window */
+ while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
+ {
+ TranslateMessage(&Msg);
+ DispatchMessageW(&Msg);
+ }
+
+ CleanupNotifications();
+
+ /* We never go there */
+
+ return 0;
}