1023 lines
25 KiB
C
1023 lines
25 KiB
C
#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);
|
|
}
|