/***************************************************************************** * * DIApHack.c * * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Support routines for app hacks * * Contents: * *****************************************************************************/ #include "dinputpr.h" /***************************************************************************** * * The sqiffle for this file. * *****************************************************************************/ //ISSUE-2001/03/29-timgill Need to sort out a prefixed version of of SquirtSqflPtszV TCHAR c_tszPrefix[]=TEXT("DINPUT: "); #define sqfl sqflCompat typedef enum { DICOMPATID_REACQUIRE, // Perform auto reaquire if device lost DICOMPATID_NOSUBCLASS, // Do not use subclassing DICOMPATID_MAXDEVICENAMELENGTH, // Truncate device names DICOMPATID_NATIVEAXISONLY, // Always report axis data in native mode DICOMPATID_NOPOLLUNACQUIRE, // Don't unaquire the device if a poll fails DICOMPATID_SUCCEEDACQUIRE // Always return a success code for calls to Acquire() } DIAPPHACKID, *LPDIAPPHACKID; typedef struct tagAPPHACKENTRY { LPCTSTR pszName; DWORD cbData; DWORD dwOSMask; } APPHACKENTRY, *LPAPPHACKENTRY; typedef struct tagAPPHACKTABLE { LPAPPHACKENTRY aEntries; ULONG cEntries; } APPHACKTABLE, *LPAPPHACKTABLE; #define BEGIN_DECLARE_APPHACK_ENTRIES(name) \ APPHACKENTRY name[] = { #define DECLARE_APPHACK_ENTRY(name, type, osmask) \ { TEXT(#name), sizeof(type), osmask }, #define END_DECLARE_APPHACK_ENTRIES() \ }; #define BEGIN_DECLARE_APPHACK_TABLE(name) \ APPHACKTABLE name = #define DECLARE_APPHACK_TABLE(entries) \ { entries, cA(entries) } #define END_DECLARE_APPHACK_TABLE() \ ; #define DIHACKOS_WIN2K (0x00000001L) #define DIHACKOS_WIN9X (0x00000002L) BEGIN_DECLARE_APPHACK_ENTRIES(g_aheAppHackEntries) DECLARE_APPHACK_ENTRY(ReAcquire, BOOL, DIHACKOS_WIN2K ) DECLARE_APPHACK_ENTRY(NoSubClass, BOOL, DIHACKOS_WIN2K ) DECLARE_APPHACK_ENTRY(MaxDeviceNameLength, DWORD, DIHACKOS_WIN2K | DIHACKOS_WIN9X ) DECLARE_APPHACK_ENTRY(NativeAxisOnly, BOOL, DIHACKOS_WIN2K | DIHACKOS_WIN9X ) DECLARE_APPHACK_ENTRY(NoPollUnacquire, BOOL, DIHACKOS_WIN2K | DIHACKOS_WIN9X ) DECLARE_APPHACK_ENTRY(SucceedAcquire, BOOL, DIHACKOS_WIN2K ) END_DECLARE_APPHACK_ENTRIES() BEGIN_DECLARE_APPHACK_TABLE(g_ahtAppHackTable) DECLARE_APPHACK_TABLE(g_aheAppHackEntries) END_DECLARE_APPHACK_TABLE() /*************************************************************************** * * AhGetOSMask * * Description: * Gets the mask for the current OS * This mask should be used when we get app hacks for more than just * Win2k such that hacks can be applied selectively per OS. * For now just #define a value as constant. * * Arguments: * none * * Returns: * DWORD: Mask of flags applicable for the current OS. * ***************************************************************************/ #ifdef WINNT #define AhGetOSMask() DIHACKOS_WIN2K #else #define AhGetOSMask() DIHACKOS_WIN9X #endif /*************************************************************************** * * AhGetCurrentApplicationPath * * Description: * Gets the full path to the current application's executable. * * Arguments: * LPTSTR [out]: receives application id. This buffer is assumed to be * at least MAX_PATH characters in size. * LPTSTR * [out]: receives pointer to executable part of the path. * * Returns: * BOOL: TRUE on success. * ***************************************************************************/ BOOL AhGetCurrentApplicationPath ( LPTSTR pszPath, LPTSTR * ppszModule ) { BOOL fSuccess = TRUE; TCHAR szOriginal[MAX_PATH]; EnterProcI(AhGetCurrentApplicationPath, (_ "")); fSuccess = GetModuleFileName(GetModuleHandle(NULL), szOriginal, cA(szOriginal)); if(fSuccess) { fSuccess = ( GetFullPathName(szOriginal, MAX_PATH, pszPath, ppszModule) != 0 ); } ExitProcF(fSuccess); return fSuccess; } /*************************************************************************** * * AhGetApplicationId * * Description: * Gets the id used to identify the current application. * * Arguments: * LPTSTR [out]: receives application id. * * Arguments: * LPTSTR [out optional]: receives application name. * * Returns: * BOOL: TRUE on success. * ***************************************************************************/ BOOL AhGetApplicationId ( LPTSTR pszAppId, LPTSTR pszAppName ) { HANDLE hFile = NULL; TCHAR szExecutable[MAX_PATH]; LPTSTR pszModule; IMAGE_NT_HEADERS nth; IMAGE_DOS_HEADER dh; DWORD cbRead; DWORD dwFileSize; BOOL fSuccess; EnterProcI(AhGetApplicationId, (_ "")); AssertF( pszAppId ); // Get the application path fSuccess = AhGetCurrentApplicationPath(szExecutable, &pszModule); if(fSuccess) { SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("%sApplication executable path: %s"), c_tszPrefix, szExecutable); SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("%sApplication module: %s"), c_tszPrefix, pszModule); } // Open the executable if(fSuccess) { hFile = CreateFile(szExecutable, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(!(( hFile ) && ( hFile != INVALID_HANDLE_VALUE ))) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sCreateFile failed to open %s with error %lu"), c_tszPrefix, szExecutable, GetLastError()); fSuccess = FALSE; } } // Read the executable's DOS header if(fSuccess) { fSuccess = ReadFile(hFile, &dh, sizeof(dh), &cbRead, NULL); if(!fSuccess || sizeof(dh) != cbRead) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to read DOS header"), c_tszPrefix); fSuccess = FALSE; } } if(fSuccess && IMAGE_DOS_SIGNATURE != dh.e_magic) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sInvalid DOS signature"), c_tszPrefix); fSuccess = FALSE; } // Read the executable's PE header if(fSuccess) { cbRead = SetFilePointer(hFile, dh.e_lfanew, NULL, FILE_BEGIN); if((LONG)cbRead != dh.e_lfanew) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to seek to PE header"), c_tszPrefix); fSuccess = FALSE; } } if(fSuccess) { fSuccess = ReadFile(hFile, &nth, sizeof(nth), &cbRead, NULL); if(!fSuccess || sizeof(nth) != cbRead) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to read PE header"), c_tszPrefix); fSuccess = FALSE; } } if(fSuccess && IMAGE_NT_SIGNATURE != nth.Signature) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sInvalid PE signature"), c_tszPrefix); fSuccess = FALSE; } // Get the executable's size if(fSuccess) { // Assuming < 4 GB dwFileSize = GetFileSize(hFile, NULL); if((DWORD)(-1) == dwFileSize) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%sUnable to get file size"), c_tszPrefix); fSuccess = FALSE; } } // Create the application id if(fSuccess) { CharUpper(pszModule); wsprintf(pszAppId, TEXT("%s%8.8lX%8.8lX"), pszModule, nth.FileHeader.TimeDateStamp, dwFileSize); if( pszAppName ) { lstrcpy(pszAppName, pszModule); } SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sApplication id: %s"), c_tszPrefix, pszAppId); } // Clean up if( hFile != NULL ) { CloseHandle( hFile ); } ExitProcF(fSuccess); return fSuccess; } /*************************************************************************** * * AhOpenApplicationKey * * Description: * Opens or creates the application's root key. * * Arguments: * LPCTSTR [in]: application id. * * Returns: * HKEY: registry key handle. * ***************************************************************************/ HKEY AhOpenApplicationKey ( LPCTSTR pszAppId ) { #ifdef DEBUG TCHAR szName[0x100] = { 0 }; LONG cbName = sizeof(szName); #endif // DEBUG HKEY hkeyAll = NULL; HKEY hkeyApp = NULL; HRESULT hr; EnterProcI(AhOpenApplicationKey, (_ "")); // Open the parent key hr = hresMumbleKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_DINPUT TEXT("\\") REGSTR_KEY_APPHACK, KEY_READ, 0, &hkeyAll ); if(SUCCEEDED(hr)) { hr = hresMumbleKeyEx( hkeyAll, pszAppId, KEY_READ, 0, &hkeyApp ); RegCloseKey( hkeyAll ); #ifdef DEBUG // Query for the application description if(SUCCEEDED(hr)) { JoyReg_GetValue( hkeyApp, NULL, REG_SZ, szName, cbName ); SquirtSqflPtszV(sqfl | sqflTrace, TEXT( "%sApplication description: %ls"), c_tszPrefix, szName ); } #endif // DEBUG } ExitProc(); return hkeyApp; } /*************************************************************************** * * AhGetHackValue * * Description: * Queries an apphack value. * * Arguments: * HKEY [in]: application registry key. * DSAPPHACKID [in]: apphack id. * LPVOID [out]: receives apphack data. * DWORD [in]: size of above data buffer. * * Returns: * BOOL: TRUE on success. * ***************************************************************************/ BOOL AhGetHackValue ( HKEY hkey, DWORD dwOSMask, DIAPPHACKID ahid, LPVOID pvData, DWORD cbData ) { HRESULT hr; EnterProcI(AhGetHackValue, (_ "")); AssertF(ahid < (DIAPPHACKID)g_ahtAppHackTable.cEntries); AssertF(cbData == g_ahtAppHackTable.aEntries[ahid].cbData); if( !( dwOSMask & g_ahtAppHackTable.aEntries[ahid].dwOSMask ) ) { hr = DI_OK; } else { hr = JoyReg_GetValue( hkey, g_ahtAppHackTable.aEntries[ahid].pszName, REG_BINARY, pvData, cbData ); if( !SUCCEEDED( hr ) ) { SquirtSqflPtszV(sqfl | sqflBenign, TEXT("%sfailed to read value \"%s\", code 0x%08x"), c_tszPrefix, g_ahtAppHackTable.aEntries[ahid].pszName, hr); } } ExitProcF(DI_OK == hr); return DI_OK == hr; } /*************************************************************************** * * AhGetAppHacks * * Description: * Gets all app-hacks for the current application. * * Arguments: * LPDSAPPHACKS [out]: receives app-hack data. * * Returns: * BOOL: TRUE if any apphacks exist for the current application. * ***************************************************************************/ BOOL AhGetAppHacks ( LPDIAPPHACKS pahAppHacks ) { static const DIAPPHACKS ahDefaults = { FALSE, FALSE, FALSE, FALSE, FALSE, MAX_PATH }; TCHAR szAppId[MAX_PATH + 8 + 8] = { 0 }; HKEY hkey = NULL; BOOL fSuccess; DWORD dwOSMask; EnterProcI(AhGetAppHacks, (_ "")); // Assume defaults CopyMemory(pahAppHacks, &ahDefaults, sizeof(ahDefaults)); // Get the OS version mask dwOSMask = AhGetOSMask(); // Get the application id fSuccess = AhGetApplicationId(szAppId, NULL); if(fSuccess) { SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sFinding apphacks for %s..."), c_tszPrefix, szAppId); } // Open the application key if(fSuccess) { hkey = AhOpenApplicationKey(szAppId); fSuccess = ( hkey && (hkey != INVALID_HANDLE_VALUE ) ); } #define GET_APP_HACK( hackid, field ) \ if( !AhGetHackValue( hkey, dwOSMask, hackid, &pahAppHacks->##field, sizeof(pahAppHacks->##field) ) ) \ { \ pahAppHacks->##field = ahDefaults.##field; \ } // Query all apphack values if(fSuccess) { GET_APP_HACK( DICOMPATID_REACQUIRE, fReacquire ); GET_APP_HACK( DICOMPATID_NOSUBCLASS, fNoSubClass ); GET_APP_HACK( DICOMPATID_MAXDEVICENAMELENGTH, nMaxDeviceNameLength ); GET_APP_HACK( DICOMPATID_NATIVEAXISONLY, fNativeAxisOnly ); GET_APP_HACK( DICOMPATID_NOPOLLUNACQUIRE, fNoPollUnacquire ); GET_APP_HACK( DICOMPATID_SUCCEEDACQUIRE, fSucceedAcquire ); } #undef GET_APP_HACK if(fSuccess) { SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfReacquire: %d"), c_tszPrefix, pahAppHacks->fReacquire ); SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfNoSubClass: %d"), c_tszPrefix, pahAppHacks->fNoSubClass ); SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%snMaxDeviceNameLength: %d"), c_tszPrefix, pahAppHacks->nMaxDeviceNameLength ); SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfNativeAxisOnly: %d"), c_tszPrefix, pahAppHacks->fNativeAxisOnly ); SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfNoPollUnacquire: %d"), c_tszPrefix, pahAppHacks->fNoPollUnacquire ); SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sfSucceedAcquire: %d"), c_tszPrefix, pahAppHacks->fSucceedAcquire ); } else { SquirtSqflPtszV(sqfl | sqflTrace, TEXT("%sNo apphacks exist"), c_tszPrefix); } // Clean up if( hkey ) { RegCloseKey(hkey); } ExitProc(); return fSuccess; } HRESULT EXTERNAL AhAppRegister(DWORD dwVer) { TCHAR szAppName[MAX_PATH]; TCHAR szAppId[MAX_PATH + 8 + 8] = { 0 }; BOOL fSuccess; HRESULT hr = E_FAIL; fSuccess = AhGetApplicationId(szAppId, szAppName); if (fSuccess) { HKEY hKey; hr = hresMumbleKeyEx( HKEY_CURRENT_USER, REGSTR_PATH_LASTAPP, KEY_WRITE, 0, &hKey ); if( SUCCEEDED(hr) ) { FILETIME ftSysTime; GetSystemTimeAsFileTime( &ftSysTime ); RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_VERSION, 0x0, REG_BINARY, (PUCHAR) &dwVer, cbX(dwVer) ); RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_NAME, 0x0, REG_SZ, (PUCHAR) szAppName, cbCtch(lstrlen(szAppName)+1) ); RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_ID, 0x0, REG_SZ, (PUCHAR) szAppId, cbCtch(lstrlen(szAppId)+1) ); RegSetValueEx(hKey, DIRECTINPUT_REGSTR_VAL_LASTSTART, 0x0, REG_BINARY, (PUCHAR)&ftSysTime, cbX(ftSysTime)); RegCloseKey(hKey); } } return hr; }