windows-nt/Source/XPSP1/NT/base/ntsetup/legacy/dll/dllmain.c

1023 lines
25 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "precomp.h"
#pragma hdrstop
/**************************************************************************/
/***** Shell Component - WinMain, ShellWndProc routines *******************/
/**************************************************************************/
//
// Reentrancy control.
//
BOOL
EnterInterpreter(
VOID
);
#define EXIT_CODE "Exit_Code"
extern HWND hwndProgressGizmo;
//
// This flag tells us whether we were invoked as a standalone process
// or whether we were called to interpret a legacy inf from within a process.
//
BOOL OwnProcess;
//
// The following two globals are only valid if 'OwnProcess' is FALSE. They are
// used to keep track of what services have been modified during an INF 'run'.
// Refer to sc.c!LegacyInfGetModifiedSvcList() for more details.
//
LPSTR ServicesModified;
DWORD ServicesModifiedSize;
/*
** Shell Global Variables
*/
HANDLE hInst = (HANDLE)NULL;
HWND hWndShell = (HWND)NULL;
HANDLE SupportLibHandle = NULL;
HWND hwParam = NULL ;
HWND hwPseudoParent = NULL ;
static BOOL fParamFlashOn = FALSE ;
// SZ szShlScriptSection = (SZ)NULL;
//
// No longer used (we never try to abort a shutdown)
//
// BOOL fIgnoreQueryEndSession = fTrue;
CHP rgchBufTmpLong[cchpBufTmpLongBuf] = "long";
CHP rgchBufTmpShort[cchpBufTmpShortBuf] = "short";
HBITMAP hbmAdvertList [ BMP_MAX + 1 ] ;
INT cAdvertIndex = -1 ;
INT cAdvertCycleSeconds = 0 ;
INT cyAdvert = 0 ;
INT cxAdvert = 0 ;
INT dyChar = 0;
INT dxChar = 0;
BOOL bTimerEnabled = FALSE ;
RECT rcBmpMax = {-1,-1,-1,-1} ;
extern BOOL fFullScreen;
extern INT gaugeCopyPercentage ;
extern PSTR LastShellReturn;
extern DWORD LastShellReturnSize;
SCP rgscp[] = {
{ "UI", spcUI },
{ "READ-SYMS", spcReadSyms },
{ "DETECT", spcDetect },
{ "INSTALL", spcInstall },
{ "UPDATE-INF", spcUpdateInf },
{ "WRITE-INF", spcWriteInf },
{ "EXIT", spcExit },
{ "WRITE-SYMTAB", spcWriteSymTab },
{ "SET-TITLE", spcSetTitle },
{ "EXIT-AND-EXEC", spcExitAndExec },
{ "ENABLEEXIT", spcEnableExit },
{ "DISABLEEXIT", spcDisableExit },
{ "SHELL", spcShell },
{ "RETURN", spcReturn },
{ NULL, spcUnknown },
};
PSPT psptShellScript = (PSPT)NULL;
VOID
RebootMachineIfNeeded(
);
#define TimerInterval 500 // 1/2 second
#define TimerId 1
VOID FSetTimer ( VOID ) ;
VOID FHandleBmpTimer ( VOID ) ;
VOID FFlashParentActive ( VOID ) ;
VOID FPaintBmp ( HWND hwnd, HDC hdc ) ;
#define POINTSIZE_WASHTEXT 24
#define X_WASHTEXT 5
#define Y_WASHTEXT 5
#define CR_BLACK RGB(0, 0, 0)
#define CR_DKBLUE RGB(0, 0, 128)
UINT ScreenWidth,ScreenHeight;
int
real_dll_main(
IN int argc,
IN char *argv[],
IN char *CommandLine OPTIONAL
)
{
HANDLE hInst;
HANDLE hPrevInst = NULL;
LPSTR lpCmdLine;
INT nCmdShow = SW_SHOWNORMAL;
USHORT _argc = (USHORT)argc;
CHAR **_argv = argv;
MSG msg;
SZ szInfSrcPath;
SZ szDestDir;
SZ szSrcDir;
SZ szCWD;
PSTR sz;
INT wModeSetup;
INT rc;
hInst = MyDllModuleHandle;
lpCmdLine = CommandLine ? CommandLine : GetCommandLine();
//
// Strip off the first string (program name).
//
if(sz = strchr(lpCmdLine,' ')) {
do {
sz++;
} while(*sz == ' ');
lpCmdLine = sz;
} else {
// no spaces, program name is alone on cmd line.
lpCmdLine += lstrlen(lpCmdLine);
}
ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
//
// We check for the -f parameter here because we have to create (and display)
// the Seup window before calling the FParseCmdLine function.
//
if( _argc < 2 ) {
//
// No parameters on setup command line. If setup has been run from
// the windows system direcotry then we conclude that setup has been
// run in maintenance mode
//
CHAR szSystemDir[MAX_PATH];
CHAR szCWD[MAX_PATH];
if ( GetSystemDirectory( szSystemDir, MAX_PATH ) &&
GetModuleFileName(hInst, szCWD, MAX_PATH)
) {
SZ szFileSpec;
//
// Extract the directory of the module file spec and compare it
// with the system directory. If the two are the same assume
// we are maintenance mode
if( szFileSpec = strrchr( szCWD, '\\' ) ) {
*szFileSpec = '\0';
if( !lstrcmpi( szSystemDir, szCWD ) ) {
fFullScreen = fFalse;
}
}
}
}
else {
//
// Check to see if blue wash has been explicitly disabled or
// if a primary parent window handle has been passed in.
//
while ( --argc ) {
if ( (_argv[argc][0] == '/') || (_argv[argc][0] == '-')) {
switch ( _argv[argc][1] )
{
case 'F':
case 'f':
fFullScreen = fFalse;
break;
case 'w':
case 'W':
hwParam = (HWND) LongToHandle(atol( _argv[argc+1] )) ;
break ;
default:
break ;
}
}
}
_argv = argv;
}
CurrentCursor = LoadCursor(NULL,IDC_ARROW);
if(!CreateShellWindow(hInst,nCmdShow,FALSE)) {
return( SETUP_ERROR_GENERAL );
}
rc = ParseCmdLine(
hInst,
(SZ)lpCmdLine,
&szInfSrcPath,
&szDestDir,
&szSrcDir,
&szCWD,
&wModeSetup
);
if( rc != CMDLINE_SUCCESS) {
FDestroyShellWindow() ;
return( ( rc == CMDLINE_SETUPDONE ) ?
SETUP_ERROR_SUCCESS : SETUP_ERROR_GENERAL );
}
if(!FInitApp(hInst, szInfSrcPath, szDestDir, szSrcDir, szCWD,
wModeSetup)) {
FDestroyShellWindow() ;
return(SETUP_ERROR_GENERAL);
}
// Start the timer ticking
FSetTimer() ;
//
// Set the parent app, if any, to *appear* enabled
//
if(OwnProcess) {
FFlashParentWindow(TRUE);
}
while (GetMessage(&msg, NULL, 0, 0)) {
if(FUiLibFilter(&msg) &&
(hwndProgressGizmo == NULL ||
!IsDialogMessage(hwndProgressGizmo,&msg))) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)(msg.wParam);
}
int
dll_main(
IN int argc,
IN char *argv[]
)
{
if(!EnterInterpreter()) {
return(SETUP_ERROR_GENERAL);
}
OwnProcess = TRUE;
//
// Set the modified service list buffer to empty, so we won't be fooled into
// using it should someone mistakenly call LegacyInfGetModifiedSvcList().
// This buffer is only valid when used after a successful call to
// LegacyInfInterpret().
//
ServicesModified = NULL;
ServicesModifiedSize = 0;
return(real_dll_main(argc,argv,NULL));
}
/*
** Purpose:
** ??
** Arguments:
** none
** Returns:
** none
**
***************************************************************************/
LRESULT APIENTRY ShellWndProc(HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rc;
INT ExitCode = SETUP_ERROR_GENERAL;
SZ szExitCode;
static LPSTR HelpContext = NULL;
switch (wMsg) {
case WM_CREATE:
break;
case WM_ERASEBKGND:
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
if ( fFullScreen ) {
HBITMAP hbmBackground;
HDC hdcMem;
BITMAP bm;
BOOL Drawn;
LOGFONT LogFont;
HFONT hFont,hFontOld;
COLORREF crBk,crTx;
Drawn = FALSE;
GetClientRect(hWnd, &rc);
if(hbmBackground = LoadBitmap(MyDllModuleHandle,MAKEINTRESOURCE(IDB_BACKGROUND))) {
if(hdcMem = CreateCompatibleDC(ps.hdc)) {
crBk = SetBkColor(ps.hdc,CR_DKBLUE);
crTx = SetTextColor(ps.hdc,CR_BLACK);
SelectObject(hdcMem,hbmBackground);
GetObject(hbmBackground,sizeof(BITMAP),&bm);
StretchBlt(
ps.hdc,
0,0,
ScreenWidth+1,
ScreenHeight+1,
hdcMem,
0,0,
bm.bmWidth,bm.bmHeight,
SRCCOPY
);
DeleteDC(hdcMem);
SetBkColor(ps.hdc, crBk);
SetTextColor(ps.hdc, crTx);
Drawn = TRUE;
}
DeleteObject(hbmBackground);
}
if(!Drawn) {
PatBlt(ps.hdc,0,0,ScreenWidth,ScreenHeight,BLACKNESS);
}
ZeroMemory(&LogFont,sizeof(LOGFONT));
LogFont.lfHeight = -1 * (GetDeviceCaps(ps.hdc,LOGPIXELSY) * POINTSIZE_WASHTEXT / 72);
LogFont.lfWeight = FW_DONTCARE;
//LogFont.lfItalic = TRUE;
LogFont.lfCharSet = DEFAULT_CHARSET;
LogFont.lfQuality = PROOF_QUALITY;
LogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_ROMAN;
lstrcpy(LogFont.lfFaceName,"MS Serif");
if(hFont = CreateFontIndirect(&LogFont)) {
TCHAR Buffer[128];
UINT i;
i = LoadString(MyDllModuleHandle,IDS_WINDOWS_NT_SETUP,Buffer,sizeof(Buffer)/sizeof(TCHAR));
hFontOld = SelectObject(ps.hdc,hFont);
SetTextColor(ps.hdc, RGB(255,255,255));
SetBkMode(ps.hdc, TRANSPARENT);
ExtTextOut(ps.hdc,X_WASHTEXT,Y_WASHTEXT,ETO_CLIPPED,&rc,Buffer,i,NULL);
SelectObject(ps.hdc, hFontOld);
DeleteObject(hFont);
}
if(cAdvertIndex >= 0) {
FPaintBmp( hWnd, hdc ) ;
}
}
EndPaint(hWnd, &ps);
break;
case WM_ACTIVATEAPP:
if (wParam != 0) {
SetWindowPos(
hWnd,
NULL,
0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE
);
}
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
case WM_NCHITTEST: {
extern BOOL WaitingOnChild;
if(WaitingOnChild) {
return(HTERROR);
} else {
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
}
case WM_TIMER:
if ( wParam == TimerId && cAdvertIndex >= 0 ){
FHandleBmpTimer() ;
}
break ;
case WM_CLOSE:
if (HdlgStackTop() != NULL) {
SendMessage(HdlgStackTop(), WM_CLOSE, 0, 0L);
} else {
MessageBeep(0);
}
break;
case STF_UI_EVENT:
if (!FGenericEventHandler(hInst, hWnd, wMsg, wParam, lParam)) {
if (hWndShell != NULL) {
SendMessage(hWndShell, (WORD)STF_ERROR_ABORT, 0, 0);
}
}
break;
case STF_SHL_INTERP:
if (!FInterpretNextInfLine(wParam, lParam)) {
if (hWndShell != NULL) {
SendMessage(hWndShell, (WORD)STF_ERROR_ABORT, 0, 0);
}
}
break;
case STF_HELP_DLG_DESTROYED:
case STF_INFO_DLG_DESTROYED:
case STF_EDIT_DLG_DESTROYED:
case STF_RADIO_DLG_DESTROYED:
case STF_LIST_DLG_DESTROYED:
case STF_MULTI_DLG_DESTROYED:
case STF_QUIT_DLG_DESTROYED:
case STF_COMBO_DLG_DESTROYED:
case STF_MULTICOMBO_DLG_DESTROYED:
case STF_MULTICOMBO_RADIO_DLG_DESTROYED:
case STF_DUAL_DLG_DESTROYED:
case STF_MAINT_DLG_DESTROYED:
break;
case WM_ENTERIDLE:
if(wParam == MSGF_DIALOGBOX) {
SendMessage((HWND)lParam,WM_ENTERIDLE,wParam,lParam);
}
return(0);
case WM_SETCURSOR:
SetCursor(CurrentCursor);
return(TRUE);
case WM_DESTROY:
if ( pGlobalContext() ) {
szExitCode = SzFindSymbolValueInSymTab( EXIT_CODE );
if ( szExitCode && (szExitCode[0] != '\0')) {
ExitCode = atoi( szExitCode );
} else {
ExitCode = SETUP_ERROR_GENERAL;
}
FCloseWinHelp(hWnd);
}
FTermHook();
PostQuitMessage(ExitCode);
break;
case STF_ERROR_ABORT:
FCloseWinHelp(hWnd);
RebootMachineIfNeeded();
FFlashParentActive() ;
if(OwnProcess) {
ExitProcess(ExitCode);
} else {
FDestroyShellWindow();
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_HELPBUTTON:
FProcessWinHelp(hWnd);
break;
default:
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
break;
default:
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
return(0L);
}
VOID
SetSupportLibHandle(
IN HANDLE Handle
)
{
SupportLibHandle = Handle;
}
VOID
RebootMachineIfNeeded(
)
{
SZ sz;
BOOLEAN OldState;
NTSTATUS Status;
if ( pGlobalContext()
&& ( sz = SzFindSymbolValueInSymTab("!STF_INSTALL_TYPE") ) != (SZ)NULL
&& !lstrcmpi( sz, "SETUPBOOTED" ) ) {
Status = RtlAdjustPrivilege(
SE_SHUTDOWN_PRIVILEGE,
TRUE,
FALSE,
&OldState);
if( NT_SUCCESS( Status ) ) {
if(OwnProcess) {
ExitWindowsEx(EWX_REBOOT, 0);
}
}
}
}
VOID FDestroyShellWindow ( VOID )
{
if ( bTimerEnabled ) {
KillTimer( hWndShell, TimerId ) ;
}
if ( hwParam ) {
EnableWindow( hwParam, TRUE );
SetActiveWindow( hwParam ) ;
}
DestroyWindow( hWndShell ) ; // needed to kill bootstrapper
}
// Set the parent app's window, if any, to appear
// active or inactive, according to 'On'.
VOID FFlashParentWindow ( BOOL On )
{
if ( hwParam == NULL || On == fParamFlashOn )
return ;
fParamFlashOn = On ;
FlashWindow( hwParam, fTrue ) ;
}
VOID FFlashParentActive ( VOID )
{
if ( hwParam == NULL )
return ;
// We don't know what state the parent is in. If
// we flash and find that it WAS active, do it again.
if ( FlashWindow( hwParam, fTrue ) )
FlashWindow( hwParam, fTrue ) ;
}
// Start the timer sending WM_TIMER messages to the
// main window.
VOID FSetTimer ( VOID )
{
bTimerEnabled = (SetTimer( hWndShell, TimerId, TimerInterval, NULL ) != 0);
}
// This routine maintains a RECT structure defining the
// largest rectangle modified by an "advertising" bitmap.
// Its value is used to invalidate only the exact portions
// of the shell window.
static void computeBmpUpdateRect ( HBITMAP hbmNext )
{
BITMAP bm ;
RECT rc ;
int ix, iy ;
// Get info about this bitmap
GetObject( hbmNext, sizeof bm, & bm ) ;
// Compute the rectangle it will occupy
GetClientRect( hWndShell, & rc ) ;
ix = (rc.right - rc.left) / 100 ;
ix *= cxAdvert ;
iy = (rc.bottom - rc.top) / 100 ;
iy *= cyAdvert ;
rc.left = ix ;
rc.right = ix + bm.bmWidth ;
rc.top = iy ;
rc.bottom = iy + bm.bmHeight ;
// Compute the max rect of this and prior history
if ( rcBmpMax.left == -1 ) {
rcBmpMax = rc ;
} else {
if ( rc.left < rcBmpMax.left )
rcBmpMax.left = rc.left ;
if ( rc.top < rcBmpMax.top )
rcBmpMax.top = rc.top ;
if ( rc.right > rcBmpMax.right )
rcBmpMax.right = rc.right ;
if ( rc.bottom > rcBmpMax.bottom )
rcBmpMax.bottom = rc.bottom ;
}
}
/*
* Update the BMP being displayed unless the cycle is zero seconds.
*
* The logic works as follows: If the cycle time is > 1, then
* the bitmaps just cycle in a loop, with each bitmap being
* displayed for the time given.
*
* If the cycle type is == 1, then the display is synchronized
* with the copy dialogs completion percentage. The global variable
* "gaugeCopyPercentage" is monitored, and each time it moves
* into a new "band", the bit map is updated. Band size is determined
* by dividing the 100% level by the number of bitmaps. The
* routine guarantees that no bitmap will appear for less than 15
* seconds. When the copy operation complets, it sets gaugeCopyPercentage
* back to -1 and the INF is responsible for calling BmpHide to tear
* down the bitmaps.
*/
VOID FHandleBmpTimer ( VOID )
{
#define MINIMUM_BITMAP_CYCLE 15
static DWORD dwFirstTime = 0;
static DWORD dwLastTime = 0 ;
static INT cIndexLast = -1 ;
if ( cAdvertIndex >= 0 && cAdvertCycleSeconds != 0 ) {
INT cIndexMax;
INT iBmp = cIndexLast;
DWORD dwCurrTime = GetCurrentTime();
DWORD dwElapsedCycles;
// Count the number of bitmaps
for ( cIndexMax = 0 ;
hbmAdvertList[cIndexMax] ;
cIndexMax++ ) ;
// See if we're based on percentages or timing
if ( cAdvertCycleSeconds == 1 ) {
// Percentages: check percentage complete of copy operation.
// Don't update display if gauge isn't active yet
if ( gaugeCopyPercentage >= 0 ) {
if ( gaugeCopyPercentage >= 100 )
gaugeCopyPercentage = 99 ;
iBmp = gaugeCopyPercentage / (100 / cIndexMax) ;
if ( iBmp >= cIndexMax )
iBmp = cIndexMax - 1 ;
}
} else {
// Timing: see if the current bitmap has expired
if ( dwFirstTime == 0 )
dwFirstTime = dwCurrTime ;
dwElapsedCycles = (dwCurrTime - dwFirstTime)
/ (cAdvertCycleSeconds * TimerInterval) ;
iBmp = dwElapsedCycles % cIndexMax ;
}
if ( iBmp != cIndexLast
&& (dwLastTime + MINIMUM_BITMAP_CYCLE) < dwCurrTime ) {
cAdvertIndex = iBmp ;
computeBmpUpdateRect( hbmAdvertList[ cAdvertIndex ] ) ;
InvalidateRect( hWndShell, & rcBmpMax, FALSE ) ;
UpdateWindow( hWndShell ) ;
dwLastTime = dwCurrTime ;
}
} else if ( cAdvertIndex < 0 && cIndexLast >= 0 ) {
// Reset last cycle timer.
dwLastTime = dwFirstTime = 0 ;
// Reset largest BMP rectangle.
rcBmpMax.top =
rcBmpMax.left =
rcBmpMax.right =
rcBmpMax.bottom = -1 ;
}
cIndexLast = cAdvertIndex ;
}
VOID FPaintBmp ( HWND hwnd, HDC hdc )
{
HDC hdcBits;
BITMAP bm;
RECT rect ;
INT ix, iy ;
HDC hdcLocal = NULL ;
if ( hdc == NULL )
{
hdcLocal = hdc = GetDC( hwnd ) ;
if ( hdc == NULL )
return ;
}
GetClientRect( hwnd, & rect ) ;
ix = (rect.right - rect.left) / 100 ;
ix *= cxAdvert ;
iy = (rect.bottom - rect.top) / 100 ;
iy *= cyAdvert ;
hdcBits = CreateCompatibleDC( hdc ) ;
if (hdcBits) {
GetObject(hbmAdvertList[cAdvertIndex], sizeof (BITMAP), & bm ) ;
SelectObject( hdcBits, hbmAdvertList[cAdvertIndex] ) ;
BitBlt( hdc, ix, iy,
bm.bmWidth,
bm.bmHeight,
hdcBits,
0, 0, SRCCOPY ) ;
DeleteDC( hdcBits ) ;
}
if ( hdcLocal )
{
ReleaseDC( hwnd, hdcLocal ) ;
}
}
//
// NOTE: This function is NOT NOT NOT serially reentrant!
// It relies on the caller to free this module and then reload it
// in between calls!!!
//
BOOL
LegacyInfInterpret(
IN HWND OwnerWindow,
IN PCSTR InfFilename,
IN PCSTR InfSection, OPTIONAL
IN PCHAR ExtraVariables,
OUT PSTR InfResult,
IN DWORD BufferSize,
OUT int *InterpResult,
IN PCSTR InfSourceDir OPTIONAL
)
{
PSTR CommandLine;
PSTR ArgvLine;
PSTR ptr;
PSTR Source;
PSTR Sym;
PSTR Val;
PVOID p;
UINT Length;
UINT RequiredLength;
BOOL b;
int argvsize;
int argc;
char **argv;
CHAR Window[24];
#define CLINE_SIZE 32768
b = FALSE;
//
// Reentrancy control.
//
if(!EnterInterpreter()) {
return(FALSE);
}
//
// Initialize the buffer that may be used to contain list of services modified during
// this INF run. (This will only be used if !LEGACY_DODEVINSTALL is set.)
//
ServicesModified = NULL;
ServicesModifiedSize = 0;
//
// Allocate memory for the command line
//
CommandLine = SAlloc(CLINE_SIZE);
if(!CommandLine) {
return(FALSE);
}
CommandLine[0] = L'\0';
//
// Allocate memory for the "-s <filename>" part
//
Source = SAlloc(MAX_PATH + 5);
if(!Source) {
SFree(CommandLine);
return (FALSE);
}
Source[0] = L'\0';
if(IsWindow(OwnerWindow)) {
wsprintf(Window," -w %u",OwnerWindow);
} else {
Window[0] = 0;
Window[1] = 0;
}
if(InfSourceDir) {
_snprintf(
Source,
(MAX_PATH + 5),
" -s %s",
InfSourceDir);
}
//
// Create the minimum sized command line that need be parsed in an
// argc/argv format
//
_snprintf(
CommandLine,
CLINE_SIZE - 1,
"setup -f%s",
Window);
CommandLine[CLINE_SIZE-1] = 0;
//
// Create a dummy argv list -> required to be parse compatible with
// dll_main()
//
ArgvLine = SAlloc ( strlen(CommandLine) + 1 );
if(!ArgvLine) {
SFree(CommandLine);
SFree(Source);
return (FALSE);
}
//
// Allocate storage for the argv
//
argvsize = 8;
argv = SAlloc( argvsize * sizeof( char * ) );
if(!argv) {
SFree(CommandLine);
SFree(Source);
SFree(ArgvLine);
return (FALSE);
}
//
// Create the argv list
//
strcpy(ArgvLine,CommandLine);
ptr = ArgvLine;
argv[0] = ptr;
argc = 1;
while(*ptr != '\0') {
if(argc == argvsize) {
argvsize += 8;
argv = SRealloc( argv, argvsize * sizeof( char * ) );
if(!argv) {
SFree(CommandLine);
SFree(Source);
SFree(ArgvLine);
return (FALSE);
}
}
if(*ptr == ' ') {
while(*ptr == ' ') {
*ptr++ = '\0';
}
argv[argc++] = ptr;
} else {
ptr++;
}
}
//
// Create the real command line now. If the caller specified an inf section,
// then he wants to call a particular section in an inf, via legacy.inf.
// If the caller did not specify an inf section, then he wants to invoke
// [Shell Commands] in the given inf, directly (ie, not via legacy.inf).
//
_snprintf(
CommandLine,
CLINE_SIZE - 1,
"setup -f -i %s%s%s -t LEGACY_TARGET_INF = %s -t LEGACY_TARGET_SECTION = %s",
InfSection ? "legacy.inf" : InfFilename,
Window,
Source,
InfFilename,
InfSection ? InfSection : "\"Shell Commands\""
);
CommandLine[CLINE_SIZE-1] = 0;
//
// Now add the extra symbols to the command line.
//
Sym = ExtraVariables;
while(*Sym) {
Val = Sym + strlen(Sym) + 1;
Length = strlen(Sym) + strlen(Val) + 8;
if(strlen(CommandLine) + Length <= CLINE_SIZE) {
strcat(CommandLine," -t ");
strcat(CommandLine,Sym);
strcat(CommandLine," = ");
strcat(CommandLine,Val);
}
Sym = Val + strlen(Val) + 1;
}
//
// Set a global pointer to the area and size of the return buffer
//
LastShellReturn = InfResult;
LastShellReturnSize = BufferSize;
if(p = SRealloc(CommandLine,strlen(CommandLine)+1)) {
//
// OK, let 'er rip.
//
OwnProcess = FALSE;
CommandLine = p;
*InterpResult = real_dll_main(argc,argv,CommandLine);
b = TRUE;
}
//
// The caller is not going to call our LegacyInfGetModifiedSvcList() API
// if this routine returns failure. So we need to clean up the buffer now,
// if we failed.
//
if((!b || (*InterpResult != SETUP_ERROR_SUCCESS)) && ServicesModified) {
SFree(ServicesModified);
ServicesModified = NULL;
ServicesModifiedSize = 0;
}
LastShellReturn = NULL;
LastShellReturnSize = 0;
SFree(Source);
SFree(CommandLine);
return(b);
}
BOOL
EnterInterpreter(
VOID
)
{
static LONG InInterpreter = -1;
//
// The InInterpreter flag starts out at -1. The first increment
// makes it 0; subsequent increments make it > 0. Only the first
// increment will allow entry into the module.
//
return(InterlockedIncrement(&InInterpreter) == 0);
}