source-engine/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

461 lines
12 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A simple app which looks for the HL2 wise installer and ticks the progress bar due
// to a bug with installing more than 2GB of data using the current ver of the windows installer
//
//=============================================================================//
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <commctrl.h>
#include <stdlib.h>
#define FIND_WINDOW_TEXT_PROGRESSDIALOG "vHackWiseProgressDialog092304"
#define FIND_WINDOW_TEXT_CHANGEDISKDIALOG "vHackWiseProgressDialogChangeCD092304"
#define FIND_WINDOW_TEXT_CANCELDIALOG "vHackWiseProgressDialogCancel092304"
static char szAppName[] = "vWiseProgressBarHackWndClass";
// The full bar is this many ticks (which are about 100 msec apart, so 30 seconds to walk bar
#define PROGRESS_TICKS 75
#define PROGRESS_WAIT_TICKS 20
// After this long, if we didn't find the setup dialog, exit the application
#define SEARCH_TIMEOUT_SECONDS 60
#define WISE_PROGRESS_BAR_WINDOW_CLASS "msctls_progress32"
//-----------------------------------------------------------------------------
// Purpose: Globals
//-----------------------------------------------------------------------------
struct Globals_t
{
DWORD m_nLastThink;
DWORD m_nStartTick;
bool m_bFoundWindow;
HWND m_hProgressBar;
HWND m_hDialog;
UINT m_nTickCounter;
};
static Globals_t g;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
struct FindParams_t
{
HWND wnd;
char searchtext[ 512 ];
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : hwnd -
// lParam -
// Output : BOOL CALLBACK
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumChildrenLookingForSpecialControl(HWND hwnd,LPARAM lParam)
{
FindParams_t *p = ( FindParams_t *)lParam;
char buf[ 512 ];
GetWindowText( hwnd, buf, sizeof( buf ) );
if ( !stricmp( buf, p->searchtext ) )
{
p->wnd = hwnd;
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : hwnd -
// lParam -
// Output : BOOL CALLBACK
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumChildWindowsProc(HWND hwnd, LPARAM lParam)
{
// Now search for the special hidden text control inside a top level window
FindParams_t *p = ( FindParams_t *)lParam;
FindParams_t special;
memset( &special, 0, sizeof( special ) );
strcpy( special.searchtext, p->searchtext );
EnumChildWindows( hwnd, EnumChildrenLookingForSpecialControl, (LPARAM)&special );
if ( special.wnd != NULL )
{
p->wnd = hwnd;
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : root -
// *text -
// Output : HWND
//-----------------------------------------------------------------------------
HWND FindWindowHavingChildWithSpecifiedText( HWND root, char const *text )
{
FindParams_t params;
memset( &params, 0, sizeof( params ) );
strncpy( params.searchtext, text, sizeof( params.searchtext ) - 1 );
EnumChildWindows( root, EnumChildWindowsProc, (LPARAM)&params );
return params.wnd;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *text -
// Output : HWND
//-----------------------------------------------------------------------------
HWND FindTopLevelWindowHavingChildWithSpecifiedText( char const *text )
{
return FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), text );
}
//-----------------------------------------------------------------------------
// Purpose: Search for window of class WISE_PROGRESS_BAR_WINDOW_CLASS
// Input : hwnd -
// lParam -
// Output : BOOL CALLBACK
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumFindProgressBarInDialog( HWND hwnd,LPARAM lParam )
{
char buf[100];
GetClassName( hwnd, buf, sizeof( buf ) );
if ( !stricmp( buf, WISE_PROGRESS_BAR_WINDOW_CLASS ) )
{
*(HWND*)lParam = hwnd;
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Purpose: Hides the window
// Input : visible -
//-----------------------------------------------------------------------------
void ShowProgressBar( bool visible )
{
if ( !g.m_hProgressBar )
return;
DWORD style = GetWindowLong( g.m_hProgressBar, GWL_STYLE );
if ( visible )
{
style |= WS_VISIBLE;
}
else
{
style &= ~WS_VISIBLE;
}
SetWindowLong( g.m_hProgressBar, GWL_STYLE, style );
InvalidateRect( g.m_hDialog, NULL, TRUE );
}
//-----------------------------------------------------------------------------
// Purpose: Search for the progress dialog
//-----------------------------------------------------------------------------
void SearchForWindow()
{
HWND hProgressDialog = FindTopLevelWindowHavingChildWithSpecifiedText( FIND_WINDOW_TEXT_PROGRESSDIALOG );
if ( !hProgressDialog )
{
return;
}
HWND hWndChild = NULL;
EnumChildWindows( hProgressDialog, EnumFindProgressBarInDialog, (LPARAM)&hWndChild );
if ( !hWndChild )
return;
g.m_bFoundWindow = true;
g.m_hProgressBar = hWndChild;
g.m_hDialog = hProgressDialog;
// Hide the progress bar on the dialog since we'll be drawing our own
ShowProgressBar( false );
}
void DrawProgressBar( HDC dc, bool showTicks, float frac )
{
// Get progress bar rectangle
RECT rc;
GetClientRect( g.m_hProgressBar, &rc );
//InflateRect( &rc, 2, 2 );
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
HDC dcMemory = CreateCompatibleDC( dc );
HBITMAP bmMemory = CreateCompatibleBitmap( dc, w, h );
HBITMAP bmOld = (HBITMAP)SelectObject( dcMemory, bmMemory );
{
HBRUSH clearColor = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
FillRect( dcMemory, &rc, clearColor );
// Create blue tick brush
HBRUSH br = CreateSolidBrush( RGB( 2, 62, 134 ) );
// Create background brush of same color as dialog background
HBRUSH bg = CreateSolidBrush( RGB( 153, 175, 199) );
// Create a black / shadow colored pen to frame the progress bar
HPEN blackpen;
blackpen = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_BTNSHADOW ) );
// Select items into dcMemory
HPEN oldPen = (HPEN)SelectObject( dcMemory, blackpen );
HBRUSH oldBrush = (HBRUSH)SelectObject( dcMemory, bg );
rc.bottom = rc.top + 15;
RoundRect( dcMemory, rc.left, rc.top, rc.right, rc.bottom, 5, 5 );
// Inset by one unit
InflateRect( &rc, -1, -1 );
if ( showTicks )
{
HRGN clipRegion = (HRGN)CreateRectRgn( rc.left+1, rc.top, rc.right-1, rc.bottom );;
SelectClipRgn( dcMemory, clipRegion );
int numblocks = 8;
int blockwidth = 6;
int blockgap = 2;
int size = numblocks * ( blockwidth + blockgap );
// Determine width of progress bar work area
int width = rc.right - rc.left + 2 * size;
// Compute right edge of progress bar
RECT rcProgress = rc;
rcProgress.right = rcProgress.left - size + ( int )( frac * width + 0.5f );
rcProgress.left = rcProgress.right - size;
for ( int block = 0; block < numblocks; ++block )
{
RECT rcBlock;
rcBlock.left = rcProgress.left + block * ( blockwidth + blockgap );
rcBlock.right = rcBlock.left + blockwidth;
rcBlock.top = rcProgress.top + 1;
rcBlock.bottom = rcProgress.bottom - 1;
// Fill in progress bar
FillRect( dcMemory, &rcBlock, br );
}
SelectClipRgn( dcMemory, NULL );
DeleteObject( clipRegion );
}
// Restore GDI states
SelectObject( dcMemory, oldBrush );
SelectObject( dcMemory, oldPen );
DeleteObject( blackpen );
DeleteObject( bg );
DeleteObject( br );
DeleteObject( clearColor );
}
POINT pt;
pt.x = pt.y = 0;
// Convert top left of progress bar to screen space
ClientToScreen( g.m_hProgressBar, &pt );
// and then back to dialog relative space
ScreenToClient( g.m_hDialog, &pt );
// Offset the progress bar rect to the right position in the dialog
OffsetRect( &rc, pt.x, pt.y );
BitBlt( dc, rc.left, rc.top, w, h, dcMemory, 0, 0, SRCCOPY );
SelectObject( dcMemory, bmOld );
DeleteObject( bmMemory );
DeleteObject( dcMemory );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void UpdateProgress()
{
// If the "Insert next CD" or "Exit Setup" dialogs are showing, stop advancing the progress bar
HWND hSwapDiskDialog = FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), FIND_WINDOW_TEXT_CHANGEDISKDIALOG );
HWND hCancelDialog = FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), FIND_WINDOW_TEXT_CANCELDIALOG );
if ( !hSwapDiskDialog && !hCancelDialog )
{
g.m_nTickCounter++;
}
if ( !g.m_hProgressBar || !g.m_hDialog )
return;
int remainder = ( g.m_nTickCounter % PROGRESS_TICKS );
bool showTicks = ( remainder <= PROGRESS_WAIT_TICKS ) ? false : true;
int currentTick = max( 0, remainder - PROGRESS_WAIT_TICKS );
int totalTicks = PROGRESS_TICKS - PROGRESS_WAIT_TICKS;
float frac = ( float )( currentTick % totalTicks ) / ( float )( totalTicks - 1 );
HDC dc = GetDC( g.m_hDialog );
{
// Draw the progress bar
DrawProgressBar( dc, showTicks, frac );
}
ReleaseDC( g.m_hDialog, dc );
}
//-----------------------------------------------------------------------------
// Purpose: Either searches for window or updates progress
// The app will quit if the dialog is found and then goes away
// The app wil also quit if the dialog was not found after waiting 60 seconds
//-----------------------------------------------------------------------------
void Think()
{
// Only think once every 100 msec
DWORD curTick = GetTickCount();
if ( curTick - g.m_nLastThink < 50 )
{
return;
}
g.m_nLastThink = curTick;
// Haven't found window yet, keep searching
if ( !g.m_bFoundWindow )
{
SearchForWindow();
// Wise never got going..., abort this app...
if ( ( curTick - g.m_nStartTick ) > ( SEARCH_TIMEOUT_SECONDS * 1000 ) )
{
PostQuitMessage( 0 );
}
}
else
{
// Only redraw progress once every 100 msec
UpdateProgress();
// If the progress dialog does away, exit this app immediately
if ( !IsWindow( g.m_hDialog ) )
{
PostQuitMessage( 0 );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Main entry point
// Input : hInstance -
// hPrevInstance -
// nCmdShow -
// Output : int APIENTRY
//-----------------------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hwnd ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = DefWindowProc;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if ( !RegisterClass (&wndclass) )
{
return 0 ;
}
hwnd = CreateWindow
(
szAppName,
TEXT (""),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL
);
if (!hwnd)
return 0 ;
ShowWindow( hwnd, SW_HIDE ) ;
// Remember when we started
g.m_nStartTick = GetTickCount();
bool done = false;
while ( 1 )
{
MSG msg;
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if ( msg.message == WM_QUIT )
{
done = true;
break;
}
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
if ( done )
break;
Think();
Sleep( 20 );
}
// Restore progress bar as needed
ShowProgressBar( true );
return 0;
}