816 lines
21 KiB
C
816 lines
21 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* EffDrv.c
|
||
|
*
|
||
|
* Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* Abstract:
|
||
|
*
|
||
|
* Effect driver.
|
||
|
*
|
||
|
* WARNING! Since the effect driver is marked ThreadingModel="Both",
|
||
|
* all methods must be thread-safe.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
#include "PIDpr.h"
|
||
|
|
||
|
#define sqfl (sqflEffDrv)
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* CPidDrv - Effect driver
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_AddRef
|
||
|
*
|
||
|
* Increment our object reference count (thread-safely) and return
|
||
|
* the new reference count.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
PID_AddRef(IDirectInputEffectDriver *ped)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
|
||
|
InterlockedIncrement((LPLONG)&this->cRef);
|
||
|
|
||
|
|
||
|
return this->cRef;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_Release
|
||
|
*
|
||
|
* Decrement our object reference count (thread-safely) and
|
||
|
* destroy ourselves if there are no more references.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
PID_Release(IDirectInputEffectDriver *ped)
|
||
|
{
|
||
|
ULONG ulRc;
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
|
||
|
if(InterlockedDecrement((LPLONG)&this->cRef) == 0)
|
||
|
{
|
||
|
DllRelease();
|
||
|
PID_Finalize(ped);
|
||
|
LocalFree(this);
|
||
|
ulRc = 0;
|
||
|
} else
|
||
|
{
|
||
|
ulRc = this->cRef;
|
||
|
}
|
||
|
|
||
|
return ulRc;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_QueryInterface
|
||
|
*
|
||
|
* Our QI is very simple because we support no interfaces beyond
|
||
|
* ourselves.
|
||
|
*
|
||
|
* riid - Interface being requested
|
||
|
* ppvOut - receives new interface (if successful)
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
PID_QueryInterface(IDirectInputEffectDriver *ped, REFIID riid, LPVOID *ppvOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
if(IsEqualIID(riid, &IID_IUnknown) ||
|
||
|
IsEqualIID(riid, &IID_IDirectInputEffectDriver))
|
||
|
{
|
||
|
PID_AddRef(ped);
|
||
|
*ppvOut = ped;
|
||
|
hres = S_OK;
|
||
|
} else
|
||
|
{
|
||
|
*ppvOut = 0;
|
||
|
hres = E_NOINTERFACE;
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_DeviceID
|
||
|
*
|
||
|
* DirectInput uses this method to inform us of
|
||
|
* the identity of the device.
|
||
|
*
|
||
|
* For example, if a device driver is passed
|
||
|
* dwExternalID = 2 and dwInternalID = 1,
|
||
|
* then this means the interface will be used to
|
||
|
* communicate with joystick ID number 2, which
|
||
|
* corresonds to physical unit 1 in VJOYD.
|
||
|
*
|
||
|
* dwDirectInputVersion
|
||
|
*
|
||
|
* The version of DirectInput that loaded the
|
||
|
* effect driver.
|
||
|
*
|
||
|
* dwExternalID
|
||
|
*
|
||
|
* The joystick ID number being used.
|
||
|
* The Windows joystick subsystem allocates external IDs.
|
||
|
*
|
||
|
* fBegin
|
||
|
*
|
||
|
* Nonzero if access to the device is beginning.
|
||
|
* Zero if the access to the device is ending.
|
||
|
*
|
||
|
* dwInternalID
|
||
|
*
|
||
|
* Internal joystick id. The device driver manages
|
||
|
* internal IDs.
|
||
|
*
|
||
|
* lpReserved
|
||
|
*
|
||
|
* Reserved for future use (HID).
|
||
|
*
|
||
|
* 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_DeviceID(IDirectInputEffectDriver *ped,
|
||
|
DWORD dwDirectInputVersion,
|
||
|
DWORD dwExternalID, DWORD fBegin,
|
||
|
DWORD dwInternalID, LPVOID pvReserved)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres = S_OK;
|
||
|
LPDIHIDFFINITINFO init = (DIHIDFFINITINFO*)pvReserved;
|
||
|
|
||
|
EnterProcI(PID_DeviceID, (_"xxxxxx", ped, dwDirectInputVersion, dwExternalID, fBegin, dwInternalID, pvReserved));
|
||
|
|
||
|
DllEnterCrit();
|
||
|
|
||
|
if( init == NULL )
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL init == NULL "),
|
||
|
s_tszProc );
|
||
|
hres = DIERR_PID_NOTINITIALIZED;
|
||
|
}
|
||
|
|
||
|
if( SUCCEEDED(hres)
|
||
|
&& (init->dwSize < cbX(*init) ) )
|
||
|
{
|
||
|
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL init->dwSize(%d) expecting(%d) "),
|
||
|
s_tszProc, init->dwSize, cbX(*init) );
|
||
|
hres = DIERR_PID_NOTINITIALIZED;
|
||
|
|
||
|
}
|
||
|
|
||
|
if( SUCCEEDED(hres) )
|
||
|
{
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
lstrcpy(this->tszDeviceInterface, init->pwszDeviceInterface );
|
||
|
#else // !UNICODE
|
||
|
{
|
||
|
TCHAR tszDeviceInterface[MAX_DEVICEINTERFACE];
|
||
|
UToA(tszDeviceInterface, MAX_DEVICEINTERFACE, init->pwszDeviceInterface);
|
||
|
|
||
|
lstrcpy(this->tszDeviceInterface, tszDeviceInterface);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if( FAILED(hres) )
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL:0x%x Invalid string(%s) "),
|
||
|
s_tszProc, hres, init->pwszDeviceInterface );
|
||
|
}
|
||
|
|
||
|
if( SUCCEEDED(hres) && IsEqualGUID(&init->GuidInstance, &GUID_NULL ) )
|
||
|
{
|
||
|
hres = DIERR_PID_NOTINITIALIZED;
|
||
|
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL:init->GuidInstance is NULL "),
|
||
|
s_tszProc );
|
||
|
}
|
||
|
|
||
|
this->GuidInstance = init->GuidInstance;
|
||
|
|
||
|
/* Record the DI version number */
|
||
|
this->dwDirectInputVersion = dwDirectInputVersion;
|
||
|
|
||
|
/* Keep the external ID as a cookie for access to the driver functionality */
|
||
|
this->dwID = dwExternalID;
|
||
|
}
|
||
|
|
||
|
if( SUCCEEDED(hres) )
|
||
|
{
|
||
|
/* Ping the device to make sure it is fine */
|
||
|
hres = PID_Init(ped);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Remember the unit number because that tells us which of
|
||
|
* our devices we are talking to. The DirectInput external
|
||
|
* joystick number is useless to us. (We don't care if we
|
||
|
* are joystick 1 or joystick 2.)
|
||
|
*
|
||
|
* Note that although our other methods are given an external
|
||
|
* joystick Id, we don't use it. Instead, we use the unit
|
||
|
* number that we were given here.
|
||
|
*
|
||
|
* Our hardware supports only MAX_UNITS units.
|
||
|
*/
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_GetVersions
|
||
|
*
|
||
|
* Obtain version information about the force feedback
|
||
|
* hardware and driver.
|
||
|
*
|
||
|
* pvers
|
||
|
*
|
||
|
* A structure which should be filled in with version information
|
||
|
* describing the hardware, firmware, and driver.
|
||
|
*
|
||
|
* DirectInput will set the dwSize field
|
||
|
* to sizeof(DIDRIVERVERSIONS) before calling this method.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* S_OK if the operation completed successfully.
|
||
|
*
|
||
|
* E_NOTIMPL to indicate that DirectInput should retrieve
|
||
|
* version information from the VxD driver instead.
|
||
|
*
|
||
|
* 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_GetVersions(IDirectInputEffectDriver *ped, LPDIDRIVERVERSIONS pvers)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres;
|
||
|
|
||
|
EnterProc(PID_GetVersions, (_"xx", ped, pvers));
|
||
|
|
||
|
DllEnterCrit();
|
||
|
|
||
|
if(pvers->dwSize >= sizeof(DIDRIVERVERSIONS))
|
||
|
{
|
||
|
/*
|
||
|
* Tell DirectInput how much of the structure we filled in.
|
||
|
*/
|
||
|
pvers->dwSize = sizeof(DIDRIVERVERSIONS);
|
||
|
|
||
|
/*
|
||
|
* In real life, we would detect the version of the hardware
|
||
|
* that is connected to unit number this->dwUnit.
|
||
|
*/
|
||
|
pvers->dwFirmwareRevision = 0x0;
|
||
|
pvers->dwHardwareRevision = this->attr.ProductID;
|
||
|
pvers->dwFFDriverVersion = PID_DRIVER_VERSION;
|
||
|
hres = S_OK;
|
||
|
} else
|
||
|
{
|
||
|
hres = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_Escape
|
||
|
*
|
||
|
* DirectInput uses this method to communicate
|
||
|
* IDirectInputDevice2::Escape and
|
||
|
* IDirectInputEFfect::Escape methods to the driver.
|
||
|
*
|
||
|
* dwId
|
||
|
*
|
||
|
* The joystick ID number being used.
|
||
|
*
|
||
|
* dwEffect
|
||
|
*
|
||
|
* If the application invoked the
|
||
|
* IDirectInputEffect::Escape method, then
|
||
|
* dwEffect contains the handle (returned by
|
||
|
* mf IDirectInputEffectDriver::DownloadEffect)
|
||
|
* of the effect at which the command is directed.
|
||
|
*
|
||
|
* If the application invoked the
|
||
|
* mf IDirectInputDevice2::Escape method, then
|
||
|
* dwEffect is zero.
|
||
|
*
|
||
|
* pesc
|
||
|
*
|
||
|
* Pointer to a DIEFFESCAPE structure which describes
|
||
|
* the command to be sent. On success, the
|
||
|
* cbOutBuffer field contains the number
|
||
|
* of bytes of the output buffer actually used.
|
||
|
*
|
||
|
* DirectInput has already validated that the
|
||
|
* lpvOutBuffer and lpvInBuffer and fields
|
||
|
* point to valid memory.
|
||
|
*
|
||
|
* 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_Escape(IDirectInputEffectDriver *ped,
|
||
|
DWORD dwId, DWORD dwEffect, LPDIEFFESCAPE pesc)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres;
|
||
|
|
||
|
EnterProc(PID_Escape, (_"xxxx", ped, dwId, dwEffect, pesc));
|
||
|
|
||
|
hres = E_NOTIMPL;
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_GetForceFeedbackState
|
||
|
*
|
||
|
* Retrieve the force feedback state for the device.
|
||
|
*
|
||
|
* dwId
|
||
|
*
|
||
|
* The external joystick number being addressed.
|
||
|
*
|
||
|
* pds
|
||
|
*
|
||
|
* Receives device state.
|
||
|
*
|
||
|
* DirectInput will set the dwSize field
|
||
|
* to sizeof(DIDEVICESTATE) before calling this method.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* S_OK on success.
|
||
|
*
|
||
|
* 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_GetForceFeedbackState(IDirectInputEffectDriver *ped,
|
||
|
DWORD dwId, LPDIDEVICESTATE pds)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres;
|
||
|
USHORT LinkCollection;
|
||
|
|
||
|
EnterProcI(PID_GetFFState, (_"xxx", ped, dwId, pds));
|
||
|
|
||
|
DllEnterCrit();
|
||
|
|
||
|
hres = PID_GetLinkCollectionIndex(ped,g_PoolReport.UsagePage,g_PoolReport.Collection,0x0,&LinkCollection);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = PID_GetReport
|
||
|
(ped,
|
||
|
&g_PoolReport,
|
||
|
LinkCollection,
|
||
|
this->pReport[g_PoolReport.HidP_Type],
|
||
|
this->cbReport[g_PoolReport.HidP_Type]
|
||
|
);
|
||
|
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
if (FAILED(PID_ParseReport
|
||
|
(
|
||
|
ped,
|
||
|
&g_PoolReport,
|
||
|
LinkCollection,
|
||
|
&this->ReportPool,
|
||
|
cbX(this->ReportPool),
|
||
|
this->pReport[g_PoolReport.HidP_Type],
|
||
|
this->cbReport[g_PoolReport.HidP_Type]
|
||
|
)))
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL to parse report."),
|
||
|
s_tszProc);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL to get report."),
|
||
|
s_tszProc);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: FAIL to get Link Collection Index."),
|
||
|
s_tszProc);
|
||
|
|
||
|
}
|
||
|
|
||
|
if( ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded != this->ReportPool.uRomETCount )
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: PID driver downloaded %d effects, device claims it has %d"),
|
||
|
s_tszProc, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded, this->ReportPool.uRomETCount );
|
||
|
|
||
|
}
|
||
|
|
||
|
if(SUCCEEDED(hres))
|
||
|
{
|
||
|
/*
|
||
|
* Start out empty and then work our way up.
|
||
|
*/
|
||
|
pds->dwState = this->dwState;
|
||
|
|
||
|
/*
|
||
|
* If there are no effects, then DIGFFS_EMPTY.
|
||
|
*/
|
||
|
// ISSUE-2001/03/29-timgill Should use this->ReportPool.uRomETCount == 0x0
|
||
|
if(((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded == 0x0 )
|
||
|
{
|
||
|
pds->dwState |= DIGFFS_EMPTY;
|
||
|
|
||
|
// No effects playing and device is not paused
|
||
|
if(!( pds->dwState & DIGFFS_PAUSED ) )
|
||
|
{
|
||
|
pds->dwState |= DIGFFS_STOPPED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//if everything has succeeded, this->ReportPool.uRamPoolSz shouldn't be 0.
|
||
|
if (this->ReportPool.uRamPoolSz != 0)
|
||
|
{
|
||
|
if( this->uDeviceManaged & PID_DEVICEMANAGED )
|
||
|
{
|
||
|
pds->dwLoad = 100 * ( this->dwUsedMem / this->ReportPool.uRamPoolSz );
|
||
|
}else
|
||
|
{
|
||
|
pds->dwLoad = 100 * ( ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cbAlloc / this->ReportPool.uRamPoolSz );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SquirtSqflPtszV(sqfl | sqflError,
|
||
|
TEXT("%s: this->ReportPool.uRamPoolSz = 0."),
|
||
|
s_tszProc);
|
||
|
hres = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_StartEffect
|
||
|
*
|
||
|
* Begin playback of an effect.
|
||
|
*
|
||
|
* If the effect is already playing, then it is restarted
|
||
|
* from the beginning.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
|
||
|
*
|
||
|
* @parm DWORD | dwId |
|
||
|
*
|
||
|
* The external joystick number being addressed.
|
||
|
*
|
||
|
* @parm DWORD | dwEffect |
|
||
|
*
|
||
|
* The effect to be played.
|
||
|
*
|
||
|
* @parm DWORD | dwMode |
|
||
|
*
|
||
|
* How the effect is to affect other effects.
|
||
|
*
|
||
|
* This parameter consists of zero or more
|
||
|
* DIES_* flags. Note, however, that the driver
|
||
|
* will never receive the DIES_NODOWNLOAD flag;
|
||
|
* the DIES_NODOWNLOAD flag is managed by
|
||
|
* DirectInput and not the driver.
|
||
|
*
|
||
|
* @parm DWORD | dwCount |
|
||
|
*
|
||
|
* Number of times the effect is to be played.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* S_OK on success.
|
||
|
*
|
||
|
* Any other DIERR_* error code may be returned.
|
||
|
*
|
||
|
* Private driver-specific error codes in the range
|
||
|
* DIERR_DRIVERFIRST through DIERR_DRIVERLAST
|
||
|
* may be returned.
|
||
|
*
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
PID_StartEffect(IDirectInputEffectDriver *ped, DWORD dwId, DWORD dwEffect,
|
||
|
DWORD dwMode, DWORD dwCount)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres;
|
||
|
|
||
|
EnterProc(PID_StartEffect, (_"xxxxx", ped, dwId, dwEffect, dwMode, dwCount));
|
||
|
|
||
|
DllEnterCrit();
|
||
|
|
||
|
hres = PID_EffectOperation
|
||
|
(
|
||
|
ped,
|
||
|
dwId,
|
||
|
dwEffect,
|
||
|
dwMode | PID_DIES_START,
|
||
|
dwCount,
|
||
|
TRUE,
|
||
|
0,
|
||
|
1
|
||
|
);
|
||
|
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
//set the status to DIEGES_PLAYING.
|
||
|
//we do this because of the following: if an app calls Start(), and then immediately
|
||
|
//calls GetEffectStatus(), it might happen that our second thread (pidrd.c)
|
||
|
//would not have time to update the status of the effect to DIEGES_PLAYING
|
||
|
//(see Whistler bug 287035).
|
||
|
//GetEffectStatus() returns (pEffectState->lEfState & DIEGES_PLAYING).
|
||
|
//at this point, we know that the call to WriteFile() has succeeded, and that
|
||
|
//all the data has been written (see PID_SendReportBl() in pidhid.c) --
|
||
|
//so we might as well set the status.
|
||
|
PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this, dwEffect);
|
||
|
pEffectState->lEfState |= DIEGES_PLAYING;
|
||
|
}
|
||
|
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
return hres;
|
||
|
|
||
|
ExitOleProc();
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_StopEffect
|
||
|
*
|
||
|
* Halt playback of an effect.
|
||
|
*
|
||
|
* dwId
|
||
|
*
|
||
|
* The external joystick number being addressed.
|
||
|
*
|
||
|
* dwEffect
|
||
|
*
|
||
|
* The effect to be stopped.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* S_OK on success.
|
||
|
*
|
||
|
* Any other DIERR_* error code may be returned.
|
||
|
*
|
||
|
* Private driver-specific error codes in the range
|
||
|
* DIERR_DRIVERFIRST through DIERR_DRIVERLAST
|
||
|
* may be returned.
|
||
|
*
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
PID_StopEffect(IDirectInputEffectDriver *ped, DWORD dwId, DWORD dwEffect)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres;
|
||
|
|
||
|
EnterProc(PID_StopEffect, (_"xxxx", ped, dwId, dwEffect));
|
||
|
|
||
|
DllEnterCrit();
|
||
|
|
||
|
hres = PID_EffectOperation
|
||
|
(
|
||
|
ped,
|
||
|
dwId,
|
||
|
dwEffect,
|
||
|
PID_DIES_STOP,
|
||
|
0x0,
|
||
|
TRUE,
|
||
|
0,
|
||
|
1
|
||
|
);
|
||
|
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
//set the status to ~(DIEGES_PLAYING).
|
||
|
//we do this because of the following: if an app calls Stop(), and then immediately
|
||
|
//calls GetEffectStatus(), it might happen that our second thread (pidrd.c)
|
||
|
//would not have time to update the status of the effect to DIEGES_PLAYING
|
||
|
//(see Whistler bug 287035).
|
||
|
//GetEffectStatus() returns (pEffectState->lEfState & DIEGES_PLAYING).
|
||
|
//at this point, we know that the call to WriteFile() has succeeded, and that
|
||
|
//all the data has been written (see PID_SendReportBl() in pidhid.c) --
|
||
|
//so we might as well set the status.
|
||
|
PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this, dwEffect);
|
||
|
pEffectState->lEfState &= ~(DIEGES_PLAYING);
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_GetEffectStatus
|
||
|
*
|
||
|
* Obtain information about an effect.
|
||
|
*
|
||
|
* dwId
|
||
|
*
|
||
|
* The external joystick number being addressed.
|
||
|
*
|
||
|
* dwEffect
|
||
|
*
|
||
|
* The effect to be queried.
|
||
|
*
|
||
|
* pdwStatus
|
||
|
*
|
||
|
* Receives the effect status in the form of zero
|
||
|
* or more DIEGES_* flags.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* S_OK on success.
|
||
|
*
|
||
|
* Any other DIERR_* error code may be returned.
|
||
|
*
|
||
|
* Private driver-specific error codes in the range
|
||
|
* DIERR_DRIVERFIRST through DIERR_DRIVERLAST
|
||
|
* may be returned.
|
||
|
*
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
PID_GetEffectStatus(IDirectInputEffectDriver *ped, DWORD dwId, DWORD dwEffect,
|
||
|
LPDWORD pdwStatus)
|
||
|
{
|
||
|
CPidDrv *this = (CPidDrv *)ped;
|
||
|
HRESULT hres;
|
||
|
|
||
|
EnterProc(PID_GetEffectStatus, (_"xxxx", ped, dwId, dwEffect, pdwStatus));
|
||
|
|
||
|
DllEnterCrit();
|
||
|
|
||
|
*pdwStatus = 0x0;
|
||
|
hres = PID_ValidateEffectIndex(ped, dwEffect);
|
||
|
|
||
|
if(SUCCEEDED(hres) )
|
||
|
{
|
||
|
PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,dwEffect);
|
||
|
*pdwStatus = (pEffectState->lEfState & DIEGES_PLAYING);
|
||
|
}
|
||
|
|
||
|
DllLeaveCrit();
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* The VTBL for our effect driver
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
IDirectInputEffectDriverVtbl PID_Vtbl = {
|
||
|
PID_QueryInterface,
|
||
|
PID_AddRef,
|
||
|
PID_Release,
|
||
|
PID_DeviceID,
|
||
|
PID_GetVersions,
|
||
|
PID_Escape,
|
||
|
PID_SetGain,
|
||
|
PID_SendForceFeedbackCommand,
|
||
|
PID_GetForceFeedbackState,
|
||
|
PID_DownloadEffect,
|
||
|
PID_DestroyEffect,
|
||
|
PID_StartEffect,
|
||
|
PID_StopEffect,
|
||
|
PID_GetEffectStatus,
|
||
|
};
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* PID_New
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
PID_New(REFIID riid, LPVOID *ppvOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
CPidDrv *this;
|
||
|
|
||
|
this = LocalAlloc(LPTR, sizeof(CPidDrv));
|
||
|
if(this)
|
||
|
{
|
||
|
|
||
|
/*
|
||
|
* Initialize the basic object management goo.
|
||
|
*/
|
||
|
this->ed.lpVtbl = &PID_Vtbl;
|
||
|
this->cRef = 1;
|
||
|
DllAddRef();
|
||
|
|
||
|
/*
|
||
|
* !!IHV!! Do instance initialization here.
|
||
|
*
|
||
|
* (e.g., open the driver you are going to IOCTL to)
|
||
|
*
|
||
|
* DO NOT RESET THE DEVICE IN YOUR CONSTRUCTOR!
|
||
|
*
|
||
|
* Wait for the SendForceFeedbackCommand(SFFC_RESET)
|
||
|
* to reset the device. Otherwise, you may reset
|
||
|
* a device that another application is still using.
|
||
|
*/
|
||
|
|
||
|
this->hdevOvrlp = this->hdev = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
/*
|
||
|
* Attempt to obtain the desired interface. QueryInterface
|
||
|
* will do an AddRef if it succeeds.
|
||
|
*/
|
||
|
hres = PID_QueryInterface(&this->ed, riid, ppvOut);
|
||
|
PID_Release(&this->ed);
|
||
|
|
||
|
} else
|
||
|
{
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|