Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

969 lines
29 KiB

/****************************** Module Header ******************************\
* Module Name: sysinit.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Winlogon main module
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
BOOLEAN PageFilePopup = FALSE;
TCHAR szMemMan[] =
TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
TCHAR szNoPageFile[] = TEXT("TempPageFile");
HANDLE hSystemProcesses[MAXIMUM_WAIT_OBJECTS];
DWORD cSystemProcesses;
#define DEBUG_COMMAND TEXT("ntsd -d ")
#define DEBUG_COMMAND_NO_WAIT TEXT("ntsd -d -g ")
#define SELECT_DEBUG_COMMAND(x) (x & DEB_DEBUG_NOWAIT ? DEBUG_COMMAND_NO_WAIT : DEBUG_COMMAND)
//
// Bogus #2: InitializeWinreg is defined in regrpc.h, but we can't include
// it in any file that uses RegXxx APIs. So, rather than add yet another
// source file, this is explicitly prototyped here, and any change there has
// to be reflected here.
//
BOOL
InitializeWinreg(void);
//
// Look for autocheck logs, and log them
//
VOID
DealWithAutochkLogs(
VOID
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Handle;
HANDLE DirectoryHandle;
POBJECT_DIRECTORY_INFORMATION DirInfo;
CHAR DirInfoBuffer[ 256 ];
ULONG Context, Length;
BOOLEAN RestartScan;
GLOBALS LocalGlobals;
UNICODE_STRING UnicodeString;
UNICODE_STRING LinkTarget;
UNICODE_STRING LinkTypeName;
UNICODE_STRING LinkTargetPrefix;
WCHAR LinkTargetBuffer[ MAXIMUM_FILENAME_LENGTH ];
WCHAR LogFile[MAX_PATH];
HANDLE LogFileHandle;
DWORD FileSize,BytesRead;
WCHAR *FileBuffer;
DWORD ServerRetryCount;
DWORD rv;
DWORD gle;
UINT OldMode;
ZeroMemory(&LocalGlobals,sizeof(LocalGlobals));
LinkTarget.Buffer = LinkTargetBuffer;
DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer;
RestartScan = TRUE;
RtlInitUnicodeString( &LinkTypeName, L"SymbolicLink" );
RtlInitUnicodeString( &LinkTargetPrefix, L"\\Device\\Harddisk" );
RtlInitUnicodeString( &UnicodeString, L"\\DosDevices" );
InitializeObjectAttributes( &ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenDirectoryObject( &DirectoryHandle,
DIRECTORY_QUERY,
&ObjectAttributes
);
if (!NT_SUCCESS( Status )) {
return;
}
while (TRUE) {
Status = NtQueryDirectoryObject( DirectoryHandle,
(PVOID)DirInfo,
sizeof( DirInfoBuffer ),
TRUE,
RestartScan,
&Context,
&Length
);
if (!NT_SUCCESS( Status )) {
Status = STATUS_SUCCESS;
break;
}
if (RtlEqualUnicodeString( &DirInfo->TypeName, &LinkTypeName, TRUE ) &&
DirInfo->Name.Buffer[(DirInfo->Name.Length>>1)-1] == L':') {
InitializeObjectAttributes( &ObjectAttributes,
&DirInfo->Name,
OBJ_CASE_INSENSITIVE,
DirectoryHandle,
NULL
);
Status = NtOpenSymbolicLinkObject( &Handle,
SYMBOLIC_LINK_QUERY,
&ObjectAttributes
);
if (NT_SUCCESS( Status )) {
LinkTarget.Length = 0;
LinkTarget.MaximumLength = sizeof( LinkTargetBuffer );
Status = NtQuerySymbolicLinkObject( Handle,
&LinkTarget,
NULL
);
NtClose( Handle );
if (NT_SUCCESS( Status ) &&
RtlPrefixUnicodeString( &LinkTargetPrefix, &LinkTarget, TRUE )
) {
CopyMemory(LogFile,DirInfo->Name.Buffer,DirInfo->Name.Length);
LogFile[DirInfo->Name.Length >> 1] = (WCHAR)0;
wcscat(LogFile,L"\\bootex.log");
OldMode = SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
LogFileHandle = CreateFileW(
LogFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
(VOID )SetErrorMode( OldMode );
if ( LogFileHandle != INVALID_HANDLE_VALUE ) {
FileSize = GetFileSize(LogFileHandle,NULL);
if ( FileSize != 0xffffffff ) {
//
// truncate the file data if necessary
//
if ( FileSize > 32000 ) {
FileSize = 32000;
}
FileBuffer = LocalAlloc(LMEM_FIXED,FileSize+sizeof(WCHAR));
if ( FileBuffer ) {
FileBuffer[FileSize>>1] = (WCHAR)'\0';
if ( ReadFile(LogFileHandle,FileBuffer,FileSize,&BytesRead,NULL) ) {
FileBuffer[BytesRead>>1] = (WCHAR)'\0';
ServerRetryCount = 0;
tryagain:
LocalGlobals.hEventLog = RegisterEventSource(
NULL,
TEXT("Autochk")
);
if ( LocalGlobals.hEventLog ) {
rv = ReportWinlogonEvent(
&LocalGlobals,
EVENTLOG_INFORMATION_TYPE,
EVENT_AUTOCHK_DATA,
0,
NULL,
1,
FileBuffer
);
DeregisterEventSource(LocalGlobals.hEventLog);
LocalGlobals.hEventLog = NULL;
NtClose(LogFileHandle);
LogFileHandle = INVALID_HANDLE_VALUE;
if ( rv == ERROR_SUCCESS ) {
DeleteFile(LogFile);
}
}
else {
gle = GetLastError();
if ( (gle == RPC_S_SERVER_UNAVAILABLE ||
gle == RPC_S_UNKNOWN_IF)
&& ServerRetryCount < 10 ) {
Sleep(1000);
ServerRetryCount++;
goto tryagain;
}
}
}
}
}
if (LogFileHandle != INVALID_HANDLE_VALUE ) {
NtClose(LogFileHandle);
}
}
}
}
}
RestartScan = FALSE;
if (!NT_SUCCESS( Status )) {
break;
}
}
NtClose(DirectoryHandle);
return;
}
DWORD FontLoaderThread( void )
{
LoadLocalFonts();
ExitThread(0);
return(0); // prevent compiler warning
}
HANDLE
StartLoadingFonts(void)
{
HANDLE hThread;
DWORD ThreadId = 0;
hThread = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
0,
(LPTHREAD_START_ROUTINE) FontLoaderThread,
0,
0,
&ThreadId
);
//
// We don't need this handle (we're not going to wait), so get rid of
// it now, rather than later.
//
return( hThread );
}
BOOL InitSystemFontInfo(
PGLOBALS pGlobals
)
{
TCHAR *FontNames, *FontName;
TCHAR FontPath[ MAX_PATH ];
ULONG cb = 63 * 1024;
FontNames = Alloc( cb );
ASSERTMSG("Winlogon failed to allocate memory for reading font information", FontNames != NULL);
if (FontNames == NULL) {
return FALSE;
}
if (GetProfileString( TEXT("Fonts"), NULL, TEXT(""), FontNames, cb )) {
FontName = FontNames;
while (*FontName) {
if (GetProfileString( TEXT("Fonts"), FontName, TEXT(""), FontPath, sizeof( FontPath ) )) {
switch (AddFontResource( FontPath )) {
case 0:
KdPrint(("WINLOGON: Unable to add new font path: %ws\n", FontPath ));
break;
case 1:
KdPrint(("WINLOGON: Found new font path: %ws\n", FontPath ));
break;
default:
KdPrint(("WINLOGON: Found existing font path: %ws\n", FontPath ));
RemoveFontResource( FontPath );
break;
}
}
while (*FontName++) ;
}
} else {
KdPrint(("WINLOGON: Unable to read font info from win.ini - %u\n", GetLastError()));
}
Free( FontNames );
return TRUE;
}
/***************************************************************************\
* SetProcessPriority
*
* Sets the priority of the winlogon process.
*
* History:
* 18-May-1992 Davidc Created.
\***************************************************************************/
BOOL SetProcessPriority(
VOID
)
{
//
// Bump us up to the high priority class
//
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
DebugLog((DEB_ERROR, "Failed to raise it's own process priority, error = %d", GetLastError()));
return(FALSE);
}
//
// Set this thread to high priority since we'll be handling all input
//
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
DebugLog((DEB_ERROR, "Failed to raise main thread priority, error = %d", GetLastError()));
return(FALSE);
}
return(TRUE);
}
VOID
CreateTemporaryPageFile()
{
LONG FileSizeInMegabytes;
UNICODE_STRING PagingFileName;
NTSTATUS st;
LARGE_INTEGER MinPagingFileSize;
LARGE_INTEGER MaxPagingFileSize;
UNICODE_STRING FileName;
BOOLEAN TranslationStatus;
TCHAR TemporaryPageFile[MAX_PATH+1];
NTSTATUS PfiStatus,PiStatus;
ULONG ReturnLength;
SYSTEM_PAGEFILE_INFORMATION pfi;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
HKEY hkeyMM;
DWORD dwRegData = 0;
GetSystemDirectory(TemporaryPageFile,sizeof(TemporaryPageFile));
wcscat(TemporaryPageFile,TEXT("\\temppf.sys"));
DeleteFile(TemporaryPageFile);
//
// Check to see if we have a pagefile, warn the user if we don't
//
PfiStatus = NtQuerySystemInformation(
SystemPageFileInformation,
&pfi,
sizeof(pfi),
&ReturnLength
);
PiStatus = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
//
// if you have no page file, or your total commit limit is at it's minimum,
// then create an additional pagefile and tel the user to do something...
//
if ( (NT_SUCCESS(PfiStatus) && (ReturnLength == 0)) ||
(NT_SUCCESS(PiStatus) && PerfInfo.CommitLimit <= 5500 ) ) {
//
// Set a flag in registry so USERINIT knows to run VMApp.
//
dwRegData = 1;
PageFilePopup = TRUE;
//
// create a temporary pagefile to get us through logon/control
// panel activation
//
//
GetSystemDirectory(TemporaryPageFile,sizeof(TemporaryPageFile));
lstrcat(TemporaryPageFile,TEXT("\\temppf.sys"));
//
// Start with a 20mb pagefile
//
FileSizeInMegabytes = 20;
RtlInitUnicodeString(&PagingFileName, TemporaryPageFile);
MinPagingFileSize = RtlEnlargedIntegerMultiply(FileSizeInMegabytes,0x100000);
MaxPagingFileSize = MinPagingFileSize;
TranslationStatus = RtlDosPathNameToNtPathName_U(
PagingFileName.Buffer,
&FileName,
NULL,
NULL
);
if ( TranslationStatus ) {
retry:
st = NtCreatePagingFile(
(PUNICODE_STRING)&FileName,
&MinPagingFileSize,
&MaxPagingFileSize,
0
);
if (!NT_SUCCESS( st )) {
if ( FileSizeInMegabytes > 0 ) {
FileSizeInMegabytes -= 2;
MinPagingFileSize = RtlEnlargedIntegerMultiply(FileSizeInMegabytes,0x100000);
MaxPagingFileSize = MinPagingFileSize;
goto retry;
}
} else {
MoveFileExW(PagingFileName.Buffer,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);
}
RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
}
}
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMemMan, 0,
KEY_WRITE, &hkeyMM) == ERROR_SUCCESS) {
if (dwRegData == 1) {
RegSetValueEx (hkeyMM, szNoPageFile, 0, REG_DWORD,
(LPBYTE)&dwRegData, sizeof(dwRegData));
} else
RegDeleteValue(hkeyMM, (LPTSTR)szNoPageFile);
RegCloseKey(hkeyMM);
}
}
BOOL
StartSystemProcess(
PWSTR pszCommandLine,
PWSTR pszDesktop,
DWORD Flags,
DWORD StartupFlags,
PVOID pEnvironment,
BOOLEAN fSaveHandle,
HANDLE *phProcess,
HANDLE *phThread
)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL Result;
#if DBG
WCHAR szExtra[MAX_PATH];
#endif
//
// Initialize process startup info
//
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpReserved = pszCommandLine;
si.lpTitle = pszCommandLine;
si.dwFlags = StartupFlags;
si.wShowWindow = SW_SHOW; // at least let the guy see it
si.lpDesktop = pszDesktop;
//
// Special debug helpers for our friends
//
#if DBG
if ((WinlogonInfoLevel & DEB_DEBUG_LSA) &&
((wcsncmp(pszCommandLine, TEXT("lsass"), 5) == 0) ||
(wcsncmp(pszCommandLine, TEXT("spmgr"), 5) == 0) ))
{
wcscpy(szExtra, SELECT_DEBUG_COMMAND(WinlogonInfoLevel));
wcscat(szExtra, pszCommandLine);
pszCommandLine = szExtra;
}
if ((WinlogonInfoLevel & DEB_DEBUG_MPR) &&
(wcsncmp(pszCommandLine, TEXT("mpnotify"), 8) == 0))
{
wcscpy(szExtra, SELECT_DEBUG_COMMAND(WinlogonInfoLevel));
wcscat(szExtra, pszCommandLine);
pszCommandLine = szExtra;
}
if ((WinlogonInfoLevel & DEB_DEBUG_SERVICES) &&
(wcsncmp(pszCommandLine, TEXT("services"), 8) == 0))
{
wcscpy(szExtra, SELECT_DEBUG_COMMAND(WinlogonInfoLevel));
wcscat(szExtra, pszCommandLine);
pszCommandLine = szExtra;
}
#endif
//
// Create the app suspended
//
Result = CreateProcess(NULL,
pszCommandLine,
NULL,
NULL,
FALSE,
Flags | CREATE_UNICODE_ENVIRONMENT,
pEnvironment,
NULL,
&si,
&pi);
if (Result)
{
if (!phProcess)
{
if (fSaveHandle)
{
if (cSystemProcesses < MAXIMUM_WAIT_OBJECTS)
{
hSystemProcesses[cSystemProcesses++] = pi.hProcess;
}
}
else
{
CloseHandle(pi.hProcess);
}
}
else
{
*phProcess = pi.hProcess;
}
if (!phThread)
{
CloseHandle(pi.hThread);
}
else
{
*phThread = pi.hThread;
}
}
return(Result);
}
BOOL
ExecSystemProcesses(
PGLOBALS pGlobals
)
{
BOOL SystemStarted = FALSE ;
SYSTEM_CRASH_STATE_INFORMATION CrashState;
PWSTR pszStartLine;
PWSTR pszTok;
DWORD dwStarted = 0;
PVOID pEnvironment;
//
// Initialize the shutdown server
//
RpcpInitRpcServer();
if ( !InitializeShutdownModule( pGlobals ) ) {
ASSERT( FALSE );
DebugLog((DEB_ERROR, "Cannot InitializeShutdownModule."));
}
//
// Initialize the registry server
//
// NB: This is prototyped local to this file. Any change must be
// reflected above.
//
if ( !InitializeWinreg() ) {
ASSERT( FALSE );
DebugLog((DEB_ERROR, "Cannot InitializeWinreg."));
}
//
// must start services.exe server before anything else. If there is an
// entry ServiceControllerStart in win.ini, use it as the command.
//
pszStartLine = AllocAndGetProfileString(APPLICATION_NAME,
TEXT("ServiceControllerStart"),
TEXT("services.exe"));
if (!pszStartLine)
{
DebugLog((DEB_ERROR, "Can't allocate space, so this exec probably won't work\n"));
pszStartLine = TEXT("services.exe");
}
if (CreateUserEnvironment(&pEnvironment))
{
SetupBasicEnvironment(&pEnvironment);
}
else
{
DebugLog((DEB_ERROR, "Failed to create initial environment\n"));
//
// Set this to NULL, and let CreateProcess deal with any
// memory constraints.
//
pEnvironment = NULL;
}
if (!StartSystemProcess(pszStartLine,
APPLICATION_DESKTOP_NAME,
0,
STARTF_FORCEOFFFEEDBACK,
pEnvironment,
FALSE, // Don't stash this handle away
NULL, NULL))
{
DebugLog((DEB_ERROR, "Couldn't start %ws, %d\n", pszStartLine, GetLastError()));
}
else
{
HANDLE hRPCRegServer;
int error,
i = 0 ;
while(i < 20000) {
Sleep(1000); i+=1000;
if (hRPCRegServer = OpenEventA(SYNCHRONIZE, FALSE, "Microsoft.RPC_Registry_Server")) {
//WLPrint(("RPC_Registry_Server event openned"));
error = WaitForSingleObject(hRPCRegServer, 100);
CloseHandle(hRPCRegServer);
break;
}
}
}
Free(pszStartLine);
//
// If this is standard installation or network installation, we need to
// create an event to stall lsa security initialization. In the case of
// WINNT -> WINNT and AS -> AS upgrade we shouldn't stall LSA.
//
if (pGlobals->fExecuteSetup && (pGlobals->SetupType != SETUPTYPE_UPGRADE)) {
CreateLsaStallEvent();
}
//
// If there is a system dump available, start up the save dump process to
// capture it so that it doesn't use as much paging file so that it is
// available for system use.
//
NtQuerySystemInformation( SystemCrashDumpStateInformation,
&CrashState,
sizeof( CrashState ),
(PULONG) NULL );
if (CrashState.ValidCrashDump) {
pszStartLine = AllocAndGetProfileString(APPLICATION_NAME,
TEXT("SaveDumpStart"),
TEXT("savedump.exe"));
if (!StartSystemProcess(pszStartLine,
APPLICATION_DESKTOP_NAME,
0,
STARTF_FORCEOFFFEEDBACK,
pEnvironment,
FALSE, // Don't care about syncing later
NULL, NULL))
{
DebugLog((DEB_ERROR, "Couldn't start %ws, %d\n", pszStartLine, GetLastError()));
}
Free(pszStartLine);
}
//
// Startup system processes
// These must be started for authentication initialization to succeed
// because one of the system processes is the LSA server.
//
pszStartLine = AllocAndGetProfileString(APPLICATION_NAME,
TEXT("System"),
NULL);
pszTok = wcstok(pszStartLine, TEXT(","));
while (pszTok)
{
//
// Skip any blanks...
//
if (*pszTok == TEXT(' '))
{
while (*pszTok++ == TEXT(' '))
;
}
if (StartSystemProcess( pszTok,
APPLICATION_DESKTOP_NAME,
0,
STARTF_FORCEOFFFEEDBACK,
pEnvironment,
TRUE, // Save this handle to sync with
NULL, NULL))
{
dwStarted++;
}
pszTok = wcstok(NULL, TEXT(","));
}
Free(pszStartLine);
RtlDestroyEnvironment(pEnvironment);
return TRUE;
}
/***************************************************************************\
* InitializeSound
*
* Set up a global function variable to address the sound playing routine.
* If no wave devices are present, this variable will remain 0 and no sound
* will be made by WinLogon.
*
* History:
* 6-May-1992 SteveDav Created
\***************************************************************************/
void InitializeSound(
PGLOBALS pGlobals)
{
//
// Load the sound playing module. If no wave devices are available
// free the library, and set the address of the sound function to 0
//
CHAR ResourceString[MAX_STRING_BYTES];
HANDLE hLib;
// Set the initial value (should not be necessary)
pGlobals->PlaySound = NULL;
pGlobals->MigrateSoundEvents = NULL;
//
// Get name of sound library
//
if (!LoadStringA(NULL, IDS_SOUND_DLL, ResourceString, sizeof(ResourceString))) {
// Cannot get the name of the sound library
return;
}
hLib = LoadLibraryA(ResourceString);
if (hLib) {
/* We must use the Ascii version of LoadString as GetProcAddress */
/* takes an Ascii string only... */
/* Whenever a user logs in, have WINMM.DLL check if there are any */
/* sound events within the [SOUNDS] section of CONTROL.INI that */
/* haven't been ported into HKCU/AppEvents. Here, we find the */
/* relevant routine within WINMM.DLL so it can be called when */
/* appropriate. */
if (!LoadStringA(NULL, IDS_MIGRATESOUNDEVENTS, ResourceString, sizeof(ResourceString))) {
/* we do not know the name of the routine to call */
pGlobals->MigrateSoundEvents = NULL;
} else {
pGlobals->MigrateSoundEvents = (SOUNDPROC)GetProcAddress(hLib, ResourceString);
}
if (!LoadStringA(NULL, IDS_WAVEOUTGETNUMDEVS, ResourceString, sizeof(ResourceString))) {
/* we do not know the name of the routine to call */
//return; We must free the library...
} else {
pGlobals->PlaySound = (SOUNDPROC)GetProcAddress(hLib, ResourceString);
}
if (pGlobals->PlaySound) {
/* See how many wave devices there are - if none, or we fail
* to load the name of PlaySound, then unload WINMM and never
* try and call it again.
*/
UINT n;
n = (UINT)(*(pGlobals->PlaySound))();
if (n &&
LoadStringA(NULL, IDS_PLAYSOUND, ResourceString, sizeof(ResourceString))) {
pGlobals->PlaySound = (SOUNDPROC)GetProcAddress(hLib, ResourceString);
} else {
pGlobals->PlaySound = NULL;
//DebugLog((DEB_ERROR, "Winlogon: NO WAVE devices"));
}
}
if (!pGlobals->PlaySound && !pGlobals->MigrateSoundEvents) {
//DebugLog((DEB_ERROR, "Winlogon: Unloading WINMM"));
FreeLibrary(hLib);
}
}
#if DBG
else { /* Could not load WINMM */
DebugLog((DEB_ERROR, "Could not load WINMM")); // Keep this debug message. It's an error
}
#endif
}
/***************************************************************************\
* InitializeMidi
*
* Set up a global function variable to address the Midi Migrate User routine.
*
* History:
* 1-3-96 ShawnB Created
\***************************************************************************/
void InitializeMidi(
PGLOBALS pGlobals)
{
//
// Load the Midi Migration module.
//
CHAR ResourceString[MAX_STRING_BYTES];
HMODULE hModule;
BOOL fFreeLib;
// Set the initial value (should not be necessary)
pGlobals->MigrateMidiUser = NULL;
//
// Get name of Midi library
//
if (!LoadStringA(NULL, IDS_MIDI_DLL, ResourceString, sizeof(ResourceString))) {
// Cannot get the name of the Midi library
return;
}
// Check if Already loaded (by InitializeSound)
hModule = GetModuleHandleA(ResourceString);
if (!hModule)
{
// Load it ourselves
hModule = (HMODULE)LoadLibraryA(ResourceString);
fFreeLib = TRUE;
}
else
{
fFreeLib = FALSE;
}
if (hModule) {
/* We must use the Ascii version of LoadString as GetProcAddress */
/* takes an Ascii string only... */
/* Whenever a user logs in, have WINMM.DLL check if the user needs */
/* their MIDI registry info updated. Here, we find the */
/* relevant routine within WINMM.DLL so it can be called when */
/* appropriate. */
if (!LoadStringA(NULL, IDS_MIGRATEMIDIUSER, ResourceString, sizeof(ResourceString))) {
/* we do not know the name of the routine to call */
pGlobals->MigrateMidiUser = NULL;
} else {
pGlobals->MigrateMidiUser = (MIDIPROC)GetProcAddress(hModule, ResourceString);
}
if (!pGlobals->MigrateMidiUser) {
//DebugLog((DEB_ERROR, "Winlogon: Unloading WINMM"));
if (fFreeLib)
{
FreeLibrary(hModule);
}
}
}
#if DBG
else { /* Could not load WINMM */
DebugLog((DEB_ERROR, "Could not load WINMM")); // Keep this debug message. It's an error
}
#endif
} // End InitializeMidi
BOOL
WaitForSystemProcesses(
PGLOBALS pGlobals)
{
DWORD i;
DWORD Exit;
//
// First, verify all handles:
//
for (i = 0; i < cSystemProcesses ; i++ )
{
WaitLoopTop:
if (GetExitCodeProcess(hSystemProcesses[i], &Exit))
{
if (Exit == STILL_ACTIVE)
{
//
// Ooh, a good one. Keep it.
//
continue;
}
}
//
// Bad handle, one way or another
//
CloseHandle(hSystemProcesses[i]);
hSystemProcesses[i] = hSystemProcesses[--cSystemProcesses];
if (i != cSystemProcesses)
{
goto WaitLoopTop; // Retry same index, but do not increment
}
}
if (!cSystemProcesses)
{
return(TRUE);
}
Exit = WaitForMultipleObjectsEx( cSystemProcesses,
hSystemProcesses,
FALSE,
4000,
FALSE );
return(Exit != WAIT_TIMEOUT);
}