/*++ Copyright (c) 1995 Microsoft Corporation Module Name: extprog.c Abstract: Routines for invoking external applications. Entry points in this module: InvokeExternalApplication InvokeControlPanelApplet Author: Ted Miller (tedm) 5-Apr-1995 Revision History: --*/ #include "setupp.h" #pragma hdrstop PCWSTR szWaitOnApp = L"WaitOnApp"; DWORD WaitOnApp( IN HANDLE Process, OUT PDWORD ExitCode, IN DWORD Timeout ) { DWORD dw; BOOL Done; MYASSERT( ExitCode != NULL ); // // Process any messages that may already be in the queue. // PumpMessageQueue(); // // Wait for process to terminate or more messages in the queue. // Done = FALSE; do { switch(MsgWaitForMultipleObjects(1,&Process,FALSE,Timeout,QS_ALLINPUT)) { case WAIT_OBJECT_0: // // Process has terminated. // dw = GetExitCodeProcess(Process,ExitCode) ? NO_ERROR : GetLastError(); Done = TRUE; break; case WAIT_OBJECT_0+1: // // Messages in the queue. // PumpMessageQueue(); break; case WAIT_TIMEOUT: dw = WAIT_TIMEOUT; *ExitCode = WAIT_TIMEOUT; Done = TRUE; break; default: // // Error. // dw = GetLastError(); Done = TRUE; break; } } while(!Done); return(dw); } BOOL InvokeExternalApplication( IN PCWSTR ApplicationName, OPTIONAL IN PCWSTR CommandLine, IN OUT PDWORD ExitCode OPTIONAL ) /*++ Routine Description: See InvokeExternalApplicationEx --*/ { // // infinite timeout // return(InvokeExternalApplicationEx( ApplicationName, CommandLine, ExitCode, INFINITE, FALSE)); } BOOL InvokeExternalApplicationEx( IN PCWSTR ApplicationName, OPTIONAL IN PCWSTR CommandLine, IN OUT PDWORD ExitCode, OPTIONAL IN DWORD Timeout, IN BOOL Hidden ) /*++ Routine Description: Invokes an external program, which is optionally detached. Arguments: ApplicationName - supplies app name. May be a partial or full path, or just a filename, in which case the standard win32 path search is performed. If not specified then the first element in CommandLine must specify the binary to execute. CommandLine - supplies the command line to be passed to the application. ExitCode - If specified, the execution is synchronous and this value receives the exit code of the application. If not specified, the execution is asynchronous. Timeout - specifies how long to wait for the app to complete. Hidden - if TRUE, indicates that the application should be invoked with the SW_HIDE attribute set. Return Value: Boolean value indicating whether the process was started successfully. --*/ { PWSTR FullCommandLine; BOOL b; PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartupInfo; DWORD d; b = FALSE; // // Form the command line to be passed to CreateProcess. // if(ApplicationName) { FullCommandLine = MyMalloc((lstrlen(ApplicationName)+lstrlen(CommandLine)+2)*sizeof(WCHAR)); if(!FullCommandLine) { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPP_FAIL, ApplicationName,NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_OUTOFMEMORY, NULL,NULL); goto err0; } lstrcpy(FullCommandLine,ApplicationName); lstrcat(FullCommandLine,L" "); lstrcat(FullCommandLine,CommandLine); } else { FullCommandLine = pSetupDuplicateString(CommandLine); if(!FullCommandLine) { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPP_FAIL, CommandLine, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_OUTOFMEMORY, NULL,NULL); goto err0; } } // // Initialize startup info. // ZeroMemory(&StartupInfo,sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(STARTUPINFO); if (Hidden) { // // no UI // GetStartupInfo(&StartupInfo); StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; StartupInfo.wShowWindow = SW_HIDE; } // // Create the process. // b = CreateProcess( NULL, FullCommandLine, NULL, NULL, FALSE, ExitCode ? 0 : DETACHED_PROCESS, NULL, NULL, &StartupInfo, &ProcessInfo ); if(!b) { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPP_FAIL, FullCommandLine, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_X_RETURNED_WINERR, szCreateProcess, GetLastError(), NULL,NULL); goto err1; } // // If execution is asynchronus, we're done. // if(!ExitCode) { SetuplogError( LogSevInformation, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPP_SUCCEED, FullCommandLine, NULL,NULL); goto err2; } // // Need to wait for the app to finish. // If the wait failed don't return an error but log a warning. // d = WaitOnApp(ProcessInfo.hProcess,ExitCode,Timeout); if(d != NO_ERROR) { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPP_FAIL, FullCommandLine, 0, SETUPLOG_USE_MESSAGEID, MSG_LOG_X_RETURNED_WINERR, szWaitOnApp, d, NULL,NULL); } else { SetuplogError( LogSevInformation | SETUPLOG_SINGLE_MESSAGE, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPP_SUCCEED_STATUS, FullCommandLine, *ExitCode, NULL, NULL); } // // Put setup back in the foreground. // SetForegroundWindow(MainWindowHandle); err2: CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); err1: MyFree(FullCommandLine); err0: return(b); } BOOL InvokeControlPanelApplet( IN PCWSTR CplSpec, IN PCWSTR AppletName, OPTIONAL IN UINT AppletNameStringId, IN PCWSTR CommandLine ) { PWSTR FullCommandLine; BOOL b; BOOL LoadedAppletName; DWORD ExitCode; b = FALSE; LoadedAppletName = FALSE; if(!AppletName) { if(AppletName = MyLoadString(AppletNameStringId)) { LoadedAppletName = TRUE; } } if(AppletName) { FullCommandLine = MyMalloc((lstrlen(CplSpec)+lstrlen(AppletName)+lstrlen(CommandLine)+3) * sizeof(WCHAR)); if(FullCommandLine) { lstrcpy(FullCommandLine,CplSpec); lstrcat(FullCommandLine,L","); lstrcat(FullCommandLine,AppletName); lstrcat(FullCommandLine,L","); lstrcat(FullCommandLine,CommandLine); b = InvokeExternalApplication(L"RUNDLL32 shell32,Control_RunDLL",FullCommandLine,&ExitCode); MyFree(FullCommandLine); } else { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPPLET_FAIL, AppletName, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_OUTOFMEMORY, NULL,NULL); } } else { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVOKEAPPLET_FAIL, L"", NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_OUTOFMEMORY, NULL,NULL); } if(LoadedAppletName) { MyFree(AppletName); } return(b); }