windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/extprog.c
2020-09-26 16:20:57 +08:00

360 lines
8.2 KiB
C

/*++
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);
}