summaryrefslogtreecommitdiff
path: root/devtools/WiseInstallerHelpers
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/WiseInstallerHelpers')
-rw-r--r--devtools/WiseInstallerHelpers/LicenseViewed.cpp217
-rw-r--r--devtools/WiseInstallerHelpers/LicenseViewed.vpc31
-rw-r--r--devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.cpp460
-rw-r--r--devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.vpc18
4 files changed, 726 insertions, 0 deletions
diff --git a/devtools/WiseInstallerHelpers/LicenseViewed.cpp b/devtools/WiseInstallerHelpers/LicenseViewed.cpp
new file mode 100644
index 0000000..037c26d
--- /dev/null
+++ b/devtools/WiseInstallerHelpers/LicenseViewed.cpp
@@ -0,0 +1,217 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Checks to see if the user has completely viewed the EULA before activing the accept/decline radio buttons
+//
+//=============================================================================//
+#include < windows.h >
+#include < msi.h >
+#include < msiquery.h >
+#include <tchar.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <commctrl.h>
+
+#define CHILD_WINDOW_OF_LICENSE "vHackLicenseWindowSibling092304"
+#define WINDOW_CLASS_OF_EULA_WINDOW "RichEdit20W"
+#define ALLOWABLE_POS_FROM_BOTTOM 5
+
+//-----------------------------------------------------------------------------
+// Purpose: Call back function for EnumChildWindows
+// Input : hwnd -
+// lParam -
+// Output : BOOL CALLBACK
+//-----------------------------------------------------------------------------
+BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)
+{
+ TCHAR buf[100];
+
+ GetClassName( hwnd, (LPTSTR)&buf, 100 );
+ if ( _tcscmp( buf, _T( WINDOW_CLASS_OF_EULA_WINDOW ) ) == 0 )
+ {
+ *(HWND*)lParam = hwnd;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Context for searching sub windows...
+//-----------------------------------------------------------------------------
+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: Finds given a root window, finds a child window which itself has a special child window with the specified text string as the window title.
+// e.g.:
+// if root == NULL (desktop), then you can search the top level dialogs (Half-Life 2 Setup,e.g.) for a subwindow with "vHackxxx" as the text, this would
+// return the appropriate top level dialog.
+// 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 );
+}
+
+
+//***********************************************************
+//** Custom action to check if the license is completly
+//** viewed.
+//**---------------------------------------------------------
+//** Return values:
+//** (1) Always returns success
+//** (2) Sets the private property LicenseViewed when
+//** the text is scrolled to near end.
+//**---------------------------------------------------------
+//** Usage:
+//** (1) Find installer window by looking for child with specified text. Can't
+//** just use window title because it's translated into foreign languages
+//** (2) In the license agreement dialog, on the scrollable
+//** text control event, call the custom action
+//** CheckLicenseViewed using a DoAction
+//** (3) For the Next button, modify the Enable
+//** ControlCondition to include the property
+//** LicenseViewed
+//**---------------------------------------------------------
+//***********************************************************
+
+// Needs to be exported as non-__stdcall with C name mangling (no mangling)
+extern "C" __declspec( dllexport ) UINT CheckLicenseViewed(MSIHANDLE hMSI)
+{
+ HWND hWnd;
+ HWND hWndChild=NULL;
+
+ if (MsiEvaluateCondition(hMSI,"LicenseViewed")==MSICONDITION_FALSE)
+ {
+ hWnd = FindTopLevelWindowHavingChildWithSpecifiedText(CHILD_WINDOW_OF_LICENSE );
+ if (hWnd)
+ {
+ EnumChildWindows( hWnd, EnumChildProc, (LPARAM)&hWndChild );
+ if ( hWndChild )
+ {
+ SCROLLINFO sinfo;
+ memset( &sinfo, 0, sizeof( sinfo ) );
+ sinfo.cbSize=sizeof(sinfo);
+ sinfo.fMask=SIF_TRACKPOS | SIF_RANGE | SIF_POS | SIF_PAGE;
+ GetScrollInfo(hWndChild, SB_VERT, &sinfo);
+ //max range depends on page size
+ UINT MaxScrollPos = sinfo.nMax - ( sinfo.nPage - 1 );
+ //max less, say ALLOWABLE_POS_FROM_BOTTOM - an allowable max.
+ MaxScrollPos = MaxScrollPos - ALLOWABLE_POS_FROM_BOTTOM;
+
+ // THIS IS A HACK, but the RichEdit20W control has a bug where while the thumb is being dragged, the position doesn't
+ // get updated. In fact, it doesn't get updated until the next time
+ UINT nScrollPos = ::SendMessage(hWndChild, EM_GETTHUMB, 0, 0);
+
+ bool trackedPastEnd = false; // (UINT)sinfo.nTrackPos >= MaxScrollPos ? true : false;
+ bool positionedPastEnd = nScrollPos >= MaxScrollPos ? true : false;
+ // Note above, this method doesn't always work... but maybe it will work in win98 and the other won't, etc. etc.
+ bool positionedPastEnd2 = (UINT)sinfo.nPos >= MaxScrollPos ? true : false;
+
+ /*
+
+ HDC dc = GetDC( GetDesktopWindow() );
+ COLORREF oldColor = SetTextColor( dc, RGB( 255, 0, 0 ) );
+
+ char sz[ 256 ];
+ _snprintf( sz, sizeof( sz ), "max %i page %i msp %i track %u pos %u pos2 %u",
+ sinfo.nMax,
+ sinfo.nPage,
+ MaxScrollPos,
+ sinfo.nTrackPos,
+ sinfo.nPos,
+ nScrollPos );
+
+ RECT rc;
+ rc.left = 0;
+ rc.right = 1000;
+ rc.top = 20;
+ rc.bottom = 50;
+
+ DrawText( dc, sz, -1, &rc, DT_NOPREFIX );
+
+ SetTextColor( dc, oldColor );
+ ReleaseDC( GetDesktopWindow(), dc );
+ */
+
+ if ( trackedPastEnd || positionedPastEnd || positionedPastEnd2 )
+ {
+ MsiSetProperty(hMSI, TEXT("LicenseViewed"), TEXT("1"));
+ }
+ else
+ {
+ MsiSetProperty(hMSI, TEXT("LicenseViewed"), NULL);
+ }
+ }
+ }
+ }
+ return ERROR_SUCCESS;
+} \ No newline at end of file
diff --git a/devtools/WiseInstallerHelpers/LicenseViewed.vpc b/devtools/WiseInstallerHelpers/LicenseViewed.vpc
new file mode 100644
index 0000000..7f9d36e
--- /dev/null
+++ b/devtools/WiseInstallerHelpers/LicenseViewed.vpc
@@ -0,0 +1,31 @@
+//-----------------------------------------------------------------------------
+// LICENSEVIEWED.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $PreprocessorDefinitions "$BASE;LicenseViewed_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE msi.lib odbc32.lib odbccp32.lib"
+ }
+}
+
+$Project "LicenseViewed"
+{
+ $Folder "Source Files"
+ {
+ $File "LicenseViewed.cpp"
+ }
+}
diff --git a/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.cpp b/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.cpp
new file mode 100644
index 0000000..f00f413
--- /dev/null
+++ b/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.cpp
@@ -0,0 +1,460 @@
+//========= 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;
+}
+
+
+
diff --git a/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.vpc b/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.vpc
new file mode 100644
index 0000000..1527322
--- /dev/null
+++ b/devtools/WiseInstallerHelpers/UpdateProgress/UpdateProgress.vpc
@@ -0,0 +1,18 @@
+//-----------------------------------------------------------------------------
+// UPDATEPROGRESS.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\..\.."
+$Macro OUTBINDIR "$SRCDIR\devtools\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc"
+
+$Project "UpdateProgress"
+{
+ $Folder "Source Files"
+ {
+ $File "UpdateProgress.cpp"
+ }
+}