1559 lines
46 KiB
C
1559 lines
46 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* DIObj.c
|
||
|
*
|
||
|
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* Abstract:
|
||
|
*
|
||
|
* The IDirectInput main interface.
|
||
|
*
|
||
|
* Contents:
|
||
|
*
|
||
|
* CDIObj_New
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "dinputpr.h"
|
||
|
#include "verinfo.h" /* For #ifdef FINAL */
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* The sqiffle for this file.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#define sqfl sqflDi
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @struct CDIObj |
|
||
|
*
|
||
|
* The <i IDirectInput> object, from which other things come.
|
||
|
*
|
||
|
* The A and W versions are simply alternate interfaces on the same
|
||
|
* underlying object.
|
||
|
*
|
||
|
* There really isn't anything interesting in the structure
|
||
|
* itself.
|
||
|
*
|
||
|
*
|
||
|
* @field IDirectInputA | diA |
|
||
|
*
|
||
|
* ANSI DirectInput object (containing vtbl).
|
||
|
*
|
||
|
* @field IDirectInputW | diW |
|
||
|
*
|
||
|
* UNICODE DirectInput object (containing vtbl).
|
||
|
*
|
||
|
* @field IDirectInputJoyConfig *| pdjc |
|
||
|
*
|
||
|
* Aggregated joystick configuration interface (if created).
|
||
|
*
|
||
|
* @field BOOL | fCritInited:1 |
|
||
|
*
|
||
|
* Set if the critical section has been initialized.
|
||
|
*
|
||
|
* @field CRITICAL_SECTION | crst |
|
||
|
*
|
||
|
* Critical section that guards thread-sensitive data.
|
||
|
*****************************************************************************/
|
||
|
|
||
|
typedef struct CDIObj {
|
||
|
|
||
|
/* Supported interfaces */
|
||
|
TFORM(IDirectInput) TFORM(di);
|
||
|
SFORM(IDirectInput) SFORM(di);
|
||
|
|
||
|
DWORD dwVersion;
|
||
|
|
||
|
IDirectInputJoyConfig *pdjc;
|
||
|
|
||
|
BOOL fCritInited:1;
|
||
|
|
||
|
CRITICAL_SECTION crst;
|
||
|
|
||
|
} CDIObj, DDI, *PDDI;
|
||
|
|
||
|
#define ThisClass CDIObj
|
||
|
|
||
|
|
||
|
#ifdef IDirectInput7Vtbl
|
||
|
|
||
|
#define ThisInterface TFORM(IDirectInput7)
|
||
|
#define ThisInterfaceA IDirectInput7A
|
||
|
#define ThisInterfaceW IDirectInput7W
|
||
|
#define ThisInterfaceT IDirectInput7
|
||
|
|
||
|
#else
|
||
|
#ifdef IDirectInput2Vtbl
|
||
|
|
||
|
#define ThisInterface TFORM(IDirectInput2)
|
||
|
#define ThisInterfaceA IDirectInput2A
|
||
|
#define ThisInterfaceW IDirectInput2W
|
||
|
#define ThisInterfaceT IDirectInput2
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define ThisInterface TFORM(IDirectInput)
|
||
|
#define ThisInterfaceA IDirectInputA
|
||
|
#define ThisInterfaceW IDirectInputW
|
||
|
#define ThisInterfaceT IDirectInput
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Declare the interfaces we will be providing.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
Primary_Interface(CDIObj, TFORM(ThisInterfaceT));
|
||
|
Secondary_Interface(CDIObj, SFORM(ThisInterfaceT));
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | QueryInterface |
|
||
|
*
|
||
|
* Gives a client access to other interfaces on an object.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @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 <mf IUnknown::QueryInterface>.
|
||
|
*
|
||
|
*//**************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | AddRef |
|
||
|
*
|
||
|
* Increments the reference count for the interface.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* Returns the object reference count.
|
||
|
*
|
||
|
* @xref OLE documentation for <mf IUnknown::AddRef>.
|
||
|
*
|
||
|
*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | 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 LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* Returns the object reference count.
|
||
|
*
|
||
|
* @xref OLE documentation for <mf IUnknown::Release>.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
Default_QueryInterface(CDIObj)
|
||
|
Default_AddRef(CDIObj)
|
||
|
Default_Release(CDIObj)
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define CDIObj_QueryInterface Common_QueryInterface
|
||
|
#define CDIObj_AddRef Common_AddRef
|
||
|
#define CDIObj_Release Common_Release
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#define CDIObj_AppFinalize Common_AppFinalize
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @mfunc void | CDIObj | EnterCrit |
|
||
|
*
|
||
|
* Enter the object critical section.
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @mfunc void | CDIObj | LeaveCrit |
|
||
|
*
|
||
|
* Leave the object critical section.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void INLINE
|
||
|
CDIObj_EnterCrit(PDDI this)
|
||
|
{
|
||
|
EnterCriticalSection(&this->crst);
|
||
|
}
|
||
|
|
||
|
void INLINE
|
||
|
CDIObj_LeaveCrit(PDDI this)
|
||
|
{
|
||
|
LeaveCriticalSection(&this->crst);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @mfunc HRESULT | IDirectInput | QIHelper |
|
||
|
*
|
||
|
* We will dynamically create <i IDirectInputJoyConfig>
|
||
|
* and aggregate it with us.
|
||
|
*
|
||
|
#ifdef IDirectInput2Vtbl
|
||
|
* Support the original IDirectInput interfaces as well
|
||
|
* as the new IDirectInput2 interfaces.
|
||
|
#endif
|
||
|
* @parm IN REFIID | riid |
|
||
|
*
|
||
|
* The requested interface's IID.
|
||
|
*
|
||
|
* @parm OUT LPVOID * | ppvObj |
|
||
|
*
|
||
|
* Receives a pointer to the obtained interface.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_QIHelper(PDDI this, RIID riid, PPV ppvObj)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcI(CDIObj_QIHelper, (_ "pG", this, riid));
|
||
|
|
||
|
if (IsEqualIID(riid, &IID_IDirectInputJoyConfig)) {
|
||
|
|
||
|
*ppvObj = 0; /* In case the New fails */
|
||
|
|
||
|
CDIObj_EnterCrit(this);
|
||
|
if (this->pdjc == 0) {
|
||
|
hres = CJoyCfg_New((PUNK)this, &IID_IUnknown, (PPV)&this->pdjc);
|
||
|
} else {
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
CDIObj_LeaveCrit(this);
|
||
|
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
/*
|
||
|
* This QI will addref us if it succeeds.
|
||
|
*/
|
||
|
hres = OLE_QueryInterface(this->pdjc, riid, ppvObj);
|
||
|
} else {
|
||
|
this->pdjc = 0;
|
||
|
}
|
||
|
|
||
|
#ifdef IDirectInput2Vtbl
|
||
|
|
||
|
} else if (IsEqualIID(riid, &IID_IDirectInputA)) {
|
||
|
|
||
|
*ppvObj = &this->diA;
|
||
|
OLE_AddRef(this);
|
||
|
hres = S_OK;
|
||
|
|
||
|
} else if (IsEqualIID(riid, &IID_IDirectInputW)) {
|
||
|
|
||
|
*ppvObj = &this->diW;
|
||
|
OLE_AddRef(this);
|
||
|
hres = S_OK;
|
||
|
|
||
|
#endif
|
||
|
#ifdef IDirectInput7Vtbl
|
||
|
|
||
|
} else if (IsEqualIID(riid, &IID_IDirectInput2A)) {
|
||
|
|
||
|
*ppvObj = &this->diA;
|
||
|
OLE_AddRef(this);
|
||
|
hres = S_OK;
|
||
|
} else if (IsEqualIID(riid, &IID_IDirectInput2W)) {
|
||
|
|
||
|
*ppvObj = &this->diW;
|
||
|
OLE_AddRef(this);
|
||
|
hres = S_OK;
|
||
|
|
||
|
#endif //IDirectInput7Vtbl
|
||
|
} else {
|
||
|
hres = Common_QIHelper(this, riid, ppvObj);
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpv(ppvObj);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func void | CDIObj_Finalize |
|
||
|
*
|
||
|
* Clean up our instance data.
|
||
|
*
|
||
|
* @parm PV | pvObj |
|
||
|
*
|
||
|
* Object being released. Note that it may not have been
|
||
|
* completely initialized, so everything should be done
|
||
|
* carefully.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void INTERNAL
|
||
|
CDIObj_Finalize(PV pvObj)
|
||
|
{
|
||
|
PDDI this = pvObj;
|
||
|
|
||
|
Invoke_Release(&this->pdjc);
|
||
|
|
||
|
if (this->fCritInited) {
|
||
|
DeleteCriticalSection(&this->crst);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | CreateDeviceHelper |
|
||
|
*
|
||
|
* Creates and initializes an instance of a device which is
|
||
|
* specified by the GUID and IID.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm IN PCGUID | pguid |
|
||
|
*
|
||
|
* See <mf IDirectInput::CreateDevice>.
|
||
|
*
|
||
|
* @parm OUT PPV | ppvObj |
|
||
|
*
|
||
|
* See <mf IDirectInput::CreateDevice>.
|
||
|
*
|
||
|
* @parm IN LPUNKNOWN | punkOuter |
|
||
|
*
|
||
|
* See <mf IDirectInput::CreateDevice>.
|
||
|
*
|
||
|
* @parm IN RIID | riid |
|
||
|
*
|
||
|
* The interface the application wants to create. This will
|
||
|
* be either <i IDirectInputDeviceA> or <i IDirectInputDeviceW>.
|
||
|
* If the object is aggregated, then this parameter is ignored.
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* Returns a COM error code.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_CreateDeviceHelper(PDDI this, PCGUID pguid, PPV ppvObj,
|
||
|
PUNK punkOuter, RIID riid)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProc(CDIObj_CreateDeviceHelper,
|
||
|
(_ "pGxG", this, pguid, punkOuter, riid));
|
||
|
|
||
|
/*
|
||
|
* CDIDev_New will validate the punkOuter and ppvObj.
|
||
|
*
|
||
|
* IDirectInputDevice_Initialize will validate the pguid.
|
||
|
*
|
||
|
* riid is known good (since it came from CDIObj_CreateDeviceW
|
||
|
* or CDIObj_CreateDeviceA).
|
||
|
*/
|
||
|
|
||
|
hres = CDIDev_New(punkOuter, punkOuter ? &IID_IUnknown : riid, ppvObj);
|
||
|
|
||
|
if (SUCCEEDED(hres) && punkOuter == 0) {
|
||
|
PDID pdid = *ppvObj;
|
||
|
hres = IDirectInputDevice_Initialize(pdid, g_hinst,
|
||
|
this->dwVersion, pguid);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
} else {
|
||
|
Invoke_Release(ppvObj);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpv(ppvObj);
|
||
|
return hres;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | CreateDevice |
|
||
|
*
|
||
|
* Creates and initializes an instance of a device which is
|
||
|
* specified by the GUID and IID.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm REFGUID | rguid |
|
||
|
* Identifies the instance of the
|
||
|
* device for which the indicated interface
|
||
|
* is requested. The <mf IDirectInput::EnumDevices> method
|
||
|
* can be used to determine which instance GUIDs are supported by
|
||
|
* the system.
|
||
|
*
|
||
|
* @parm OUT LPDIRECTINPUTDEVICE * | lplpDirectInputDevice |
|
||
|
* Points to where to return
|
||
|
* the pointer to the <i IDirectInputDevice> interface, if successful.
|
||
|
*
|
||
|
* @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown
|
||
|
* for OLE aggregation, or 0 if the interface is not aggregated.
|
||
|
* Most callers will pass 0.
|
||
|
*
|
||
|
* @comm Calling this function with <p punkOuter> = NULL
|
||
|
* is equivalent to creating the object via
|
||
|
* <f CoCreateInstance>(&CLSID_DirectInputDevice, NULL,
|
||
|
* CLSCTX_INPROC_SERVER, <p riid>, <p lplpDirectInputDevice>);
|
||
|
* then initializing it with <f Initialize>.
|
||
|
*
|
||
|
* Calling this function with <p punkOuter> != NULL
|
||
|
* is equivalent to creating the object via
|
||
|
* <f CoCreateInstance>(&CLSID_DirectInputDevice, <p punkOuter>,
|
||
|
* CLSCTX_INPROC_SERVER, &IID_IUnknown, <p lplpDirectInputDevice>).
|
||
|
* The aggregated object must be initialized manually.
|
||
|
*
|
||
|
* @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_INVALIDPARAM> = <c E_INVALIDARG>: The
|
||
|
* <p ppvOut> parameter is not a valid pointer.
|
||
|
*
|
||
|
* <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
|
||
|
* Out of memory.
|
||
|
*
|
||
|
* <c DIERR_NOINTERFACE> = <c E_NOINTERFACE>
|
||
|
* The specified interface is not supported by the object.
|
||
|
*
|
||
|
* <c DIERR_DEVICENOTREG> = The device instance does not
|
||
|
* correspond to a device that is registered with DirectInput.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_CreateDeviceW(PV pdiW, REFGUID rguid, PPDIDW ppdidW, PUNK punkOuter)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::CreateDevice,
|
||
|
(_ "pGp", pdiW, rguid, punkOuter));
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW))) {
|
||
|
PDDI this = _thisPvNm(pdiW, diW);
|
||
|
|
||
|
hres = CDIObj_CreateDeviceHelper(this, rguid, (PPV)ppdidW,
|
||
|
punkOuter, &IID_IDirectInputDeviceW);
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpv(ppdidW);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_CreateDeviceA(PV pdiA, REFGUID rguid, PPDIDA ppdidA, PUNK punkOuter)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::CreateDevice,
|
||
|
(_ "pGp", pdiA, rguid, punkOuter));
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA))) {
|
||
|
PDDI this = _thisPvNm(pdiA, diA);
|
||
|
|
||
|
hres = CDIObj_CreateDeviceHelper(this, rguid, (PPV)ppdidA,
|
||
|
punkOuter, &IID_IDirectInputDeviceA);
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpv(ppdidA);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | CreateDeviceEx |
|
||
|
*
|
||
|
* Creates and initializes an instance of a device which is
|
||
|
* specified by the GUID. CreateDeviceEx allows an app to
|
||
|
* directly create a IID_IDirectInputDevice7 interface without
|
||
|
* going through a CreateDevice() and QI the interface
|
||
|
* for an IID_IDirectInput7.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm REFGUID | rguid |
|
||
|
* Identifies the instance of the
|
||
|
* device for which the indicated interface
|
||
|
* is requested. The <mf IDirectInput::EnumDevices> method
|
||
|
* can be used to determine which instance GUIDs are supported by
|
||
|
* the system.
|
||
|
*
|
||
|
* @parm REFIID | riid |
|
||
|
* Identifies the REFIID for the interface. Currently accepted values
|
||
|
* are IID_IDirectInputDevice, IID_IDirectInputDevice2, IID_IDirectInputDevice7.
|
||
|
*
|
||
|
*
|
||
|
* @parm OUT LPVOID * | pvOut |
|
||
|
* Points to where to return
|
||
|
* the pointer to the <i IDirectInputDevice#> interface, if successful.
|
||
|
*
|
||
|
* @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown
|
||
|
* for OLE aggregation, or 0 if the interface is not aggregated.
|
||
|
* Most callers will pass 0.
|
||
|
*
|
||
|
* @comm Calling this function with <p punkOuter> = NULL
|
||
|
* is equivalent to creating the object via
|
||
|
* <f CoCreateInstance>(&CLSID_DirectInputDevice, NULL,
|
||
|
* CLSCTX_INPROC_SERVER, <p riid>, <p lplpDirectInputDevice>);
|
||
|
* then initializing it with <f Initialize>.
|
||
|
*
|
||
|
* Calling this function with <p punkOuter> != NULL
|
||
|
* is equivalent to creating the object via
|
||
|
* <f CoCreateInstance>(&CLSID_DirectInputDevice, <p punkOuter>,
|
||
|
* CLSCTX_INPROC_SERVER, &IID_IUnknown, <p lplpDirectInputDevice>).
|
||
|
* The aggregated object must be initialized manually.
|
||
|
*
|
||
|
* @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_INVALIDPARAM> = <c E_INVALIDARG>: The
|
||
|
* <p ppvOut> parameter is not a valid pointer.
|
||
|
*
|
||
|
* <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
|
||
|
* Out of memory.
|
||
|
*
|
||
|
* <c DIERR_NOINTERFACE> = <c E_NOINTERFACE>
|
||
|
* The specified interface is not supported by the object.
|
||
|
*
|
||
|
* <c DIERR_DEVICENOTREG> = The device instance does not
|
||
|
* correspond to a device that is registered with DirectInput.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_CreateDeviceExW(PV pdiW, REFGUID rguid, REFIID riid, LPVOID * pvOut, PUNK punkOuter)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::CreateDeviceEx,
|
||
|
(_ "pGGp", pdiW, rguid, riid, punkOuter));
|
||
|
|
||
|
if(SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW)))
|
||
|
{
|
||
|
PDDI this = _thisPvNm(pdiW, diW);
|
||
|
|
||
|
hres = CDIObj_CreateDeviceHelper(this, rguid, pvOut,
|
||
|
punkOuter, riid);
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpv(pvOut);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_CreateDeviceExA(PV pdiA, REFGUID rguid, REFIID riid, LPVOID * pvOut, PUNK punkOuter)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::CreateDevice,
|
||
|
(_ "pGp", pdiA, rguid, riid, punkOuter));
|
||
|
|
||
|
if(SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA)))
|
||
|
{
|
||
|
PDDI this = _thisPvNm(pdiA, diA);
|
||
|
|
||
|
hres = CDIObj_CreateDeviceHelper(this, rguid, pvOut,
|
||
|
punkOuter, riid);
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpv(pvOut);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func HRESULT | CDIObj_TestDeviceFlags |
|
||
|
*
|
||
|
* Determines whether the device matches the specified flags.
|
||
|
* Phantom devices are treated as not really there.
|
||
|
*
|
||
|
* @parm PDIDW | pdidW |
|
||
|
*
|
||
|
* Device to be queried.
|
||
|
*
|
||
|
* @parm DWORD | edfl |
|
||
|
*
|
||
|
* Enumeration flags. It is one or more <c DIEDFL_*> values.
|
||
|
*
|
||
|
* The bits in the enumeration flags are in two categories.*
|
||
|
*
|
||
|
* Normal flags are the ones whose presence requires that
|
||
|
* the corresponding bit in the device flags also be set.
|
||
|
*
|
||
|
* Inverted flags (<c DIEDFL_INCLUDEMASK>) are the ones whose
|
||
|
* absence requires that the corresponding bit in the device
|
||
|
* flags also be absent.
|
||
|
*
|
||
|
* By inverting the inclusion flags in both the enumeration
|
||
|
* flags and the actual device flags, and then treating the
|
||
|
* whole thing as a bunch of normal flags, we get the desired
|
||
|
* behavior for the inclusion flags.
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* <c S_OK> if the device meets the criteria.
|
||
|
*
|
||
|
* <c S_FALSE> if the device does not meet the criteria.
|
||
|
* Note that <mf DirectInput::GetDeviceStatus> relies on
|
||
|
* this specific return value.
|
||
|
*
|
||
|
* Other error code as appropriate.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
HRESULT EXTERNAL
|
||
|
CDIObj_TestDeviceFlags(PDIDW pdidW, DWORD edfl)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
DIDEVCAPS_DX3 dc;
|
||
|
EnterProcI(CDIObj_TestDeviceFlags, (_ "px", pdidW, edfl));
|
||
|
|
||
|
/*
|
||
|
* We intentionally use a DIDEVCAPS_DX3 because going for
|
||
|
* a full DIDEVCAPS_DX5 requires us to load the force
|
||
|
* feedback driver which is pointless for our current
|
||
|
* goal.
|
||
|
*/
|
||
|
dc.dwSize = cbX(dc);
|
||
|
|
||
|
hres = IDirectInputDevice_GetCapabilities(pdidW, (PV)&dc);
|
||
|
|
||
|
AssertF(dc.dwSize == cbX(dc));
|
||
|
|
||
|
CAssertF(DIEDFL_ATTACHEDONLY == DIDC_ATTACHED);
|
||
|
CAssertF(DIEDFL_FORCEFEEDBACK == DIDC_FORCEFEEDBACK);
|
||
|
CAssertF(DIEDFL_INCLUDEALIASES == DIDC_ALIAS);
|
||
|
CAssertF(DIEDFL_INCLUDEPHANTOMS == DIDC_PHANTOM);
|
||
|
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
if (fHasAllBitsFlFl(dc.dwFlags ^ DIEDFL_INCLUDEMASK,
|
||
|
edfl ^ DIEDFL_INCLUDEMASK)) {
|
||
|
hres = S_OK;
|
||
|
} else {
|
||
|
/*
|
||
|
* Note: DX3 and DX5 returned E_DEVICENOTREG for
|
||
|
* phantom devices. Now we return S_FALSE. Let's
|
||
|
* hope nobody gets upset.
|
||
|
*/
|
||
|
hres = S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | EnumDevices |
|
||
|
*
|
||
|
* Enumerates the DirectInput devices that are attached to
|
||
|
* or could be attached to the computer.
|
||
|
*
|
||
|
* For example, an external game port may support a joystick
|
||
|
* or a steering wheel, but only one can be plugged in at a
|
||
|
* time. <mf IDirectInput::EnumDevices> will enumerate both
|
||
|
* devices.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm DWORD | dwDevType |
|
||
|
*
|
||
|
* Device type filter. If 0, then all device types are
|
||
|
* enumerated. Otherwise, it is a <c DIDEVTYPE_*> value,
|
||
|
* indicating the device type that should be enumerated.
|
||
|
*
|
||
|
* @parm LPDIENUMDEVICESCALLBACK | lpCallback |
|
||
|
* Points to an application-defined callback function.
|
||
|
* For more information, see the description of the
|
||
|
* <f DIEnumDevicesProc> callback function.
|
||
|
*
|
||
|
* @parm IN LPVOID | pvRef |
|
||
|
* Specifies a 32-bit application-defined
|
||
|
* value to be passed to the callback function. This value
|
||
|
* may be any 32-bit value; it is prototyped as an <t LPVOID>
|
||
|
* for convenience.
|
||
|
*
|
||
|
* @parm DWORD | fl |
|
||
|
* Optional flags which control the enumeration. The
|
||
|
* following flags are defined and may be combined.
|
||
|
*
|
||
|
* <c DIEDFL_ATTACHEDONLY>: Enumerate only attached devices.
|
||
|
*
|
||
|
* <c DIEDFL_FORCEFEEDBACK>: Enumerate only devices which
|
||
|
* support force feedback. This flag is new for DirectX 5.0.
|
||
|
*
|
||
|
* <c DIEDFL_INCLUDEALIASES>: Include alias devices in the
|
||
|
* enumeration. If this flag is not specified, then devices
|
||
|
* which are aliases of other devices (indicated by the
|
||
|
* <c DIDC_ALIAS> flag in the <e DIDEVCAPS.dwFlags> field
|
||
|
* of the <t DIDEVCAPS> structure) will be excluded from
|
||
|
* the enumeration. This flag is new for DirectX 5.0a.
|
||
|
*
|
||
|
* <c DIEDFL_INCLUDEPHANTOMS>: Include phantom devices in the
|
||
|
* enumeration. If this flag is not specified, then devices
|
||
|
* which are phantoms (indicated by the
|
||
|
* <c DIDC_PHANTOM> flag in the <e DIDEVCAPS.dwFlags> field
|
||
|
* of the <t DIDEVCAPS> structure) will be excluded from
|
||
|
* the enumeration. This flag is new for DirectX 5.0a.
|
||
|
*
|
||
|
* The default is
|
||
|
* <c DIEDFL_ALLDEVICES>: Enumerate all installed devices.
|
||
|
*
|
||
|
* @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.
|
||
|
* Note that if the callback stops the enumeration prematurely,
|
||
|
* the enumeration is considered to have succeeded.
|
||
|
*
|
||
|
* <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
|
||
|
* <p fl> parameter contains invalid flags, or the callback
|
||
|
* procedure returned an invalid status code.
|
||
|
*
|
||
|
* @cb BOOL CALLBACK | DIEnumDevicesProc |
|
||
|
*
|
||
|
* An application-defined callback function that receives
|
||
|
* DirectInput devices as a result of a call to the
|
||
|
* <om IDirectInput::EnumDevices> method.
|
||
|
*
|
||
|
* @parm IN LPDIDEVICEINSTANCE | lpddi |
|
||
|
*
|
||
|
* Structure that describes the device instance.
|
||
|
*
|
||
|
*
|
||
|
* @parm IN OUT LPVOID | pvRef |
|
||
|
* Specifies the application-defined value given in the
|
||
|
* <mf IDirectInput::EnumDevices> function.
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* Returns <c DIENUM_CONTINUE> to continue the enumeration
|
||
|
* or <c DIENUM_STOP> to stop the enumeration.
|
||
|
*
|
||
|
*//**************************************************************************
|
||
|
*
|
||
|
* In DEBUG/RDEBUG, if the callback returns a bogus value, raise
|
||
|
* a validation exception.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
HRESULT INLINE
|
||
|
CDIObj_EnumDevices_IsValidTypeFilter(DWORD dwDevType)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
/*
|
||
|
* First make sure the type mask is okay.
|
||
|
*/
|
||
|
if ((dwDevType & DIDEVTYPE_TYPEMASK) < DIDEVTYPE_MAX) {
|
||
|
|
||
|
/*
|
||
|
* Now make sure attribute masks are okay.
|
||
|
*/
|
||
|
if (dwDevType & DIDEVTYPE_ENUMMASK & ~DIDEVTYPE_ENUMVALID) {
|
||
|
RPF("IDirectInput::EnumDevices: Invalid dwDevType");
|
||
|
hres = E_INVALIDARG;
|
||
|
} else {
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
RPF("IDirectInput::EnumDevices: Invalid dwDevType");
|
||
|
hres = E_INVALIDARG;
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_EnumDevicesW(PV pdiW, DWORD dwDevType,
|
||
|
LPDIENUMDEVICESCALLBACKW pec, LPVOID pvRef, DWORD fl)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::EnumDevices,
|
||
|
(_ "pxppx", pdiW, dwDevType, pec, pvRef, fl));
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW)) &&
|
||
|
SUCCEEDED(hres = hresFullValidPfn(pec, 2)) &&
|
||
|
SUCCEEDED(hres = CDIObj_EnumDevices_IsValidTypeFilter(dwDevType)) &&
|
||
|
SUCCEEDED(hres = hresFullValidFl(fl, DIEDFL_VALID, 4))) {
|
||
|
PDDI this = _thisPvNm(pdiW, diW);
|
||
|
|
||
|
if(SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion))) {
|
||
|
|
||
|
CDIDEnum *pde;
|
||
|
|
||
|
hres = CDIDEnum_New(&this->diW, dwDevType, fl, this->dwVersion, &pde);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
DIDEVICEINSTANCEW ddiW;
|
||
|
ddiW.dwSize = cbX(ddiW);
|
||
|
|
||
|
while ((hres = CDIDEnum_Next(pde, &ddiW)) == S_OK) {
|
||
|
BOOL fRc;
|
||
|
|
||
|
/*
|
||
|
* WARNING! "goto" here! Make sure that nothing
|
||
|
* is held while we call the callback.
|
||
|
*/
|
||
|
fRc = Callback(pec, &ddiW, pvRef);
|
||
|
|
||
|
switch (fRc) {
|
||
|
case DIENUM_STOP: goto enumdoneok;
|
||
|
case DIENUM_CONTINUE: break;
|
||
|
default:
|
||
|
RPF("%s: Invalid return value from callback", s_szProc);
|
||
|
ValidationException();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
AssertF(hres == S_FALSE);
|
||
|
enumdoneok:;
|
||
|
CDIDEnum_Release(pde);
|
||
|
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitOleProcR();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func BOOL | CDIObj_EnumDevicesCallbackA |
|
||
|
*
|
||
|
* Wrapper function for <mf IDirectInput::EnumDevices>
|
||
|
* which translates the UNICODE parameters to ANSI.
|
||
|
*
|
||
|
* @parm IN LPCDIDECICEINSTANCEW | pdiW |
|
||
|
*
|
||
|
* Same as <mf IDirectInput::EnumDevices>.
|
||
|
*
|
||
|
* @parm IN OUT PV | pvRef |
|
||
|
*
|
||
|
* Pointer to <t struct ENUMDEVICESINFO> which describes
|
||
|
* the original callback.
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* Returns whatever the original callback returned.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
typedef struct ENUMDEVICESINFO {
|
||
|
LPDIENUMDEVICESCALLBACKA pecA;
|
||
|
PV pvRef;
|
||
|
} ENUMDEVICESINFO, *PENUMDEVICESINFO;
|
||
|
|
||
|
BOOL CALLBACK
|
||
|
CDIObj_EnumDevicesCallback(LPCDIDEVICEINSTANCEW pdiW, PV pvRef)
|
||
|
{
|
||
|
PENUMDEVICESINFO pedi = pvRef;
|
||
|
BOOL fRc;
|
||
|
DIDEVICEINSTANCEA diA;
|
||
|
EnterProc(CDIObj_EnumDevicesCallback,
|
||
|
(_ "GGxWWp", &pdiW->guidInstance, &pdiW->guidProduct,
|
||
|
&pdiW->dwDevType,
|
||
|
pdiW->tszProductName, pdiW->tszInstanceName,
|
||
|
pvRef));
|
||
|
|
||
|
diA.dwSize = cbX(diA);
|
||
|
DeviceInfoWToA(&diA, pdiW);
|
||
|
|
||
|
fRc = pedi->pecA(&diA, pedi->pvRef);
|
||
|
|
||
|
ExitProcX(fRc);
|
||
|
return fRc;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInputA | EnumDevices |
|
||
|
*
|
||
|
* ANSI version of <mf IDirectInput::EnumDevices>.
|
||
|
* We wrap the operation.
|
||
|
*
|
||
|
* @parm IN LPGUID | lpGUIDDeviceType |
|
||
|
* Same as <mf IDirectInput::EnumDevices>.
|
||
|
*
|
||
|
* @parm LPDIENUMDEVICESCALLBACKA | lpCallbackA |
|
||
|
* Same as <mf IDirectInput::EnumDevices>, except ANSI.
|
||
|
*
|
||
|
* @parm IN LPVOID | pvRef |
|
||
|
* Same as <mf IDirectInput::EnumDevices>.
|
||
|
*
|
||
|
* @parm DWORD | fl |
|
||
|
* Same as <mf IDirectInput::EnumDevices>.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_EnumDevicesA(PV pdiA, DWORD dwDevType,
|
||
|
LPDIENUMDEVICESCALLBACKA pec, LPVOID pvRef, DWORD fl)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::EnumDevices,
|
||
|
(_ "pxppx", pdiA, dwDevType, pec, pvRef, fl));
|
||
|
|
||
|
/*
|
||
|
* EnumDevicesW will validate the rest.
|
||
|
*/
|
||
|
if (SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA)) &&
|
||
|
SUCCEEDED(hres = hresFullValidPfn(pec, 1))) {
|
||
|
ENUMDEVICESINFO edi = { pec, pvRef };
|
||
|
PDDI this = _thisPvNm(pdiA, diA);
|
||
|
hres = CDIObj_EnumDevicesW(&this->diW, dwDevType,
|
||
|
CDIObj_EnumDevicesCallback, &edi, fl);
|
||
|
}
|
||
|
|
||
|
ExitOleProcR();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | GetDeviceStatus |
|
||
|
*
|
||
|
* Determine whether a device is currently attached.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm REFGUID | rguid |
|
||
|
*
|
||
|
* Identifies the instance of the
|
||
|
* device whose status is being checked.
|
||
|
*
|
||
|
* @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 device is attached.
|
||
|
*
|
||
|
* <c DI_NOTATTACHED> = <c S_FALSE>: The device is not
|
||
|
* attached.
|
||
|
*
|
||
|
* <c E_FAIL>: DirectInput could not determine
|
||
|
* whether the device is attached.
|
||
|
*
|
||
|
* <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
|
||
|
* device does not exist.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_GetDeviceStatus(PV pdi, REFGUID rguid _THAT)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::GetDeviceStatus, (_ "pG", pdi, rguid));
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvT(pdi))) {
|
||
|
PDDI this = _thisPv(pdi);
|
||
|
PDIDW pdidW;
|
||
|
|
||
|
hres = IDirectInput_CreateDevice(&this->diW, rguid, (PV)&pdidW, 0);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
hres = CDIObj_TestDeviceFlags(pdidW, DIEDFL_ATTACHEDONLY);
|
||
|
OLE_Release(pdidW);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
#ifdef XDEBUG
|
||
|
|
||
|
CSET_STUBS(GetDeviceStatus, (PV pdi, REFGUID rguid), (pdi, rguid THAT_))
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define CDIObj_GetDeviceStatusA CDIObj_GetDeviceStatus
|
||
|
#define CDIObj_GetDeviceStatusW CDIObj_GetDeviceStatus
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef DO_THE_IMPOSSIBLE
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | SetAttachedDevice |
|
||
|
*
|
||
|
* Informs DirectInput that a new device has been attached
|
||
|
* to the system by the user. This is useful when an application
|
||
|
* asks the user to attach a currently installed device but does
|
||
|
* not want to launch the DirectInput control panel.
|
||
|
*
|
||
|
* DirectInput needs to be informed that the device has
|
||
|
* been attached for internal bookkeeping purposes.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm IN LPDIRECTINPUTDEVICE | lpDIDevice |
|
||
|
*
|
||
|
* Identifies the device which has been attached.
|
||
|
*
|
||
|
* @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 device is attached.
|
||
|
*
|
||
|
* @devnote
|
||
|
*
|
||
|
* This method is not implemented in the current release
|
||
|
* of DirectInput.
|
||
|
*
|
||
|
* This won't work. We need to receive a port, too.
|
||
|
* And how can the app create a <p lpDIDevice> in the
|
||
|
* first place for a device that does not exist?
|
||
|
* I guess I just don't understand.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_SetAttachedDevice(PV pdi, PV pdid _THAT)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::SetAttachedDevice, (_ "pp", pdi, pdid));
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvT(pdi))) {
|
||
|
PDDI this = _thisPv(pdi);
|
||
|
|
||
|
hres = E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
#ifdef XDEBUG
|
||
|
|
||
|
CSET_STUBS(SetAttachedDevice, (PV pdi, PV pdid), (pdi, pdid THAT_))
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define CDIObj_SetAttachedDeviceA CDIObj_SetAttachedDevice
|
||
|
#define CDIObj_SetAttachedDeviceW CDIObj_SetAttachedDevice
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | RunControlPanel |
|
||
|
*
|
||
|
* Run the DirectInput control panel so that the user can
|
||
|
* install a new input device or modify the setup.
|
||
|
*
|
||
|
* This function will not run third-party control panels.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm IN HWND | hwndOwner |
|
||
|
*
|
||
|
* Identifies the window handle that will be used as the
|
||
|
* parent window for subsequent UI. NULL is a valid parameter,
|
||
|
* indicating that there is no parent window.
|
||
|
*
|
||
|
* @parm DWORD | dwFlags |
|
||
|
*
|
||
|
* No flags are currently defined. This parameter "must" be
|
||
|
* zero.
|
||
|
*
|
||
|
* @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 device is attached.
|
||
|
*
|
||
|
* @devnote
|
||
|
*
|
||
|
* The <p dwFlags> is eventually going to allow
|
||
|
* <c DIRCP_MODAL> to request a modal control panel.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#pragma BEGIN_CONST_DATA
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_RunControlPanel(PV pdi, HWND hwndOwner, DWORD fl _THAT)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::RunControlPanel, (_ "pxx", pdi, hwndOwner, fl));
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvT(pdi)) &&
|
||
|
SUCCEEDED(hres = hresFullValidHwnd0(hwndOwner, 1)) &&
|
||
|
SUCCEEDED(hres = hresFullValidFl(fl, DIRCP_VALID, 2)) ) {
|
||
|
|
||
|
PDDI this = _thisPv(pdi);
|
||
|
|
||
|
if(SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion))) {
|
||
|
|
||
|
/*
|
||
|
* We used to run "directx.cpl,@0,3" but directx.cpl is not
|
||
|
* redistributable; it comes only with the SDK. So we just
|
||
|
* run the system control panel.
|
||
|
*/
|
||
|
|
||
|
hres = hresRunControlPanel(TEXT(""));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
#ifdef XDEBUG
|
||
|
|
||
|
CSET_STUBS(RunControlPanel, (PV pdi, HWND hwndOwner, DWORD fl),
|
||
|
(pdi, hwndOwner, fl THAT_))
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define CDIObj_RunControlPanelA CDIObj_RunControlPanel
|
||
|
#define CDIObj_RunControlPanelW CDIObj_RunControlPanel
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput | Initialize |
|
||
|
*
|
||
|
* Initialize a DirectInput object.
|
||
|
*
|
||
|
* The <f DirectInputCreate> method automatically
|
||
|
* initializes the DirectInput object device after creating it.
|
||
|
* Applications normally do not need to call this function.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT | lpDirectInput
|
||
|
*
|
||
|
* @parm IN HINSTANCE | hinst |
|
||
|
*
|
||
|
* Instance handle of the application or DLL that is creating
|
||
|
* the DirectInput object.
|
||
|
*
|
||
|
* See the section titled "Initialization and Versions"
|
||
|
* for more information.
|
||
|
*
|
||
|
* @parm DWORD | dwVersion |
|
||
|
*
|
||
|
* Version number of the dinput.h header file that was used.
|
||
|
*
|
||
|
* See the section titled "Initialization and Versions"
|
||
|
* for more information.
|
||
|
*
|
||
|
* @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 device is attached.
|
||
|
*
|
||
|
* <c DIERR_DIERR_OLDDIRECTINPUTVERSION>: The application
|
||
|
* requires a newer version of DirectInput.
|
||
|
*
|
||
|
* <c DIERR_DIERR_BETADIRECTINPUTVERSION>: The application
|
||
|
* was written for an unsupported prerelease version
|
||
|
* of DirectInput.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_Initialize(PV pdi, HINSTANCE hinst, DWORD dwVersion _THAT)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::Initialize, (_ "pxx", pdi, hinst, dwVersion));
|
||
|
|
||
|
AhAppRegister(dwVersion);
|
||
|
|
||
|
if (SUCCEEDED(hres = hresPvT(pdi))) {
|
||
|
PDDI this = _thisPv(pdi);
|
||
|
|
||
|
if (SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion))) {
|
||
|
this->dwVersion = dwVersion;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifndef DX_FINAL_RELEASE
|
||
|
{
|
||
|
#pragma message("BETA EXPIRATION TIME BOMB! Remove for final build!")
|
||
|
SYSTEMTIME st;
|
||
|
GetSystemTime(&st);
|
||
|
|
||
|
if ( st.wYear > DX_EXPIRE_YEAR ||
|
||
|
((st.wYear == DX_EXPIRE_YEAR) && (MAKELONG(st.wDay, st.wMonth) > MAKELONG(DX_EXPIRE_DAY, DX_EXPIRE_MONTH)))
|
||
|
) {
|
||
|
MessageBox(0, DX_EXPIRE_TEXT,
|
||
|
TEXT("Microsoft DirectInput"), MB_OK);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
#ifdef XDEBUG
|
||
|
|
||
|
CSET_STUBS(Initialize, (PV pdi, HINSTANCE hinst, DWORD dwVersion),
|
||
|
(pdi, hinst, dwVersion THAT_))
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define CDIObj_InitializeA CDIObj_Initialize
|
||
|
#define CDIObj_InitializeW CDIObj_Initialize
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef IDirectInput2Vtbl
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @func HRESULT | CDIObj_FindDeviceInternal |
|
||
|
*
|
||
|
* The worker function for
|
||
|
* <mf IDirectInput2::FindDevice> which works only for HID devices.
|
||
|
*
|
||
|
* For more details, see <mf IDirectInput2::FindDevice>.
|
||
|
*
|
||
|
* @parm LPCTSTR | ptszName |
|
||
|
*
|
||
|
* The name of the device relative to the class <t GUID>.
|
||
|
*
|
||
|
* @parm OUT LPGUID | pguidOut |
|
||
|
*
|
||
|
* Pointer to a <t GUID> which receives the instance
|
||
|
* <t GUID> for the device, if the device is found.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
HRESULT EXTERNAL
|
||
|
CDIObj_FindDeviceInternal(LPCTSTR ptszName, LPGUID pguidOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
|
||
|
/*
|
||
|
* Look twice. If it's not found the first time,
|
||
|
* then refresh the cache and try again in case
|
||
|
* it was for a device that was recently added.
|
||
|
* (In fact, it will likely be a device that was
|
||
|
* recently added, because FindDevice is usually
|
||
|
* called in response to a Plug and Play event.)
|
||
|
*/
|
||
|
hres = hresFindHIDDeviceInterface(ptszName, pguidOut);
|
||
|
if (FAILED(hres)) {
|
||
|
DIHid_BuildHidList(TRUE);
|
||
|
hres = hresFindHIDDeviceInterface(ptszName, pguidOut);
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc EXTERNAL
|
||
|
*
|
||
|
* @method HRESULT | IDirectInput2 | FindDevice |
|
||
|
*
|
||
|
* Obtain the instance <t GUID> for a device given
|
||
|
* its class <t GUID> and an opaque name.
|
||
|
*
|
||
|
* This method can be used by applications which register
|
||
|
* for Plug and Play notifications and are notified by
|
||
|
* Plug and Play that a new device has been added
|
||
|
* to the system. The Plug and Play notification will
|
||
|
* be in the form of a class <t GUID> and a device name.
|
||
|
* The application can pass the <t GUID> and name to
|
||
|
* this method to obtain the instance <t GUID> for
|
||
|
* the device, which can then be passed to
|
||
|
* <mf IDirectInput::CreateDevice> or
|
||
|
* <mf IDirectInput::GetDeviceStatus>.
|
||
|
*
|
||
|
* @cwrap LPDIRECTINPUT2 | lpDirectInput2
|
||
|
*
|
||
|
* @parm REFGUID | rguidClass |
|
||
|
*
|
||
|
* Class <t GUID> identifying the device class
|
||
|
* for the device the application wishes to locate.
|
||
|
*
|
||
|
* The application obtains the class <t GUID> from the
|
||
|
* Plug and Play device arrival notification.
|
||
|
*
|
||
|
* @parm LPCTSTR | ptszName |
|
||
|
*
|
||
|
* The name of the device relative to the class <t GUID>.
|
||
|
*
|
||
|
* The application obtains the class name from the
|
||
|
* Plug and Play device arrival notification.
|
||
|
*
|
||
|
* @parm OUT LPGUID | pguidInstance |
|
||
|
*
|
||
|
* Pointer to a <t GUID> which receives the instance
|
||
|
* <t GUID> for the device, if the device is found.
|
||
|
*
|
||
|
* @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 device was found, and its
|
||
|
* instance <t GUID> has been stored in <p pguidInstance>.
|
||
|
*
|
||
|
* <c DIERR_DEVICENOTREG> = The <t GUID> and name do not
|
||
|
* correspond to a device that is registered with DirectInput.
|
||
|
* For example, they may refer to a storage device rather
|
||
|
* than an input device.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#define cchNameMax MAX_PATH
|
||
|
|
||
|
STDMETHODIMP
|
||
|
TFORM(CDIObj_FindDevice)(PV pdiT, REFGUID rguid,
|
||
|
LPCTSTR ptszName, LPGUID pguidOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput2::FindDevice,
|
||
|
(_ "pGs", pdiT, rguid, ptszName));
|
||
|
|
||
|
if (SUCCEEDED(hres = TFORM(hresPv)(pdiT)) &&
|
||
|
SUCCEEDED(hres = hresFullValidGuid(rguid, 1)) &&
|
||
|
SUCCEEDED(hres = TFORM(hresFullValidReadStr)(ptszName,
|
||
|
cchNameMax, 2)) &&
|
||
|
SUCCEEDED(hres = hresFullValidWritePvCb(pguidOut, cbX(GUID), 3))) {
|
||
|
|
||
|
if (IsEqualIID(rguid, &GUID_HIDClass)) {
|
||
|
hres = CDIObj_FindDeviceInternal(ptszName, pguidOut);
|
||
|
} else {
|
||
|
hres = DIERR_DEVICENOTREG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
SFORM(CDIObj_FindDevice)(PV pdiS, REFGUID rguid,
|
||
|
LPCSSTR psszName, LPGUID pguidOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
TCHAR tsz[cchNameMax];
|
||
|
EnterProcR(IDirectInput2::FindDevice,
|
||
|
(_ "pGS", pdiS, rguid, psszName));
|
||
|
|
||
|
/*
|
||
|
* TFORM(CDIObj_FindDevice) will validate the rguid and pguidOut.
|
||
|
*/
|
||
|
if (SUCCEEDED(hres = SFORM(hresPv)(pdiS)) &&
|
||
|
SUCCEEDED(hres = SFORM(hresFullValidReadStr)(psszName, cA(tsz), 2))) {
|
||
|
PDDI this = _thisPvNm(pdiS, SFORM(di));
|
||
|
|
||
|
SToT(tsz, cA(tsz), psszName);
|
||
|
|
||
|
hres = TFORM(CDIObj_FindDevice)(&this->TFORM(di), rguid, tsz, pguidOut);
|
||
|
}
|
||
|
|
||
|
ExitOleProc();
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @mfunc HRESULT | IDirectInput | New |
|
||
|
*
|
||
|
* Create a new instance of an IDirectInput object.
|
||
|
*
|
||
|
* @parm IN PUNK | punkOuter |
|
||
|
*
|
||
|
* Controlling unknown for aggregation.
|
||
|
*
|
||
|
* @parm IN RIID | riid |
|
||
|
* Desired interface to new object.
|
||
|
*
|
||
|
* @parm OUT PPV | ppvObj |
|
||
|
* Output pointer for new object.
|
||
|
*
|
||
|
* @returns
|
||
|
*
|
||
|
* Standard OLE <t HRESULT>.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDIObj_New(PUNK punkOuter, RIID riid, PPV ppvObj)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
EnterProcR(IDirectInput::CreateInstance, (_ "Gp", riid, ppvObj));
|
||
|
|
||
|
hres = Excl_Init();
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
|
||
|
/*
|
||
|
* Note that we cannot use Common_NewRiid for an object
|
||
|
* that aggregates other interfaces!
|
||
|
*
|
||
|
* The reason is that Common_NewRiid will perform
|
||
|
* a QI as part of the initialization, but we cannot handle
|
||
|
* the QI until after we've been initialized and are
|
||
|
* ready to mess with aggregated goo.
|
||
|
*/
|
||
|
|
||
|
if (SUCCEEDED(hres = hresFullValidRiid(riid, 2))) {
|
||
|
if (fLimpFF(punkOuter, IsEqualIID(riid, &IID_IUnknown))) {
|
||
|
|
||
|
hres = Common_New(CDIObj, punkOuter, ppvObj);
|
||
|
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
PDDI this = _thisPv(*ppvObj);
|
||
|
|
||
|
this->fCritInited = fInitializeCriticalSection(&this->crst);
|
||
|
if( this->fCritInited )
|
||
|
{
|
||
|
/*
|
||
|
* Only after the object is ready do we QI for the
|
||
|
* requested interface. And the reason is that the
|
||
|
* QI might cause us to create an aggregated buddy,
|
||
|
* which we can't do until we've been initialized.
|
||
|
*
|
||
|
* Don't do this extra QI if we are ourselves aggregated,
|
||
|
* or we will end up giving the wrong punk to the caller!
|
||
|
*/
|
||
|
if (punkOuter == 0) {
|
||
|
hres = OLE_QueryInterface(this, riid, ppvObj);
|
||
|
OLE_Release(this);
|
||
|
}
|
||
|
if (FAILED(hres)) {
|
||
|
Invoke_Release(ppvObj);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Common_Unhold(this);
|
||
|
*ppvObj = NULL;
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
RPF("CreateDevice: IID must be IID_IUnknown if created for aggregation");
|
||
|
*ppvObj = 0;
|
||
|
hres = CLASS_E_NOAGGREGATION;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitOleProcPpvR(ppvObj);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* The long-awaited vtbls and templates
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#pragma BEGIN_CONST_DATA
|
||
|
|
||
|
#define CDIObj_Signature 0x504E4944 /* "DINP" */
|
||
|
|
||
|
Interface_Template_Begin(CDIObj)
|
||
|
Primary_Interface_Template(CDIObj, TFORM(ThisInterfaceT))
|
||
|
Secondary_Interface_Template(CDIObj, SFORM(ThisInterfaceT))
|
||
|
Interface_Template_End(CDIObj)
|
||
|
|
||
|
Primary_Interface_Begin(CDIObj, TFORM(ThisInterfaceT))
|
||
|
TFORM(CDIObj_CreateDevice),
|
||
|
TFORM(CDIObj_EnumDevices),
|
||
|
TFORM(CDIObj_GetDeviceStatus),
|
||
|
TFORM(CDIObj_RunControlPanel),
|
||
|
TFORM(CDIObj_Initialize),
|
||
|
#ifdef IDirectInput2Vtbl
|
||
|
TFORM(CDIObj_FindDevice),
|
||
|
#ifdef IDirectInput7Vtbl
|
||
|
TFORM(CDIObj_CreateDeviceEx),
|
||
|
#endif
|
||
|
#endif
|
||
|
Primary_Interface_End(CDIObj, TFORM(ThisInterfaceT))
|
||
|
|
||
|
Secondary_Interface_Begin(CDIObj, SFORM(ThisInterfaceT), SFORM(di))
|
||
|
SFORM(CDIObj_CreateDevice),
|
||
|
SFORM(CDIObj_EnumDevices),
|
||
|
SFORM(CDIObj_GetDeviceStatus),
|
||
|
SFORM(CDIObj_RunControlPanel),
|
||
|
SFORM(CDIObj_Initialize),
|
||
|
#ifdef IDirectInput2Vtbl
|
||
|
SFORM(CDIObj_FindDevice),
|
||
|
#ifdef IDirectInput7Vtbl
|
||
|
SFORM(CDIObj_CreateDeviceEx),
|
||
|
#endif
|
||
|
#endif
|
||
|
Secondary_Interface_End(CDIObj, SFORM(ThisInterfaceT), SFORM(di))
|