/***************************************************************************** * * 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 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 . * *//************************************************************************** * * @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 . * ***************************************************************************** * * @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 . * *****************************************************************************/ #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 * 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 . * * @parm OUT PPV | ppvObj | * * See . * * @parm IN LPUNKNOWN | punkOuter | * * See . * * @parm IN RIID | riid | * * The interface the application wants to create. This will * be either or . * 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 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 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

= NULL * is equivalent to creating the object via * (&CLSID_DirectInputDevice, NULL, * CLSCTX_INPROC_SERVER,

,

); * then initializing it with . * * Calling this function with

!= NULL * is equivalent to creating the object via * (&CLSID_DirectInputDevice,

, * CLSCTX_INPROC_SERVER, &IID_IUnknown,

). * 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. * * = : The operation completed successfully. * * = : The *

parameter is not a valid pointer. * * = : * Out of memory. * * = * The specified interface is not supported by the object. * * = 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 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 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

= NULL * is equivalent to creating the object via * (&CLSID_DirectInputDevice, NULL, * CLSCTX_INPROC_SERVER,

,

); * then initializing it with . * * Calling this function with

!= NULL * is equivalent to creating the object via * (&CLSID_DirectInputDevice,

, * CLSCTX_INPROC_SERVER, &IID_IUnknown,

). * 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. * * = : The operation completed successfully. * * = : The *

parameter is not a valid pointer. * * = : * Out of memory. * * = * The specified interface is not supported by the object. * * = 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 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 () 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 * * if the device meets the criteria. * * if the device does not meet the criteria. * Note that 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. 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 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 * 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 * for convenience. * * @parm DWORD | fl | * Optional flags which control the enumeration. The * following flags are defined and may be combined. * * : Enumerate only attached devices. * * : Enumerate only devices which * support force feedback. This flag is new for DirectX 5.0. * * : Include alias devices in the * enumeration. If this flag is not specified, then devices * which are aliases of other devices (indicated by the * flag in the field * of the structure) will be excluded from * the enumeration. This flag is new for DirectX 5.0a. * * : Include phantom devices in the * enumeration. If this flag is not specified, then devices * which are phantoms (indicated by the * flag in the field * of the structure) will be excluded from * the enumeration. This flag is new for DirectX 5.0a. * * The default is * : Enumerate all installed devices. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * = : The operation completed successfully. * Note that if the callback stops the enumeration prematurely, * the enumeration is considered to have succeeded. * * = : The *

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 * method. * * @parm IN LPDIDEVICEINSTANCE | lpddi | * * Structure that describes the device instance. * * * @parm IN OUT LPVOID | pvRef | * Specifies the application-defined value given in the * function. * * @returns * * Returns to continue the enumeration * or 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 * which translates the UNICODE parameters to ANSI. * * @parm IN LPCDIDECICEINSTANCEW | pdiW | * * Same as . * * @parm IN OUT PV | pvRef | * * Pointer to 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 . * We wrap the operation. * * @parm IN LPGUID | lpGUIDDeviceType | * Same as . * * @parm LPDIENUMDEVICESCALLBACKA | lpCallbackA | * Same as , except ANSI. * * @parm IN LPVOID | pvRef | * Same as . * * @parm DWORD | fl | * Same as . * *****************************************************************************/ 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. * * = : The device is attached. * * = : The device is not * attached. * * : DirectInput could not determine * whether the device is attached. * * = : 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. * * = : 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

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. * * = : The device is attached. * * @devnote * * The

is eventually going to allow * 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 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. * * = : The device is attached. * * : The application * requires a newer version of DirectInput. * * : 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 * which works only for HID devices. * * For more details, see . * * @parm LPCTSTR | ptszName | * * The name of the device relative to the class . * * @parm OUT LPGUID | pguidOut | * * Pointer to a which receives the instance * 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 for a device given * its class 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 and a device name. * The application can pass the and name to * this method to obtain the instance for * the device, which can then be passed to * or * . * * @cwrap LPDIRECTINPUT2 | lpDirectInput2 * * @parm REFGUID | rguidClass | * * Class identifying the device class * for the device the application wishes to locate. * * The application obtains the class from the * Plug and Play device arrival notification. * * @parm LPCTSTR | ptszName | * * The name of the device relative to the class . * * The application obtains the class name from the * Plug and Play device arrival notification. * * @parm OUT LPGUID | pguidInstance | * * Pointer to a which receives the instance * 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. * * = : The device was found, and its * instance has been stored in

. * * = The 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 . * *****************************************************************************/ 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))