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.

216 lines
7.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Checks to see if the user has completely viewed the EULA before activing the accept/decline radio buttons
  4. //
  5. //=============================================================================//
  6. #include < windows.h >
  7. #include < msi.h >
  8. #include < msiquery.h >
  9. #include <tchar.h>
  10. #include <stdarg.h>
  11. #include <stdio.h>
  12. #include <commctrl.h>
  13. #define CHILD_WINDOW_OF_LICENSE "vHackLicenseWindowSibling092304"
  14. #define WINDOW_CLASS_OF_EULA_WINDOW "RichEdit20W"
  15. #define ALLOWABLE_POS_FROM_BOTTOM 5
  16. //-----------------------------------------------------------------------------
  17. // Purpose: Call back function for EnumChildWindows
  18. // Input : hwnd -
  19. // lParam -
  20. // Output : BOOL CALLBACK
  21. //-----------------------------------------------------------------------------
  22. BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)
  23. {
  24. TCHAR buf[100];
  25. GetClassName( hwnd, (LPTSTR)&buf, 100 );
  26. if ( _tcscmp( buf, _T( WINDOW_CLASS_OF_EULA_WINDOW ) ) == 0 )
  27. {
  28. *(HWND*)lParam = hwnd;
  29. return FALSE;
  30. }
  31. return TRUE;
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Purpose: Context for searching sub windows...
  35. //-----------------------------------------------------------------------------
  36. struct FindParams_t
  37. {
  38. HWND wnd;
  39. char searchtext[ 512 ];
  40. };
  41. //-----------------------------------------------------------------------------
  42. // Purpose:
  43. // Input : hwnd -
  44. // lParam -
  45. // Output : BOOL CALLBACK
  46. //-----------------------------------------------------------------------------
  47. BOOL CALLBACK EnumChildrenLookingForSpecialControl(HWND hwnd,LPARAM lParam)
  48. {
  49. FindParams_t *p = ( FindParams_t *)lParam;
  50. char buf[ 512 ];
  51. GetWindowText( hwnd, buf, sizeof( buf ) );
  52. if ( !stricmp( buf, p->searchtext ) )
  53. {
  54. p->wnd = hwnd;
  55. return FALSE;
  56. }
  57. return TRUE;
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose:
  61. // Input : hwnd -
  62. // lParam -
  63. // Output : BOOL CALLBACK
  64. //-----------------------------------------------------------------------------
  65. BOOL CALLBACK EnumChildWindowsProc(HWND hwnd, LPARAM lParam)
  66. {
  67. // Now search for the special hidden text control inside a top level window
  68. FindParams_t *p = ( FindParams_t *)lParam;
  69. FindParams_t special;
  70. memset( &special, 0, sizeof( special ) );
  71. strcpy( special.searchtext, p->searchtext );
  72. EnumChildWindows( hwnd, EnumChildrenLookingForSpecialControl, (LPARAM)&special );
  73. if ( special.wnd != NULL )
  74. {
  75. p->wnd = hwnd;
  76. return FALSE;
  77. }
  78. return TRUE;
  79. }
  80. //-----------------------------------------------------------------------------
  81. // 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.
  82. // e.g.:
  83. // 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
  84. // return the appropriate top level dialog.
  85. // Input : root -
  86. // *text -
  87. // Output : HWND
  88. //-----------------------------------------------------------------------------
  89. HWND FindWindowHavingChildWithSpecifiedText( HWND root, char const *text )
  90. {
  91. FindParams_t params;
  92. memset( &params, 0, sizeof( params ) );
  93. strncpy( params.searchtext, text, sizeof( params.searchtext ) - 1 );
  94. EnumChildWindows( root, EnumChildWindowsProc, (LPARAM)&params );
  95. return params.wnd;
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Purpose:
  99. // Input : *text -
  100. // Output : HWND
  101. //-----------------------------------------------------------------------------
  102. HWND FindTopLevelWindowHavingChildWithSpecifiedText( char const *text )
  103. {
  104. return FindWindowHavingChildWithSpecifiedText( GetDesktopWindow(), text );
  105. }
  106. //***********************************************************
  107. //** Custom action to check if the license is completly
  108. //** viewed.
  109. //**---------------------------------------------------------
  110. //** Return values:
  111. //** (1) Always returns success
  112. //** (2) Sets the private property LicenseViewed when
  113. //** the text is scrolled to near end.
  114. //**---------------------------------------------------------
  115. //** Usage:
  116. //** (1) Find installer window by looking for child with specified text. Can't
  117. //** just use window title because it's translated into foreign languages
  118. //** (2) In the license agreement dialog, on the scrollable
  119. //** text control event, call the custom action
  120. //** CheckLicenseViewed using a DoAction
  121. //** (3) For the Next button, modify the Enable
  122. //** ControlCondition to include the property
  123. //** LicenseViewed
  124. //**---------------------------------------------------------
  125. //***********************************************************
  126. // Needs to be exported as non-__stdcall with C name mangling (no mangling)
  127. extern "C" __declspec( dllexport ) UINT CheckLicenseViewed(MSIHANDLE hMSI)
  128. {
  129. HWND hWnd;
  130. HWND hWndChild=NULL;
  131. if (MsiEvaluateCondition(hMSI,"LicenseViewed")==MSICONDITION_FALSE)
  132. {
  133. hWnd = FindTopLevelWindowHavingChildWithSpecifiedText(CHILD_WINDOW_OF_LICENSE );
  134. if (hWnd)
  135. {
  136. EnumChildWindows( hWnd, EnumChildProc, (LPARAM)&hWndChild );
  137. if ( hWndChild )
  138. {
  139. SCROLLINFO sinfo;
  140. memset( &sinfo, 0, sizeof( sinfo ) );
  141. sinfo.cbSize=sizeof(sinfo);
  142. sinfo.fMask=SIF_TRACKPOS | SIF_RANGE | SIF_POS | SIF_PAGE;
  143. GetScrollInfo(hWndChild, SB_VERT, &sinfo);
  144. //max range depends on page size
  145. UINT MaxScrollPos = sinfo.nMax - ( sinfo.nPage - 1 );
  146. //max less, say ALLOWABLE_POS_FROM_BOTTOM - an allowable max.
  147. MaxScrollPos = MaxScrollPos - ALLOWABLE_POS_FROM_BOTTOM;
  148. // THIS IS A HACK, but the RichEdit20W control has a bug where while the thumb is being dragged, the position doesn't
  149. // get updated. In fact, it doesn't get updated until the next time
  150. UINT nScrollPos = ::SendMessage(hWndChild, EM_GETTHUMB, 0, 0);
  151. bool trackedPastEnd = false; // (UINT)sinfo.nTrackPos >= MaxScrollPos ? true : false;
  152. bool positionedPastEnd = nScrollPos >= MaxScrollPos ? true : false;
  153. // Note above, this method doesn't always work... but maybe it will work in win98 and the other won't, etc. etc.
  154. bool positionedPastEnd2 = (UINT)sinfo.nPos >= MaxScrollPos ? true : false;
  155. /*
  156. HDC dc = GetDC( GetDesktopWindow() );
  157. COLORREF oldColor = SetTextColor( dc, RGB( 255, 0, 0 ) );
  158. char sz[ 256 ];
  159. _snprintf( sz, sizeof( sz ), "max %i page %i msp %i track %u pos %u pos2 %u",
  160. sinfo.nMax,
  161. sinfo.nPage,
  162. MaxScrollPos,
  163. sinfo.nTrackPos,
  164. sinfo.nPos,
  165. nScrollPos );
  166. RECT rc;
  167. rc.left = 0;
  168. rc.right = 1000;
  169. rc.top = 20;
  170. rc.bottom = 50;
  171. DrawText( dc, sz, -1, &rc, DT_NOPREFIX );
  172. SetTextColor( dc, oldColor );
  173. ReleaseDC( GetDesktopWindow(), dc );
  174. */
  175. if ( trackedPastEnd || positionedPastEnd || positionedPastEnd2 )
  176. {
  177. MsiSetProperty(hMSI, TEXT("LicenseViewed"), TEXT("1"));
  178. }
  179. else
  180. {
  181. MsiSetProperty(hMSI, TEXT("LicenseViewed"), NULL);
  182. }
  183. }
  184. }
  185. }
  186. return ERROR_SUCCESS;
  187. }