/***************************************************************************** * * DIEffJ.c * * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Dummy effect driver for joystick. * * Contents: * * CJoyEff_CreateInstance * *****************************************************************************/ #include "dinputpr.h" #if defined(IDirectInputDevice2Vtbl) && defined(DEMONSTRATION_FFDRIVER) /***************************************************************************** * * The sqiffle for this file. * *****************************************************************************/ #define sqfl sqflJoyEff /**************************************************************************** * * @doc DDK * * @topic DirectInput force feedback effect drivers | * * DirectInput instantiates the force feedback effect driver * by creating the object named by the CLSID stored in the * OEMForceFeedback registry subkey of the joystick type * key. * * Note, however, that since applications using DirectInput * need not load OLE, the effect driver should be careful * not to rely on OLE-specific behavior. * For example, applications using DirectInput cannot be * relied upon to call . * DirectInput will perform the standard COM operations to * instantiate the effect driver object. The only visible * effect this should have on the implementation of the * effect driver is as follows: * * When DirectInput has released the last effect driver * object, it will manually perform a of * the effect driver DLL. Consequently, if the effect * driver DLL creates additional resources that are not * associated with the effect driver object, it should * manually itself to artificially * increase its DLL reference count, thereby preventing * the from DirectInput from unloading * the DLL prematurely. * * In particular, if the effect driver DLL creates a worker * thread, the effect driver must perform this artificial * for as long as the worker thread exists. * When the worker thread is no longer needed (for example, upon * notification from the last effect driver object as it * is being destroyed), the worker thread should call * to decrement the DLL reference * count and terminate the thread. * * All magnitude and gain values used by DirectInput * are uniform and linear across the range. Any * nonlinearity in the physical device must be * handled by the device driver so that the application * sees a linear device. * *****************************************************************************/ /***************************************************************************** * * Declare the interfaces we will be providing. * * WARNING! If you add a secondary interface, you must also change * CJoyEff_New! * *****************************************************************************/ Primary_Interface(CJoyEff, IDirectInputEffectDriver); /***************************************************************************** * * @doc INTERNAL * * @struct JEFFECT | * * Dummy structure that records information about an effect. * * @field DWORD | tmDuration | * * Putative duration for effect. * * @field DWORD | tmStart | * * Time the effect started, or zero if not playing. * * @field BOOL | fInUse | * * Nonzero if this effect is allocated. * *****************************************************************************/ typedef struct JEFFECT { DWORD tmDuration; DWORD tmStart; BOOL fInUse; } JEFFECT, *PJEFFECT; /***************************************************************************** * * @doc INTERNAL * * @struct CJoyEff | * * A dummy object for the * generic joystick. * * @field IDirectInputEffectDriver | didc | * * The object (containing vtbl). * * @field BOOL | fCritInited:1 | * * Set if the critical section has been initialized. * * @field DWORD | state | * * The current device state. * * @field LONG | cCrit | * * Number of times the critical section has been taken. * Used only in XDEBUG to check whether the caller is * releasing the object while another method is using it. * * @field DWORD | thidCrit | * * The thread that is currently in the critical section. * Used only in DEBUG for internal consistency checking. * * @field CRITICAL_SECTION | crst | * * Object critical section. Must be taken when accessing * volatile member variables. * * @field JEFFECT | rgjeff[cjeffMax] | * * Information for each effect. * *****************************************************************************/ #define cjeffMax 8 /* Up to 8 simultaneous effects */ typedef struct CJoyEff { /* Supported interfaces */ IDirectInputEffectDriver ded; BOOL fCritInited; DWORD state; DWORD dwGain; RD(LONG cCrit;) D(DWORD thidCrit;) CRITICAL_SECTION crst; JEFFECT rgjeff[cjeffMax]; } CJoyEff, DJE, *PDJE; typedef IDirectInputEffectDriver DED, *PDED; #define ThisClass CJoyEff #define ThisInterface IDirectInputEffectDriver #define riidExpected &IID_IDirectInputEffectDriver /***************************************************************************** * * CJoyEff::QueryInterface (from IUnknown) * CJoyEff::AddRef (from IUnknown) * CJoyEff::Release (from IUnknown) * *****************************************************************************/ /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | QueryInterface | * * Gives a client access to other interfaces on an object. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm IN REFIID | riid | * * The requested interface's IID. * * @parm OUT LPVOID * | ppvObj | * * Receives a pointer to the obtained interface. * * @returns * * Returns a COM error code. * * @xref OLE documentation for . * ***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | AddRef | * * Increments the reference count for the interface. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @returns * * Returns the object reference count. * * @xref OLE documentation for . * ***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | Release | * * Decrements the reference count for the interface. * If the reference count on the object falls to zero, * the object is freed from memory. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @returns * * Returns the object reference count. * * @xref OLE documentation for . * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CJoyEff | QIHelper | * * We don't have any dynamic interfaces and simply forward * to . * * @parm IN REFIID | riid | * * The requested interface's IID. * * @parm OUT LPVOID * | ppvObj | * * Receives a pointer to the obtained interface. * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CJoyEff | AppFinalize | * * We don't have any weak pointers, so we can just * forward to . * * @parm PV | pvObj | * * Object being released from the application's perspective. * *****************************************************************************/ #ifdef DEBUG Default_QueryInterface(CJoyEff) Default_AddRef(CJoyEff) Default_Release(CJoyEff) #else #define CJoyEff_QueryInterface Common_QueryInterface #define CJoyEff_AddRef Common_AddRef #define CJoyEff_Release Common_Release #endif #define CJoyEff_QIHelper Common_QIHelper #define CJoyEff_AppFinalize Common_AppFinalize /***************************************************************************** * * @doc INTERNAL * * @func void | CJoyEff_Finalize | * * Releases the resources of the device. * * @parm PV | pvObj | * * Object being released. Note that it may not have been * completely initialized, so everything should be done * carefully. * *****************************************************************************/ void INTERNAL CJoyEff_Finalize(PV pvObj) { PDJE this = pvObj; if (this->fCritInited) { DeleteCriticalSection(&this->crst); } } /***************************************************************************** * * @doc INTERNAL * * @method void | CJoyEff | EnterCrit | * * Enter the object critical section. * * @cwrap PDJE | this * *****************************************************************************/ void EXTERNAL CJoyEff_EnterCrit(PDJE this) { EnterCriticalSection(&this->crst); D(this->thidCrit = GetCurrentThreadId()); RD(InterlockedIncrement(&this->cCrit)); } /***************************************************************************** * * @doc INTERNAL * * @method void | CJoyEff | LeaveCrit | * * Leave the object critical section. * * @cwrap PDJE | this * *****************************************************************************/ void EXTERNAL CJoyEff_LeaveCrit(PDJE this) { #ifdef XDEBUG AssertF(this->cCrit); AssertF(this->thidCrit == GetCurrentThreadId()); if (InterlockedDecrement(&this->cCrit) == 0) { D(this->thidCrit = 0); } #endif LeaveCriticalSection(&this->crst); } /***************************************************************************** * * @doc INTERNAL * * @method BOOL | CJoyEff | InCrit | * * Nonzero if we are in the critical section. * *****************************************************************************/ #ifdef DEBUG BOOL INTERNAL CJoyEff_InCrit(PDJE this) { return this->cCrit && this->thidCrit == GetCurrentThreadId(); } #endif /***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CJoyEff | IsValidId | * * Determine whether the effect pseudo-handle is valid. * If so, returns a pointer to the . * * @cwrap PDJE | this * * @parm DWORD | dwId | * * Putative ID number. * * @parm PJEFFECT * | ppjeff | * * Receives pointer to the on success. * *****************************************************************************/ HRESULT INTERNAL CJoyEff_IsValidId(PDJE this, DWORD dwId, PJEFFECT *ppjeff) { HRESULT hres; AssertF(CJoyEff_InCrit(this)); if (dwId) { PJEFFECT pjeff = &this->rgjeff[dwId - 1]; if (pjeff->fInUse) { *ppjeff = pjeff; hres = S_OK; } else { hres = E_HANDLE; } } else { hres = E_HANDLE; } return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | DeviceID | * * Inform the driver of the identity of the device. * * For example, if a device driver is passed *

= 2 and

= 1, * then this means that unit 1 on the device * corresponds to joystick ID number 2. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwDirectInputVersion | * * The version of DirectInput that loaded the * effect driver. * * @parm DWORD | dwExternalID | * * The joystick ID number being used. * The Windows joystick subsystem allocates external IDs. * * If the

field is non- then this * parameter should be ignored. * * @parm DWORD | fBegin | * * Nonzero if access to the device is beginning. * Zero if the access to the device is ending. * * @parm DWORD | dwInternalID | * * Internal joystick id. The device driver manages * internal IDs. * * If the

field is non- then this * parameter should be ignored. * * @parm LPVOID | lpHIDInfo | * * If the underlying device is not a HID device, then this * parameter is . * * If the underlying device is a HID device, then this * parameter points to a structure * which informs the driver of HID information. * * @returns * * if the operation completed successfully. * * An error code if something is wrong. * *****************************************************************************/ STDMETHODIMP CJoyEff_DeviceID(PDED pded, DWORD dwDIVer, DWORD dwExternalID, DWORD fBegin, DWORD dwInternalID, LPVOID pvReserved) { PDJE this; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::DeviceID, (_ "pxuuu", pded, dwDIVer, dwExternalID, fBegin, dwInternalID)); this = _thisPvNm(pded, ded); dwDIVer; dwExternalID; fBegin; dwInternalID; pvReserved; hres = S_OK; ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | Escape | * * Escape to the driver. This method is called * in response to an application invoking the * or * method. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The joystick ID number being used. * * @parm DWORD | dwEffect | * * If the application invoked the * method, then *

contains the handle (returned by * ) * of the effect at which the command is directed. * * If the application invoked the * method, then *

is zero. * * @parm LPDIEFFESCAPE | pesc | * * Pointer to a structure which describes * the command to be sent. On success, the * field contains the number * of bytes of the output buffer actually used. * * DirectInput has already validated that the * and * and fields * point to valid memory. * * @returns * * if the operation completed successfully. * * An error code if something is wrong. * *****************************************************************************/ STDMETHODIMP CJoyEff_Escape(PDED pded, DWORD dwId, DWORD dwEffect, LPDIEFFESCAPE pesc) { PDJE this; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::Escape, (_ "puxx", pded, dwId, dwEffect, pesc->dwCommand)); this = _thisPvNm(pded, ded); dwId; dwEffect; pesc; hres = E_NOTIMPL; ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | SetGain | * * Set the overall device gain. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The joystick ID number being used. * * @parm DWORD | dwGain | * * The new gain value. * * If the value is out of range for the device, the device * should use the nearest supported value and return * . * * @returns * * if the operation completed successfully. * * An error code if something is wrong. * *****************************************************************************/ STDMETHODIMP CJoyEff_SetGain(PDED pded, DWORD dwId, DWORD dwGain) { PDJE this; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::SetGain, (_ "puu", pded, dwId, dwGain)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; this->dwGain = dwGain; CJoyEff_LeaveCrit(this); hres = S_OK; ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | SendForceFeedbackCommand | * * Send a command to the device. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The external joystick number being addressed. * * @parm DWORD | dwCommand | * * Command, one of the values. * * @returns * on success. * * @devnote * * Semantics unclear. * *****************************************************************************/ STDMETHODIMP CJoyEff_SendForceFeedbackCommand(PDED pded, DWORD dwId, DWORD dwCmd) { PDJE this; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::SendForceFeedbackCommand, (_ "pux", pded, dwId, dwCmd)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; dwCmd; this->state = dwCmd; /* * On a reset, all effects are destroyed. */ if (dwCmd & DISFFC_RESET) { DWORD ijeff; for (ijeff = 0; ijeff < cjeffMax; ijeff++) { this->rgjeff[ijeff].fInUse = FALSE; } } CJoyEff_LeaveCrit(this); hres = S_OK; ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | GetForceFeedbackState | * * Retrieve the force feedback state for the device. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The external joystick number being addressed. * * @parm LPDEVICESTATE | pds | * * Receives device state. * * DirectInput will set the field * to sizeof(DIDEVICESTATE) before calling this method. * @returns * on success. * * @devnote * * Semantics unclear. * *****************************************************************************/ STDMETHODIMP CJoyEff_GetForceFeedbackState(PDED pded, DWORD dwId, LPDIDEVICESTATE pds) { PDJE this; HRESULT hres; DWORD ijeff, cjeff, cjeffPlaying; EnterProcI(IDirectInputEffectDriver::Joy::GetForceFeedbackState, (_ "pup", pded, dwId, pds)); this = _thisPvNm(pded, ded); dwId; pds; if (pds->dwSize == cbX(*pds)) { CJoyEff_EnterCrit(this); /* * Count how many effects are in use, and return it as a percentage. */ cjeff = cjeffPlaying = 0; for (ijeff = 0; ijeff < cjeffMax; ijeff++) { PJEFFECT pjeff = &this->rgjeff[ijeff]; if (pjeff->fInUse) { cjeff++; if (pjeff->tmStart && GetTickCount() - pjeff->tmStart < pjeff->tmDuration) { cjeffPlaying++; } } } pds->dwLoad = MulDiv(100, cjeff, cjeffMax); /* * If there are no effects downloaded, then we are empty. */ pds->dwState = 0; if (cjeff == 0) { pds->dwState |= DIGFFS_EMPTY; } else /* * If there are no effects playing, then we are stopped. */ if (cjeffPlaying == 0) { pds->dwState |= DIGFFS_STOPPED; } /* * Actuators are always on (dumb fake hardware) */ pds->dwState |= DIGFFS_ACTUATORSON; CJoyEff_LeaveCrit(this); hres = S_OK; } else { hres = E_INVALIDARG; } ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | DownloadEffect | * * Send an effect to the device. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The external joystick number being addressed. * * @parm DWORD | dwEffectId | * * Internal identifier for the effect, taken from * the structure for the effect * as stored in the registry. * * @parm IN OUT LPDWORD | pdwEffect | * * On entry, contains the handle of the effect being * downloaded. If the value is zero, then a new effect * is downloaded. If the value is nonzero, then an * existing effect is modified. * * On exit, contains the new effect handle. * * On failure, set to zero if the effect is lost, * or left alone if the effect is still valid with * its old parameters. * * Note that zero is never a valid effect handle. * * * @parm LPCDIEFFECT | peff | * * The new parameters for the effect. The axis and button * values have been converted to object identifiers * as follows: * * - One type specifier: * , * , * , * , * . * * - One instance specifier: * (n). * * Other bits are reserved and should be ignored. * * For example, the value 0x0200104 corresponds to * the type specifier and * the instance specifier (1), * which together indicate that the effect should * be associated with button 1. Axes, buttons, and POVs * are each numbered starting from zero. * * @parm DWORD | dwFlags | * * Zero or more flags specifying which * portions of the effect information has changed from * the effect already on the device. * * This information is passed to drivers to allow for * optimization of effect modification. If an effect * is being modified, a driver may be able to update * the effect and transmit to the device * only the information that has changed. * * Drivers are not, however, required to implement this * optimization. All fields in the structure * pointed to by the

parameter are valid, and * a driver may choose simply to update all parameters of * the effect at each download. * * @returns * on success. * * @devnote * * This implies that 0 is never a valid effect handle value. * *****************************************************************************/ STDMETHODIMP CJoyEff_DownloadEffect(PDED pded, DWORD dwId, DWORD dwEffectId, LPDWORD pdwEffect, LPCDIEFFECT peff, DWORD fl) { PDJE this; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::DownloadEffect, (_ "puxxpx", pded, dwId, dwEffectId, *pdwEffect, peff, fl)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; fl; if (dwEffectId == 1) { PJEFFECT pjeff; DWORD dwGain; /* * Parameter validation goes here, if any. * * Envelope parameter is ignored. */ if (peff->cAxes == 0) { /* Zero axes? Nice try */ hres = E_INVALIDARG; goto done; } /* * Pin above-nominal values to DI_FFNOMINALMAX because * we don't support overgain. */ dwGain = min(peff->dwGain, DI_FFNOMINALMAX); /* * We do not support triggers. */ if (peff->dwTriggerButton != DIEB_NOTRIGGER) { hres = E_NOTIMPL; goto done; } /* * If no downloading in effect, then we're done. */ if (fl & DIEP_NODOWNLOAD) { hres = S_OK; goto done; } if (*pdwEffect) { hres = CJoyEff_IsValidId(this, *pdwEffect, &pjeff); if (FAILED(hres)) { goto done; } } else { DWORD ijeff; for (ijeff = 0; ijeff < cjeffMax; ijeff++) { if (!this->rgjeff[ijeff].fInUse) { this->rgjeff[ijeff].fInUse = TRUE; pjeff = &this->rgjeff[ijeff]; goto haveEffect; } } hres = DIERR_DEVICEFULL; goto done; } haveEffect:; SquirtSqflPtszV(sqfl, TEXT("dwFlags=%08x"), peff->dwFlags); SquirtSqflPtszV(sqfl, TEXT("cAxes=%d"), peff->cAxes); for (fl = 0; fl < peff->cAxes; fl++) { SquirtSqflPtszV(sqfl, TEXT(" Axis%2d=%08x Direction=%5d"), fl, peff->rgdwAxes[fl], peff->rglDirection[fl]); } SquirtSqflPtszV(sqfl, TEXT("dwTrigger=%08x"), peff->dwTriggerButton); pjeff->tmDuration = peff->dwDuration / 1000; *pdwEffect = (DWORD)(pjeff - this->rgjeff) + 1; //we are sure this cast will not cause problem hres = S_OK; } else { hres = E_NOTIMPL; } done:; CJoyEff_LeaveCrit(this); ExitOleProc(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | DestroyEffect | * * Remove an effect from the device. * * If the effect is playing, the driver should stop it * before unloading it. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The external joystick number being addressed. * * @parm DWORD | dwEffect | * * The effect to be destroyed. * * @returns * on success. * *****************************************************************************/ STDMETHODIMP CJoyEff_DestroyEffect(PDED pded, DWORD dwId, DWORD dwEffect) { PDJE this; PJEFFECT pjeff; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::DestroyEffect, (_ "pux", pded, dwId, dwEffect)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; hres = CJoyEff_IsValidId(this, dwEffect, &pjeff); if (SUCCEEDED(hres)) { pjeff->fInUse = 0; } CJoyEff_LeaveCrit(this); ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | 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 * flags. Note, however, that the driver * will never receive the flag; * the flag is managed by * DirectInput and not the driver. * * @parm DWORD | dwCount | * * Number of times the effect is to be played. * * @returns * on success. * *****************************************************************************/ STDMETHODIMP CJoyEff_StartEffect(PDED pded, DWORD dwId, DWORD dwEffect, DWORD dwMode, DWORD dwCount) { PDJE this; PJEFFECT pjeff; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::StartEffect, (_ "puxxu", pded, dwId, dwEffect, dwMode, dwCount)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; hres = CJoyEff_IsValidId(this, dwEffect, &pjeff); if (SUCCEEDED(hres)) { if (pjeff->tmStart) { if (GetTickCount() - pjeff->tmStart < pjeff->tmDuration) { /* Already playing */ hres = hresLe(ERROR_BUSY); } else { pjeff->tmStart = GetTickCount(); hres = S_OK; } } else { pjeff->tmStart = GetTickCount(); hres = S_OK; } } CJoyEff_LeaveCrit(this); ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | StopEffect | * * Halt playback of an effect. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The external joystick number being addressed. * * @parm DWORD | dwEffect | * * The effect to be stopped. * * @returns * on success. * *****************************************************************************/ STDMETHODIMP CJoyEff_StopEffect(PDED pded, DWORD dwId, DWORD dwEffect) { PDJE this; PJEFFECT pjeff; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::StopEffect, (_ "pux", pded, dwId, dwEffect)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; hres = CJoyEff_IsValidId(this, dwEffect, &pjeff); if (SUCCEEDED(hres)) { if (pjeff->tmStart) { if (GetTickCount() - pjeff->tmStart < pjeff->tmDuration) { /* It is still playing; stop it */ hres = S_OK; } else { hres = S_FALSE; /* It already stopped on its own */ } pjeff->tmStart = 0; } else { hres = S_FALSE; /* It was never started */ } } CJoyEff_LeaveCrit(this); ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | GetEffectStatus | * * Obtain information about an effect. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm DWORD | dwId | * * The external joystick number being addressed. * * @parm DWORD | dwEffect | * * The effect to be queried. * * @parm LPDWORD | pdwStatus | * * Receives the effect status. * * @returns * on success. * *****************************************************************************/ STDMETHODIMP CJoyEff_GetEffectStatus(PDED pded, DWORD dwId, DWORD dwEffect, LPDWORD pdwStatus) { PDJE this; PJEFFECT pjeff; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::StopEffect, (_ "pux", pded, dwId, dwEffect)); this = _thisPvNm(pded, ded); CJoyEff_EnterCrit(this); dwId; hres = CJoyEff_IsValidId(this, dwEffect, &pjeff); if (SUCCEEDED(hres)) { DWORD dwStatus; dwStatus = 0; if (pjeff->tmStart && GetTickCount() - pjeff->tmStart < pjeff->tmDuration) { dwStatus |= DEV_STS_EFFECT_RUNNING; } *pdwStatus = dwStatus; hres = S_OK; } CJoyEff_LeaveCrit(this); ExitOleProcR(); return hres; } /***************************************************************************** * * @doc DDK * * @method HRESULT | IDirectInputEffectDriver | GetVersions | * * Obtain version information about the force feedback * hardware and driver. * * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver * * @parm LPDIDRIVERVERSIONS | pvers | * * A structure which should be filled in with version information * describing the hardware, firmware, and driver. * * DirectInput will set the field * to sizeof(DIDRIVERVERSIONS) before calling this method. * * @returns * on success. * *****************************************************************************/ STDMETHODIMP CJoyEff_GetVersions(PDED pded, LPDIDRIVERVERSIONS pvers) { PDJE this; HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::GetVersions, (_ "pux", pded)); this = _thisPvNm(pded, ded); /* * Returning E_NOTIMPL causes DirectInput to ask the VxD for the same * information. */ hres = E_NOTIMPL; ExitOleProcR(); return hres; } /***************************************************************************** * * CJoyEff_New (constructor) * *****************************************************************************/ STDMETHODIMP CJoyEff_New(PUNK punkOuter, RIID riid, PPV ppvObj) { HRESULT hres; EnterProcI(IDirectInputEffectDriver::Joy::, (_ "Gp", riid, ppvObj)); hres = Common_NewRiid(CJoyEff, punkOuter, riid, ppvObj); if (SUCCEEDED(hres)) { /* Must use _thisPv if multiple interfaces supported */ PDJE this = _thisPvNm(*ppvObj, ded); /* * The critical section must be the very first thing we do, * because only Finalize checks for its existence. * * (We might be finalized without being initialized if the user * passed a bogus interface to CJoyEff_New.) */ this->fCritInited = fInitializeCriticalSection(&this->crst); if( !this->fCritInited ) { Common_Unhold(this); *ppvObj = NULL; hres = E_OUTOFMEMORY; } } ExitOleProcPpvR(ppvObj); return hres; } /***************************************************************************** * * The long-awaited vtbls and templates * *****************************************************************************/ #pragma BEGIN_CONST_DATA #define CJoyEff_Signature 0x4645454B /* "JEFF" */ Interface_Template_Begin(CJoyEff) Primary_Interface_Template(CJoyEff, IDirectInputEffectDriver) Interface_Template_End(CJoyEff) Primary_Interface_Begin(CJoyEff, IDirectInputEffectDriver) CJoyEff_DeviceID, CJoyEff_GetVersions, CJoyEff_Escape, CJoyEff_SetGain, CJoyEff_SendForceFeedbackCommand, CJoyEff_GetForceFeedbackState, CJoyEff_DownloadEffect, CJoyEff_DestroyEffect, CJoyEff_StartEffect, CJoyEff_StopEffect, CJoyEff_GetEffectStatus, Primary_Interface_End(CJoyEff, IDirectInputEffectDriver) #endif