Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

460 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A simple app which looks for the HL2 wise installer and ticks the progress bar due
  4. // to a bug with installing more than 2GB of data using the current ver of the windows installer
  5. //
  6. //=============================================================================//
  7. #include <windows.h>
  8. #include <stdarg.h>
  9. #include <stdio.h>
  10. #include <commctrl.h>
  11. #include <stdlib.h>
  12. #define FIND_WINDOW_TEXT_PROGRESSDIALOG "vHackWiseProgressDialog092304"
  13. #define FIND_WINDOW_TEXT_CHANGEDISKDIALOG "vHackWiseProgressDialogChangeCD092304"
  14. #define FIND_WINDOW_TEXT_CANCELDIALOG "vHackWiseProgressDialogCancel092304"
  15. static char szAppName[] = "vWiseProgressBarHackWndClass";
  16. // The full bar is this many ticks (which are about 100 msec apart, so 30 seconds to walk bar
  17. #define PROGRESS_TICKS 75
  18. #define PROGRESS_WAIT_TICKS 20
  19. // After this long, if we didn't find the setup dialog, exit the application
  20. #define SEARCH_TIMEOUT_SECONDS 60
  21. #define WISE_PROGRESS_BAR_WINDOW_CLASS "msctls_progress32"
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Globals
  24. //-----------------------------------------------------------------------------
  25. struct Globals_t
  26. {
  27. DWORD m_nLastThink;
  28. DWORD m_nStartTick;
  29. bool m_bFoundWindow;
  30. HWND m_hProgressBar;
  31. HWND m_hDialog;
  32. UINT m_nTickCounter;
  33. };
  34. static Globals_t g;
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. //-----------------------------------------------------------------------------
  38. struct FindParams_t
  39. {
  40. HWND wnd;
  41. char searchtext[ 512 ];
  42. };
  43. //-----------------------------------------------------------------------------
  44. // Purpose:
  45. // Input : hwnd -
  46. // lParam -
  47. // Output : BOOL CALLBACK
  48. //-----------------------------------------------------------------------------
  49. BOOL CALLBACK EnumChildrenLookingForSpecialControl(HWND hwnd,LPARAM lParam)
  50. {
  51. FindParams_t *p = ( FindParams_t *)lParam;
  52. char buf[ 512 ];
  53. GetWindowText( hwnd, buf, sizeof( buf ) );
  54. if ( !stricmp( buf, p->searchtext ) )
  55. {
  56. p->wnd = hwnd;
  57. return FALSE;
  58. }
  59. return TRUE;
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose:
  63. // Input : hwnd -
  64. // lParam -
  65. // Output : BOOL CALLBACK
  66. //-----------------------------------------------------------------------------
  67. BOOL CALLBACK EnumChildWindowsProc(HWND hwnd, LPARAM lParam)
  68. {
  69. // Now search for the special hidden text control inside a top level window
  70. FindParams_t *p = ( FindParams_t *)lParam;
  71. FindParams_t special;
  72. memset( &special, 0, sizeof( special ) );
  73. strcpy( special.searchtext, p->searchtext );
  74. EnumChildWindows( hwnd, EnumChildrenLookingForSpecialControl, (LPARAM)&special );
  75. if ( special.wnd != NULL )
  76. {
  77. p->wnd = hwnd;
  78. return FALSE;
  79. }
  80. return TRUE;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose:
  84. // Input : root -
  85. // *text -
  86. // Output : HWND
  87. //-----------------------------------------------------------------------------
  88. HWND FindWindowHavingChildWithSpecifiedText( HWND root, char const *text )
  89. {
  90. FindParams_t params;
  91. memset( &params, 0, sizeof( params ) );
  92. strncpy( params.searchtext, text, sizeof( params.searchtext ) - 1 );
  93. EnumChildWindows( root, EnumChildWindowsProc, (LPARAM)&params );
  94. return params.wnd;
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. // Input : *text -
  99. // Output : HWND
  100. //-----------------------------------------------------------------------------
  101. HWND FindTopLevelWindowHavingChildWithSpecifiedText( char const *text )
  102. {
  103. return FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), text );
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Search for window of class WISE_PROGRESS_BAR_WINDOW_CLASS
  107. // Input : hwnd -
  108. // lParam -
  109. // Output : BOOL CALLBACK
  110. //-----------------------------------------------------------------------------
  111. BOOL CALLBACK EnumFindProgressBarInDialog( HWND hwnd,LPARAM lParam )
  112. {
  113. char buf[100];
  114. GetClassName( hwnd, buf, sizeof( buf ) );
  115. if ( !stricmp( buf, WISE_PROGRESS_BAR_WINDOW_CLASS ) )
  116. {
  117. *(HWND*)lParam = hwnd;
  118. return FALSE;
  119. }
  120. return TRUE;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Hides the window
  124. // Input : visible -
  125. //-----------------------------------------------------------------------------
  126. void ShowProgressBar( bool visible )
  127. {
  128. if ( !g.m_hProgressBar )
  129. return;
  130. DWORD style = GetWindowLong( g.m_hProgressBar, GWL_STYLE );
  131. if ( visible )
  132. {
  133. style |= WS_VISIBLE;
  134. }
  135. else
  136. {
  137. style &= ~WS_VISIBLE;
  138. }
  139. SetWindowLong( g.m_hProgressBar, GWL_STYLE, style );
  140. InvalidateRect( g.m_hDialog, NULL, TRUE );
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Purpose: Search for the progress dialog
  144. //-----------------------------------------------------------------------------
  145. void SearchForWindow()
  146. {
  147. HWND hProgressDialog = FindTopLevelWindowHavingChildWithSpecifiedText( FIND_WINDOW_TEXT_PROGRESSDIALOG );
  148. if ( !hProgressDialog )
  149. {
  150. return;
  151. }
  152. HWND hWndChild = NULL;
  153. EnumChildWindows( hProgressDialog, EnumFindProgressBarInDialog, (LPARAM)&hWndChild );
  154. if ( !hWndChild )
  155. return;
  156. g.m_bFoundWindow = true;
  157. g.m_hProgressBar = hWndChild;
  158. g.m_hDialog = hProgressDialog;
  159. // Hide the progress bar on the dialog since we'll be drawing our own
  160. ShowProgressBar( false );
  161. }
  162. void DrawProgressBar( HDC dc, bool showTicks, float frac )
  163. {
  164. // Get progress bar rectangle
  165. RECT rc;
  166. GetClientRect( g.m_hProgressBar, &rc );
  167. //InflateRect( &rc, 2, 2 );
  168. int w = rc.right - rc.left;
  169. int h = rc.bottom - rc.top;
  170. HDC dcMemory = CreateCompatibleDC( dc );
  171. HBITMAP bmMemory = CreateCompatibleBitmap( dc, w, h );
  172. HBITMAP bmOld = (HBITMAP)SelectObject( dcMemory, bmMemory );
  173. {
  174. HBRUSH clearColor = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
  175. FillRect( dcMemory, &rc, clearColor );
  176. // Create blue tick brush
  177. HBRUSH br = CreateSolidBrush( RGB( 2, 62, 134 ) );
  178. // Create background brush of same color as dialog background
  179. HBRUSH bg = CreateSolidBrush( RGB( 153, 175, 199) );
  180. // Create a black / shadow colored pen to frame the progress bar
  181. HPEN blackpen;
  182. blackpen = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_BTNSHADOW ) );
  183. // Select items into dcMemory
  184. HPEN oldPen = (HPEN)SelectObject( dcMemory, blackpen );
  185. HBRUSH oldBrush = (HBRUSH)SelectObject( dcMemory, bg );
  186. rc.bottom = rc.top + 15;
  187. RoundRect( dcMemory, rc.left, rc.top, rc.right, rc.bottom, 5, 5 );
  188. // Inset by one unit
  189. InflateRect( &rc, -1, -1 );
  190. if ( showTicks )
  191. {
  192. HRGN clipRegion = (HRGN)CreateRectRgn( rc.left+1, rc.top, rc.right-1, rc.bottom );;
  193. SelectClipRgn( dcMemory, clipRegion );
  194. int numblocks = 8;
  195. int blockwidth = 6;
  196. int blockgap = 2;
  197. int size = numblocks * ( blockwidth + blockgap );
  198. // Determine width of progress bar work area
  199. int width = rc.right - rc.left + 2 * size;
  200. // Compute right edge of progress bar
  201. RECT rcProgress = rc;
  202. rcProgress.right = rcProgress.left - size + ( int )( frac * width + 0.5f );
  203. rcProgress.left = rcProgress.right - size;
  204. for ( int block = 0; block < numblocks; ++block )
  205. {
  206. RECT rcBlock;
  207. rcBlock.left = rcProgress.left + block * ( blockwidth + blockgap );
  208. rcBlock.right = rcBlock.left + blockwidth;
  209. rcBlock.top = rcProgress.top + 1;
  210. rcBlock.bottom = rcProgress.bottom - 1;
  211. // Fill in progress bar
  212. FillRect( dcMemory, &rcBlock, br );
  213. }
  214. SelectClipRgn( dcMemory, NULL );
  215. DeleteObject( clipRegion );
  216. }
  217. // Restore GDI states
  218. SelectObject( dcMemory, oldBrush );
  219. SelectObject( dcMemory, oldPen );
  220. DeleteObject( blackpen );
  221. DeleteObject( bg );
  222. DeleteObject( br );
  223. DeleteObject( clearColor );
  224. }
  225. POINT pt;
  226. pt.x = pt.y = 0;
  227. // Convert top left of progress bar to screen space
  228. ClientToScreen( g.m_hProgressBar, &pt );
  229. // and then back to dialog relative space
  230. ScreenToClient( g.m_hDialog, &pt );
  231. // Offset the progress bar rect to the right position in the dialog
  232. OffsetRect( &rc, pt.x, pt.y );
  233. BitBlt( dc, rc.left, rc.top, w, h, dcMemory, 0, 0, SRCCOPY );
  234. SelectObject( dcMemory, bmOld );
  235. DeleteObject( bmMemory );
  236. DeleteObject( dcMemory );
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. //-----------------------------------------------------------------------------
  241. void UpdateProgress()
  242. {
  243. // If the "Insert next CD" or "Exit Setup" dialogs are showing, stop advancing the progress bar
  244. HWND hSwapDiskDialog = FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), FIND_WINDOW_TEXT_CHANGEDISKDIALOG );
  245. HWND hCancelDialog = FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), FIND_WINDOW_TEXT_CANCELDIALOG );
  246. if ( !hSwapDiskDialog && !hCancelDialog )
  247. {
  248. g.m_nTickCounter++;
  249. }
  250. if ( !g.m_hProgressBar || !g.m_hDialog )
  251. return;
  252. int remainder = ( g.m_nTickCounter % PROGRESS_TICKS );
  253. bool showTicks = ( remainder <= PROGRESS_WAIT_TICKS ) ? false : true;
  254. int currentTick = max( 0, remainder - PROGRESS_WAIT_TICKS );
  255. int totalTicks = PROGRESS_TICKS - PROGRESS_WAIT_TICKS;
  256. float frac = ( float )( currentTick % totalTicks ) / ( float )( totalTicks - 1 );
  257. HDC dc = GetDC( g.m_hDialog );
  258. {
  259. // Draw the progress bar
  260. DrawProgressBar( dc, showTicks, frac );
  261. }
  262. ReleaseDC( g.m_hDialog, dc );
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose: Either searches for window or updates progress
  266. // The app will quit if the dialog is found and then goes away
  267. // The app wil also quit if the dialog was not found after waiting 60 seconds
  268. //-----------------------------------------------------------------------------
  269. void Think()
  270. {
  271. // Only think once every 100 msec
  272. DWORD curTick = GetTickCount();
  273. if ( curTick - g.m_nLastThink < 50 )
  274. {
  275. return;
  276. }
  277. g.m_nLastThink = curTick;
  278. // Haven't found window yet, keep searching
  279. if ( !g.m_bFoundWindow )
  280. {
  281. SearchForWindow();
  282. // Wise never got going..., abort this app...
  283. if ( ( curTick - g.m_nStartTick ) > ( SEARCH_TIMEOUT_SECONDS * 1000 ) )
  284. {
  285. PostQuitMessage( 0 );
  286. }
  287. }
  288. else
  289. {
  290. // Only redraw progress once every 100 msec
  291. UpdateProgress();
  292. // If the progress dialog does away, exit this app immediately
  293. if ( !IsWindow( g.m_hDialog ) )
  294. {
  295. PostQuitMessage( 0 );
  296. }
  297. }
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose: Main entry point
  301. // Input : hInstance -
  302. // hPrevInstance -
  303. // nCmdShow -
  304. // Output : int APIENTRY
  305. //-----------------------------------------------------------------------------
  306. int APIENTRY WinMain(HINSTANCE hInstance,
  307. HINSTANCE hPrevInstance,
  308. LPSTR lpCmdLine,
  309. int nCmdShow)
  310. {
  311. HWND hwnd ;
  312. WNDCLASS wndclass ;
  313. wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  314. wndclass.lpfnWndProc = DefWindowProc;
  315. wndclass.cbClsExtra = 0 ;
  316. wndclass.cbWndExtra = 0 ;
  317. wndclass.hInstance = hInstance ;
  318. wndclass.hIcon = NULL;
  319. wndclass.hCursor = NULL;
  320. wndclass.hbrBackground = NULL;
  321. wndclass.lpszMenuName = NULL ;
  322. wndclass.lpszClassName = szAppName ;
  323. if ( !RegisterClass (&wndclass) )
  324. {
  325. return 0 ;
  326. }
  327. hwnd = CreateWindow
  328. (
  329. szAppName,
  330. TEXT (""),
  331. WS_OVERLAPPEDWINDOW,
  332. CW_USEDEFAULT, CW_USEDEFAULT,
  333. CW_USEDEFAULT, CW_USEDEFAULT,
  334. NULL, NULL, hInstance, NULL
  335. );
  336. if (!hwnd)
  337. return 0 ;
  338. ShowWindow( hwnd, SW_HIDE ) ;
  339. // Remember when we started
  340. g.m_nStartTick = GetTickCount();
  341. bool done = false;
  342. while ( 1 )
  343. {
  344. MSG msg;
  345. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  346. {
  347. if ( msg.message == WM_QUIT )
  348. {
  349. done = true;
  350. break;
  351. }
  352. TranslateMessage (&msg) ;
  353. DispatchMessage (&msg) ;
  354. }
  355. if ( done )
  356. break;
  357. Think();
  358. Sleep( 20 );
  359. }
  360. // Restore progress bar as needed
  361. ShowProgressBar( true );
  362. return 0;
  363. }