/***************************************************************************** * * PidReg.c * * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Update registry information for PID device. * *****************************************************************************/ #include "pidpr.h" #define sqfl ( sqflReg ) #pragma BEGIN_CONST_DATA /* ;--------------------------------------- ; ; Force feedback registry settings for GUID_Sine. ; ; GUID_Sine is a predefined GUID; applications which want ; to use a sine effect independent of hardware will ; request a GUID_Sine. ; ; The default value is the friendly name for the effect. ; HKLM,%KEY_OEM%\XYZZY.FFDrv1\OEMForceFeedback\Effects\%GUID_Sine%,,,"%Sine.Desc%" ; ; The Attributes value contains a DIEFFECTATTRIBUTES structure. ; ; The effect ID is the number that is passed by DirectInput to the ; effect driver to identify the effect (thereby saving the effect ; driver the trouble of parsing GUIDs all the time). ; ; Our effect is a periodic effect whose optional envelope ; supports attack and fade. ; ; Our hardware supports changing the following parameters when ; the effect is not playing (static): Duration, gain, trigger button, ; axes, direction, envelope, type-specific parameters. We do not ; support sample period or trigger repeat interval. ; ; Our hardware does not support changing any parameters while an ; effect is playing (dynamic). ; ; Our hardware prefers receiving multiple-axis direction information ; in polar coordinates. ; ; dwEffectId = EFFECT_SINE ; = 723 = D3,02,00,00 ; dwEffType = DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY ; = 0x00000603 = 03,06,00,00 ; dwStaticParams = DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | ; DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | ; DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY ; = 0x000001ED = ED,01,00,00 ; dwDynamicParams = 0x00000000 = 00,00,00,00 ; dwCoords = DIEFF_POLAR ; = 0x00000020 = 20,00,00,00 */ static EFFECTMAPINFO g_EffectMapInfo[] = { { PIDMAKEUSAGEDWORD(ET_CONSTANT), DIEFT_CONSTANTFORCE | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_ConstantForce, TEXT("GUID_ConstantForce"), }, { PIDMAKEUSAGEDWORD(ET_RAMP), DIEFT_RAMPFORCE | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_RampForce, TEXT("GUID_RampForce"), }, { PIDMAKEUSAGEDWORD(ET_SQUARE), DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Square, TEXT("GUID_Square"), }, { PIDMAKEUSAGEDWORD(ET_SINE), DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Sine, TEXT("GUID_Sine"), }, { PIDMAKEUSAGEDWORD(ET_TRIANGLE), DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Triangle, TEXT("GUID_Triangle"), }, { PIDMAKEUSAGEDWORD(ET_SAWTOOTH_UP), DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_SawtoothUp, TEXT("GUID_SawtoothUp"), }, { PIDMAKEUSAGEDWORD(ET_SAWTOOTH_DOWN), DIEFT_PERIODIC | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_SawtoothDown, TEXT("GUID_SawtoothDown"), }, { PIDMAKEUSAGEDWORD(ET_SPRING), DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Spring, TEXT("GUID_Spring"), }, { PIDMAKEUSAGEDWORD(ET_DAMPER), DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Damper, TEXT("GUID_Damper"), }, { PIDMAKEUSAGEDWORD(ET_INERTIA), DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Inertia, TEXT("GUID_Inertia"), }, { PIDMAKEUSAGEDWORD(ET_FRICTION), DIEFT_CONDITION | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_Friction, TEXT("GUID_Friction"), }, { PIDMAKEUSAGEDWORD(ET_CUSTOM), DIEFT_CUSTOMFORCE | DIEFT_SATURATION | DIEFT_DEADBAND | DIEFT_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEP_DURATION | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_ENVELOPE | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY, DIEFF_POLAR, &GUID_CustomForce, TEXT("GUID_CustomForce"), }, }; static PIDSUPPORT g_DIeft[] = { {DIEFT_CONSTANTFORCE, PIDMAKEUSAGEDWORD(SET_CONSTANT_FORCE_REPORT), HID_COLLECTION, 0x0}, {DIEFT_RAMPFORCE, PIDMAKEUSAGEDWORD(SET_RAMP_FORCE_REPORT), HID_COLLECTION, 0x0}, {DIEFT_PERIODIC, PIDMAKEUSAGEDWORD(SET_PERIODIC_REPORT), HID_COLLECTION, 0x0}, {DIEFT_CONDITION, PIDMAKEUSAGEDWORD(SET_CONDITION_REPORT), HID_COLLECTION, 0x0}, {DIEFT_CUSTOMFORCE, PIDMAKEUSAGEDWORD(SET_CUSTOM_FORCE_REPORT), HID_COLLECTION, 0x0}, //{DIEFT_HARDWARE, ???? }, {DIEFT_FFATTACK, PIDMAKEUSAGEDWORD(ATTACK_LEVEL), HID_VALUE, HidP_Output}, {DIEFT_FFFADE, PIDMAKEUSAGEDWORD(FADE_LEVEL), HID_VALUE, HidP_Output}, {DIEFT_SATURATION, PIDMAKEUSAGEDWORD(POSITIVE_SATURATION), HID_VALUE, HidP_Output}, {DIEFT_POSNEGCOEFFICIENTS, PIDMAKEUSAGEDWORD(NEGATIVE_COEFFICIENT), HID_VALUE, HidP_Output}, {DIEFT_POSNEGSATURATION, PIDMAKEUSAGEDWORD(NEGATIVE_SATURATION), HID_VALUE, HidP_Output}, {DIEFT_DEADBAND, PIDMAKEUSAGEDWORD(DEAD_BAND), HID_VALUE, HidP_Output}, #if DIRECTINPUT_VERSION >= 0x600 {DIEFT_STARTDELAY, PIDMAKEUSAGEDWORD(START_DELAY), HID_VALUE, HidP_Output}, #endif }; static PIDSUPPORT g_DIep[] = { {DIEP_DURATION, PIDMAKEUSAGEDWORD(DURATION), HID_VALUE, HidP_Output}, {DIEP_SAMPLEPERIOD, PIDMAKEUSAGEDWORD(SAMPLE_PERIOD), HID_VALUE, HidP_Output}, {DIEP_GAIN, PIDMAKEUSAGEDWORD(GAIN), HID_VALUE, HidP_Output}, {DIEP_TRIGGERBUTTON, PIDMAKEUSAGEDWORD(TRIGGER_BUTTON), HID_VALUE, HidP_Output}, {DIEP_TRIGGERREPEATINTERVAL, PIDMAKEUSAGEDWORD(TRIGGER_REPEAT_INTERVAL), HID_VALUE, HidP_Output}, {DIEP_AXES, PIDMAKEUSAGEDWORD(AXES_ENABLE), HID_COLLECTION, 0x0}, {DIEP_DIRECTION, PIDMAKEUSAGEDWORD(DIRECTION), HID_COLLECTION, 0x0}, {DIEP_ENVELOPE, PIDMAKEUSAGEDWORD(SET_ENVELOPE_REPORT), HID_COLLECTION, 0x0}, #if DIRECTINPUT_VERSION >= 0x600 {DIEP_STARTDELAY, PIDMAKEUSAGEDWORD(START_DELAY), HID_VALUE, HidP_Output}, #endif }; static PIDSUPPORT g_DIeff[] = { {DIEFF_POLAR, PIDMAKEUSAGEDWORD(DIRECTION_ENABLE), HID_BUTTON, HidP_Output}, // PID devices do not support Cartesian // {DIEFF_ CARTESIAN, PIDMAKEUSAGEDWORD(AXES_ENABLE), HID_COLLECTION,0x0}, }; #pragma END_CONST_DATA //our own version of KEY_ALL_ACCESS, that does not use WRITE_DAC and WRITE_OWNER (see Whistler bug 318865, 370734) #define DI_DAC_OWNER (WRITE_DAC | WRITE_OWNER) #define DI_KEY_ALL_ACCESS (KEY_ALL_ACCESS & ~DI_DAC_OWNER) // we need to know on which OS we're running, to to have appropriate reg key permissions (see Whistler bug 318865, 370734) #define WIN_UNKNOWN_OS 0 #define WIN95_OS 1 #define WIN98_OS 2 #define WINME_OS 3 #define WINNT_OS 4 #define WINWH_OS 5 STDMETHODIMP PID_Support ( IDirectInputEffectDriver *ped, UINT cAPidSupport, PPIDSUPPORT rgPidSupport, PDWORD pdwFlags ) { CPidDrv *this = (CPidDrv *)ped; HRESULT hres; UINT indx; PPIDSUPPORT pPidSupport; EnterProcI(PID_Support, (_"xxxx", ped, cAPidSupport, rgPidSupport, pdwFlags)); hres = S_OK; for( indx = 0x0, pPidSupport = rgPidSupport; indx < cAPidSupport; indx++, pPidSupport++ ) { USAGE Usage = DIGETUSAGE(pPidSupport->dwPidUsage); USAGE UsagePage = DIGETUSAGEPAGE(pPidSupport->dwPidUsage); if( pPidSupport->Type == HID_COLLECTION ) { HRESULT hres0; USHORT LinkCollection; hres0 = PID_GetLinkCollectionIndex(ped, UsagePage, Usage , 0x0, &LinkCollection); if( SUCCEEDED(hres0) ) { *pdwFlags |= pPidSupport->dwDIFlags; } else { hres |= E_NOTIMPL; SquirtSqflPtszV(sqfl | sqflBenign, TEXT("%s: FAIL PID_GetCollectionIndex:0x%x for(%x,%x,%x:%s)"), s_tszProc, hres0, LinkCollection,UsagePage, Usage, PIDUSAGETXT(UsagePage,Usage) ); } } else if( pPidSupport->Type == HID_VALUE ) { NTSTATUS ntStat; HIDP_VALUE_CAPS ValCaps; USHORT cAValCaps = 0x1; ntStat = HidP_GetSpecificValueCaps ( pPidSupport->HidP_Type, //ReportType UsagePage, //UsagePage 0x0, //LinkCollection, Usage, //Usage &ValCaps, //ValueCaps, &cAValCaps, //ValueCapsLength, this->ppd //Preparsed Data ); if( SUCCEEDED(ntStat ) || ntStat == HIDP_STATUS_BUFFER_TOO_SMALL) { *pdwFlags |= pPidSupport->dwDIFlags; } else { hres |= E_NOTIMPL; SquirtSqflPtszV(sqfl | sqflBenign, TEXT("%s: FAIL HidP_GetSpValCaps:0x%x for(%x,%x,%x:%s)"), s_tszProc, ntStat, 0x0,UsagePage, Usage, PIDUSAGETXT(UsagePage,Usage) ); } } else if( pPidSupport->Type == HID_BUTTON ) { NTSTATUS ntStat; HIDP_BUTTON_CAPS ButtonCaps; USHORT cAButtonCaps = 0x1; ntStat = HidP_GetSpecificButtonCaps ( pPidSupport->HidP_Type, //ReportType UsagePage, //UsagePage 0x0, //LinkCollection, Usage, //Usage &ButtonCaps, //ValueCaps, &cAButtonCaps, //ValueCapsLength, this->ppd //Preparsed Data ); if( SUCCEEDED(ntStat ) || ntStat == HIDP_STATUS_BUFFER_TOO_SMALL) { *pdwFlags |= pPidSupport->dwDIFlags; } else { hres |= E_NOTIMPL; SquirtSqflPtszV(sqfl | sqflBenign, TEXT("%s: FAIL HidP_GetSpButtonCaps:0x%x for(%x,%x,%x:%s)"), s_tszProc, ntStat, 0x0,UsagePage, Usage, PIDUSAGETXT(UsagePage,Usage) ); } } else { hres |= DIERR_PID_USAGENOTFOUND; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc INTERNAL * * @func void | NameFromGUID | * * Convert a GUID into an ASCII string that will be used * to name it in the global namespace. * * * @parm LPTSTR | ptszBuf | * * Output buffer to receive the converted name. It must * be characters in size. * * @parm PCGUID | pguid | * * The GUID to convert. * * *****************************************************************************/ #pragma BEGIN_CONST_DATA /* Note: If you change this string, you need to change ctchNameGuid to match */ TCHAR c_tszNameFormat[] = TEXT("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"); #pragma END_CONST_DATA #define ctchGuid (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1) void EXTERNAL NameFromGUID(LPTSTR ptszBuf, PCGUID pguid) { int ctch; ctch = wsprintf(ptszBuf, c_tszNameFormat, pguid->Data1, pguid->Data2, pguid->Data3, pguid->Data4[0], pguid->Data4[1], pguid->Data4[2], pguid->Data4[3], pguid->Data4[4], pguid->Data4[5], pguid->Data4[6], pguid->Data4[7]); AssertF(ctch == ctchGuid - 1); } #define hresLe(le) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, (USHORT)(le)) BOOL INLINE IsWriteSam(REGSAM sam) { return sam & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | MAXIMUM_ALLOWED); } /***************************************************************************** * * @doc INTERNAL * * @func DWORD | PID_GetOSVersion | * * Return the OS version on which pid.dll is running. * * @returns * * WIN95_OS, WIN98_OS, WINME_OS, WINNT_OS, WINWH_OS, or WIN_UNKNOWN_OS. * *****************************************************************************/ DWORD PID_GetOSVersion() { OSVERSIONINFO osVerInfo; DWORD dwVer; if( GetVersion() < 0x80000000 ) { dwVer = WINNT_OS; } else { dwVer = WIN95_OS; //assume Windows 95 for safe } osVerInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); // If GetVersionEx is supported, then get more details. if( GetVersionEx( &osVerInfo ) ) { // Win2K if( osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) { // Whistler: Major = 5 & Build # > 2195 if( osVerInfo.dwMajorVersion == 5 && osVerInfo.dwBuildNumber > 2195 ) { dwVer = WINWH_OS; } else { dwVer = WINNT_OS; } } // Win9X else { if( (HIBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 4) ) { // WinMe: Major = 4, Minor = 90 if( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 90) ) { dwVer = WINME_OS; } else if ( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) > 0) ) { dwVer = WIN98_OS; } else { dwVer = WIN95_OS; } } } } return dwVer; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | hresMumbleKeyEx | * * Either open or create the key, depending on the degree * of access requested. * * @parm HKEY | hk | * * Base key. * * @parm LPCTSTR | ptszKey | * * Name of subkey, possibly NULL. * * @parm REGSAM | sam | * * Security access mask. * * @parm DWORD | dwOptions | * Options for RegCreateEx * * @parm PHKEY | phk | * * Receives output key. * * @returns * * Return value from or , * converted to an . * *****************************************************************************/ STDMETHODIMP hresMumbleKeyEx(HKEY hk, LPCTSTR ptszKey, REGSAM sam, DWORD dwOptions, PHKEY phk) { HRESULT hres; LONG lRc; BOOL bWinXP = FALSE; EnterProc(hresMumbleKeyEx, (_"xsxxx", hk, ptszKey, sam, dwOptions, phk)); /* * If caller is requesting write access, then create the key. * Else just open it. */ if(IsWriteSam(sam)) { // on WinXP, we strip out WRITE_DAC and WRITE_OWNER bits if (PID_GetOSVersion() == WINWH_OS) { sam &= ~DI_DAC_OWNER; bWinXP = TRUE; } lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk); if( lRc == ERROR_SUCCESS ) { // Don't need to create it already exists } else { #ifdef WINNT EXPLICIT_ACCESS ExplicitAccess; PACL pACL; DWORD dwErr; SECURITY_DESCRIPTOR SecurityDesc; DWORD dwDisposition; SECURITY_ATTRIBUTES sa; PSID pSid = NULL; SID_IDENTIFIER_AUTHORITY authority = SECURITY_WORLD_SID_AUTHORITY; // Describe the access we want to create the key with ZeroMemory (&ExplicitAccess, sizeof(ExplicitAccess) ); //set the access depending on the OS (see Whistler bug 318865) if (bWinXP == TRUE) { ExplicitAccess.grfAccessPermissions = DI_KEY_ALL_ACCESS; } else { ExplicitAccess.grfAccessPermissions = KEY_ALL_ACCESS; } ExplicitAccess.grfAccessMode = GRANT_ACCESS; ExplicitAccess.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; if (AllocateAndInitializeSid( &authority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSid )) { BuildTrusteeWithSid(&(ExplicitAccess.Trustee), pSid ); dwErr = SetEntriesInAcl( 1, &ExplicitAccess, NULL, &pACL ); if( dwErr == ERROR_SUCCESS ) { AssertF( pACL ); if( InitializeSecurityDescriptor( &SecurityDesc, SECURITY_DESCRIPTOR_REVISION ) ) { if( SetSecurityDescriptorDacl( &SecurityDesc, TRUE, pACL, FALSE ) ) { // Initialize a security attributes structure. sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = &SecurityDesc; sa.bInheritHandle = TRUE;// Use the security attributes to create a key. lRc = RegCreateKeyEx ( hk, // handle of an open key ptszKey, // address of subkey name 0, // reserved NULL, // address of class string dwOptions, // special options flag ExplicitAccess.grfAccessPermissions, // desired security access &sa, // address of key security structure phk, // address of buffer for opened handle &dwDisposition // address of disposition value buffer); ); } else { SquirtSqflPtszV( sqflError | sqflReg, TEXT("SetSecurityDescriptorDacl failed lastError=0x%x "), GetLastError()); } } else { SquirtSqflPtszV( sqflError | sqflReg, TEXT("InitializeSecurityDescriptor failed lastError=0x%x "), GetLastError()); } LocalFree( pACL ); } else { SquirtSqflPtszV( sqflError | sqflReg, TEXT("SetEntriesInACL failed, dwErr=0x%x"), dwErr ); } } else { SquirtSqflPtszV( sqflError | sqflReg, TEXT("AllocateAndInitializeSid failed")); } //Cleanup pSid if (pSid != NULL) { FreeSid(pSid); } if( lRc != ERROR_SUCCESS ) { SquirtSqflPtszV( sqflError, TEXT("Failed to create regkey %s with security descriptor, lRc=0x%x "), ptszKey, lRc); } #else lRc = RegCreateKeyEx(hk, ptszKey, 0, 0, dwOptions, sam, 0, phk, 0); #endif } } else { lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk); } if(lRc == ERROR_SUCCESS) { hres = S_OK; } else { if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY) { lRc = ERROR_FILE_NOT_FOUND; } hres = hresLe(lRc); } ExitOleProc(); return hres; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | PID_CreateFFKeys | * * Given a handle to a PID device, create the registry entries to enable * force feedback. * * @parm HANDLE | hdev | * * Handle to the PID device. * * @parm HKEY | hkFF | * * Force Feedback registry key. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * = : The operation completed successfully. * * : Couldn't open the key. * *****************************************************************************/ STDMETHODIMP PID_CreateFFKeys ( IDirectInputEffectDriver *ped, HKEY hkFF ) { CPidDrv *this = (CPidDrv *)ped; HRESULT hres; UINT uEffect; HKEY hkEffect; EnterProc(PID_CreateFFKey, (_"xx", ped, hkFF)); hres = hresMumbleKeyEx(hkFF, REGSTR_EFFECTS, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hkEffect); if( SUCCEEDED(hres) ) { DWORD dwDIef, dwDIep, dwDIeff; dwDIef = dwDIep = dwDIeff = 0x0; /* * Determine supported flags for effectType and Effect Params * based on the PID descriptors */ PID_Support(ped, cA(g_DIeft), g_DIeft, &dwDIef); PID_Support(ped, cA(g_DIep), g_DIep, &dwDIep); PID_Support(ped, cA(g_DIeff), g_DIeff, &dwDIeff); // All effects support DIEP_TYPESPECIFICPARAMS dwDIep |= DIEP_TYPESPECIFICPARAMS; for( uEffect = 0x0; uEffect < cA(g_EffectMapInfo); uEffect++ ) { EFFECTMAPINFO emi = g_EffectMapInfo[uEffect]; PIDSUPPORT PidSupport; DWORD dwJunk; HRESULT hres0; PidSupport.dwPidUsage = emi.attr.dwEffectId; PidSupport.Type = HID_BUTTON; PidSupport.HidP_Type = HidP_Output; hres0 = PID_Support(ped, 0x1, &PidSupport, &dwJunk); if( SUCCEEDED(hres0) ) { TCHAR tszName[ctchGuid]; HKEY hk; NameFromGUID(tszName, emi.pcguid); hres = hresMumbleKeyEx(hkEffect, tszName, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hk); if( SUCCEEDED(hres) ) { LONG lRc; lRc = RegSetValueEx(hk, 0x0, 0x0, REG_SZ, (char*)emi.tszName, lstrlen(emi.tszName) * cbX(emi.tszName[0])); if( lRc == ERROR_SUCCESS ) { /* * Modify generic attribute flags depending * on PID firmware descriptors */ emi.attr.dwEffType &= dwDIef; emi.attr.dwStaticParams &= dwDIep; emi.attr.dwDynamicParams &= dwDIep; emi.attr.dwCoords &= dwDIeff; lRc = RegSetValueEx(hk, REGSTR_ATTRIBUTES, 0x0, REG_BINARY, (char*)&emi.attr, cbX(emi.attr) ) ; if( lRc == ERROR_SUCCESS ) { } else { hres = REGDB_E_WRITEREGDB; } } else { hres = REGDB_E_WRITEREGDB; } RegCloseKey(hk); } } } RegCloseKey(hkEffect); } ExitOleProc(); return hres; } /***************************************************************************** * * PID_InitRegistry * * This function updates the registry for a specified device. * * LPTSTR ptszDeviceInterface * * * Returns: * * S_OK if the operation completed successfully. * * Any DIERR_* error code may be returned. * * Private driver-specific error codes in the range * DIERR_DRIVERFIRST through DIERR_DRIVERLAST * may be returned. * *****************************************************************************/ STDMETHODIMP PID_InitRegistry ( IDirectInputEffectDriver *ped ) { CPidDrv *this = (CPidDrv *)ped; HRESULT hres; TCHAR tszType[MAX_JOYSTRING]; HKEY hkFF; EnterProc(PID_InitRegistry, (_"x", ped)); wsprintf(tszType, REGSTR_OEM_FF_TEMPLATE, this->attr.VendorID, this->attr.ProductID); //If there is no pid version written, -- or it is less then the "last known good version" (today it is 0x0720), //overwrite the previous key. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tszType, KEY_READ, REG_OPTION_NON_VOLATILE, &hkFF ); if( SUCCEEDED(hres) ) { DWORD dwCreatedBy = 0x0; DWORD dwSize = cbX(dwCreatedBy); hres = E_FAIL; if ((RegQueryValueEx(hkFF, REGSTR_CREATEDBY, 0x0, 0x0, (BYTE*)&dwCreatedBy, &dwSize) == ERROR_SUCCESS) && (dwCreatedBy >= 0x0720)) { hres = S_OK; } RegCloseKey(hkFF); } if (FAILED(hres)) { hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tszType, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hkFF); if( SUCCEEDED(hres) ) { hres = PID_CreateFFKeys(ped, hkFF ); if( SUCCEEDED(hres) ) { DWORD dwCreatedBy = DIRECTINPUT_HEADER_VERSION; LONG lRc; DWORD dwSize; DWORD dwType; //DX8a Do not overwrite an existing CLSID as we may have //been loaded by an IHV with their own CLSID. In DX8, this //was always written causing some IHV drivers to be ignored. //Allow long values as a lot of people write strings with //garbage after a null terminated string //For now, DInput won't load such a CLSID but just in case lRc = RegQueryValueEx( hkFF, REGSTR_CLSID, NULL, &dwType, NULL, &dwSize ); if( ( lRc == ERROR_SUCCESS ) && ( dwType == REG_SZ ) && ( dwSize >= ctchGuid - 1 ) ) { #ifdef DEBUG TCHAR tszDbg[MAX_PATH]; dwSize = cbX(tszDbg); if( RegQueryValueEx( hkFF, REGSTR_CLSID, NULL, NULL, (BYTE*)tszDbg, &dwSize ) || !dwSize ) { tszDbg[0] = TEXT('?'); tszDbg[1] = TEXT('\0'); } SquirtSqflPtszV(sqfl | sqflBenign, TEXT("RegistryInit: Not overwiting existing CLSID %s"), tszDbg ); #endif } else { TCHAR tszGuid[ctchGuid]; NameFromGUID(tszGuid, &IID_IDirectInputPIDDriver); AssertF( lstrlen(tszGuid) * cbX(tszGuid[0]) == cbX(tszGuid) - cbX(tszGuid[0]) ); lRc = RegSetValueEx(hkFF, REGSTR_CLSID, 0x0, REG_SZ, (char*)tszGuid, cbX(tszGuid) - cbX(tszGuid[0])); if( lRc == ERROR_SUCCESS ) { } else { hres = REGDB_E_WRITEREGDB; } } //set "CreatedBy" value lRc = RegSetValueEx(hkFF, REGSTR_CREATEDBY, 0x0, REG_BINARY, (BYTE*) &dwCreatedBy, cbX(dwCreatedBy)); if( lRc == ERROR_SUCCESS ) { } else { hres = REGDB_E_WRITEREGDB; } } if(SUCCEEDED(hres) ) { DIFFDEVICEATTRIBUTES diff; LONG lRc; diff.dwFlags = 0x0; diff.dwFFSamplePeriod = diff.dwFFMinTimeResolution = DI_SECONDS; lRc = RegSetValueEx(hkFF, REGSTR_ATTRIBUTES, 0x0, REG_BINARY, (char*)&diff, cbX(diff) ) ; if(lRc == ERROR_SUCCESS) { } else { hres = REGDB_E_WRITEREGDB; } } RegCloseKey(hkFF); } } ExitOleProc(); return hres; }