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.
217 lines
7.0 KiB
217 lines
7.0 KiB
5 years ago
|
//========= 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( ¶ms, 0, sizeof( params ) );
|
||
|
|
||
|
strncpy( params.searchtext, text, sizeof( params.searchtext ) - 1 );
|
||
|
|
||
|
EnumChildWindows( root, EnumChildWindowsProc, (LPARAM)¶ms );
|
||
|
|
||
|
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;
|
||
|
}
|