|
|
/*****************************************************************************
* * 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 <c ctchNameGuid> 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 <f RegOpenKeyEx> or <f RegCreateKeyEx>, * converted to an <t HRESULT>. * *****************************************************************************/
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. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: 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; }
|