Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1558 lines
46 KiB

  1. /*****************************************************************************
  2. *
  3. * DIObj.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The IDirectInput main interface.
  10. *
  11. * Contents:
  12. *
  13. * CDIObj_New
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. #include "verinfo.h" /* For #ifdef FINAL */
  18. /*****************************************************************************
  19. *
  20. * The sqiffle for this file.
  21. *
  22. *****************************************************************************/
  23. #define sqfl sqflDi
  24. /*****************************************************************************
  25. *
  26. * @doc INTERNAL
  27. *
  28. * @struct CDIObj |
  29. *
  30. * The <i IDirectInput> object, from which other things come.
  31. *
  32. * The A and W versions are simply alternate interfaces on the same
  33. * underlying object.
  34. *
  35. * There really isn't anything interesting in the structure
  36. * itself.
  37. *
  38. *
  39. * @field IDirectInputA | diA |
  40. *
  41. * ANSI DirectInput object (containing vtbl).
  42. *
  43. * @field IDirectInputW | diW |
  44. *
  45. * UNICODE DirectInput object (containing vtbl).
  46. *
  47. * @field IDirectInputJoyConfig *| pdjc |
  48. *
  49. * Aggregated joystick configuration interface (if created).
  50. *
  51. * @field BOOL | fCritInited:1 |
  52. *
  53. * Set if the critical section has been initialized.
  54. *
  55. * @field CRITICAL_SECTION | crst |
  56. *
  57. * Critical section that guards thread-sensitive data.
  58. *****************************************************************************/
  59. typedef struct CDIObj {
  60. /* Supported interfaces */
  61. TFORM(IDirectInput) TFORM(di);
  62. SFORM(IDirectInput) SFORM(di);
  63. DWORD dwVersion;
  64. IDirectInputJoyConfig *pdjc;
  65. BOOL fCritInited:1;
  66. CRITICAL_SECTION crst;
  67. } CDIObj, DDI, *PDDI;
  68. #define ThisClass CDIObj
  69. #ifdef IDirectInput7Vtbl
  70. #define ThisInterface TFORM(IDirectInput7)
  71. #define ThisInterfaceA IDirectInput7A
  72. #define ThisInterfaceW IDirectInput7W
  73. #define ThisInterfaceT IDirectInput7
  74. #else
  75. #ifdef IDirectInput2Vtbl
  76. #define ThisInterface TFORM(IDirectInput2)
  77. #define ThisInterfaceA IDirectInput2A
  78. #define ThisInterfaceW IDirectInput2W
  79. #define ThisInterfaceT IDirectInput2
  80. #else
  81. #define ThisInterface TFORM(IDirectInput)
  82. #define ThisInterfaceA IDirectInputA
  83. #define ThisInterfaceW IDirectInputW
  84. #define ThisInterfaceT IDirectInput
  85. #endif
  86. #endif
  87. /*****************************************************************************
  88. *
  89. * Declare the interfaces we will be providing.
  90. *
  91. *****************************************************************************/
  92. Primary_Interface(CDIObj, TFORM(ThisInterfaceT));
  93. Secondary_Interface(CDIObj, SFORM(ThisInterfaceT));
  94. /*****************************************************************************
  95. *
  96. * @doc EXTERNAL
  97. *
  98. * @method HRESULT | IDirectInput | QueryInterface |
  99. *
  100. * Gives a client access to other interfaces on an object.
  101. *
  102. * @cwrap LPDIRECTINPUT | lpDirectInput
  103. *
  104. * @parm IN REFIID | riid |
  105. *
  106. * The requested interface's IID.
  107. *
  108. * @parm OUT LPVOID * | ppvObj |
  109. *
  110. * Receives a pointer to the obtained interface.
  111. *
  112. * @returns
  113. *
  114. * Returns a COM error code.
  115. *
  116. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  117. *
  118. *//**************************************************************************
  119. *
  120. * @doc EXTERNAL
  121. *
  122. * @method HRESULT | IDirectInput | AddRef |
  123. *
  124. * Increments the reference count for the interface.
  125. *
  126. * @cwrap LPDIRECTINPUT | lpDirectInput
  127. *
  128. * @returns
  129. *
  130. * Returns the object reference count.
  131. *
  132. * @xref OLE documentation for <mf IUnknown::AddRef>.
  133. *
  134. *****************************************************************************
  135. *
  136. * @doc EXTERNAL
  137. *
  138. * @method HRESULT | IDirectInput | Release |
  139. *
  140. * Decrements the reference count for the interface.
  141. * If the reference count on the object falls to zero,
  142. * the object is freed from memory.
  143. *
  144. * @cwrap LPDIRECTINPUT | lpDirectInput
  145. *
  146. * @returns
  147. *
  148. * Returns the object reference count.
  149. *
  150. * @xref OLE documentation for <mf IUnknown::Release>.
  151. *
  152. *****************************************************************************/
  153. #ifdef DEBUG
  154. Default_QueryInterface(CDIObj)
  155. Default_AddRef(CDIObj)
  156. Default_Release(CDIObj)
  157. #else
  158. #define CDIObj_QueryInterface Common_QueryInterface
  159. #define CDIObj_AddRef Common_AddRef
  160. #define CDIObj_Release Common_Release
  161. #endif
  162. #define CDIObj_AppFinalize Common_AppFinalize
  163. /*****************************************************************************
  164. *
  165. * @doc INTERNAL
  166. *
  167. * @mfunc void | CDIObj | EnterCrit |
  168. *
  169. * Enter the object critical section.
  170. *
  171. * @doc INTERNAL
  172. *
  173. * @mfunc void | CDIObj | LeaveCrit |
  174. *
  175. * Leave the object critical section.
  176. *
  177. *****************************************************************************/
  178. void INLINE
  179. CDIObj_EnterCrit(PDDI this)
  180. {
  181. EnterCriticalSection(&this->crst);
  182. }
  183. void INLINE
  184. CDIObj_LeaveCrit(PDDI this)
  185. {
  186. LeaveCriticalSection(&this->crst);
  187. }
  188. /*****************************************************************************
  189. *
  190. * @doc INTERNAL
  191. *
  192. * @mfunc HRESULT | IDirectInput | QIHelper |
  193. *
  194. * We will dynamically create <i IDirectInputJoyConfig>
  195. * and aggregate it with us.
  196. *
  197. #ifdef IDirectInput2Vtbl
  198. * Support the original IDirectInput interfaces as well
  199. * as the new IDirectInput2 interfaces.
  200. #endif
  201. * @parm IN REFIID | riid |
  202. *
  203. * The requested interface's IID.
  204. *
  205. * @parm OUT LPVOID * | ppvObj |
  206. *
  207. * Receives a pointer to the obtained interface.
  208. *
  209. *****************************************************************************/
  210. STDMETHODIMP
  211. CDIObj_QIHelper(PDDI this, RIID riid, PPV ppvObj)
  212. {
  213. HRESULT hres;
  214. EnterProcI(CDIObj_QIHelper, (_ "pG", this, riid));
  215. if (IsEqualIID(riid, &IID_IDirectInputJoyConfig)) {
  216. *ppvObj = 0; /* In case the New fails */
  217. CDIObj_EnterCrit(this);
  218. if (this->pdjc == 0) {
  219. hres = CJoyCfg_New((PUNK)this, &IID_IUnknown, (PPV)&this->pdjc);
  220. } else {
  221. hres = S_OK;
  222. }
  223. CDIObj_LeaveCrit(this);
  224. if (SUCCEEDED(hres)) {
  225. /*
  226. * This QI will addref us if it succeeds.
  227. */
  228. hres = OLE_QueryInterface(this->pdjc, riid, ppvObj);
  229. } else {
  230. this->pdjc = 0;
  231. }
  232. #ifdef IDirectInput2Vtbl
  233. } else if (IsEqualIID(riid, &IID_IDirectInputA)) {
  234. *ppvObj = &this->diA;
  235. OLE_AddRef(this);
  236. hres = S_OK;
  237. } else if (IsEqualIID(riid, &IID_IDirectInputW)) {
  238. *ppvObj = &this->diW;
  239. OLE_AddRef(this);
  240. hres = S_OK;
  241. #endif
  242. #ifdef IDirectInput7Vtbl
  243. } else if (IsEqualIID(riid, &IID_IDirectInput2A)) {
  244. *ppvObj = &this->diA;
  245. OLE_AddRef(this);
  246. hres = S_OK;
  247. } else if (IsEqualIID(riid, &IID_IDirectInput2W)) {
  248. *ppvObj = &this->diW;
  249. OLE_AddRef(this);
  250. hres = S_OK;
  251. #endif //IDirectInput7Vtbl
  252. } else {
  253. hres = Common_QIHelper(this, riid, ppvObj);
  254. }
  255. ExitOleProcPpv(ppvObj);
  256. return hres;
  257. }
  258. /*****************************************************************************
  259. *
  260. * @doc INTERNAL
  261. *
  262. * @func void | CDIObj_Finalize |
  263. *
  264. * Clean up our instance data.
  265. *
  266. * @parm PV | pvObj |
  267. *
  268. * Object being released. Note that it may not have been
  269. * completely initialized, so everything should be done
  270. * carefully.
  271. *
  272. *****************************************************************************/
  273. void INTERNAL
  274. CDIObj_Finalize(PV pvObj)
  275. {
  276. PDDI this = pvObj;
  277. Invoke_Release(&this->pdjc);
  278. if (this->fCritInited) {
  279. DeleteCriticalSection(&this->crst);
  280. }
  281. }
  282. /*****************************************************************************
  283. *
  284. * @doc INTERNAL
  285. *
  286. * @method HRESULT | IDirectInput | CreateDeviceHelper |
  287. *
  288. * Creates and initializes an instance of a device which is
  289. * specified by the GUID and IID.
  290. *
  291. * @cwrap LPDIRECTINPUT | lpDirectInput
  292. *
  293. * @parm IN PCGUID | pguid |
  294. *
  295. * See <mf IDirectInput::CreateDevice>.
  296. *
  297. * @parm OUT PPV | ppvObj |
  298. *
  299. * See <mf IDirectInput::CreateDevice>.
  300. *
  301. * @parm IN LPUNKNOWN | punkOuter |
  302. *
  303. * See <mf IDirectInput::CreateDevice>.
  304. *
  305. * @parm IN RIID | riid |
  306. *
  307. * The interface the application wants to create. This will
  308. * be either <i IDirectInputDeviceA> or <i IDirectInputDeviceW>.
  309. * If the object is aggregated, then this parameter is ignored.
  310. *
  311. * @returns
  312. *
  313. * Returns a COM error code.
  314. *
  315. *****************************************************************************/
  316. STDMETHODIMP
  317. CDIObj_CreateDeviceHelper(PDDI this, PCGUID pguid, PPV ppvObj,
  318. PUNK punkOuter, RIID riid)
  319. {
  320. HRESULT hres;
  321. EnterProc(CDIObj_CreateDeviceHelper,
  322. (_ "pGxG", this, pguid, punkOuter, riid));
  323. /*
  324. * CDIDev_New will validate the punkOuter and ppvObj.
  325. *
  326. * IDirectInputDevice_Initialize will validate the pguid.
  327. *
  328. * riid is known good (since it came from CDIObj_CreateDeviceW
  329. * or CDIObj_CreateDeviceA).
  330. */
  331. hres = CDIDev_New(punkOuter, punkOuter ? &IID_IUnknown : riid, ppvObj);
  332. if (SUCCEEDED(hres) && punkOuter == 0) {
  333. PDID pdid = *ppvObj;
  334. hres = IDirectInputDevice_Initialize(pdid, g_hinst,
  335. this->dwVersion, pguid);
  336. if (SUCCEEDED(hres)) {
  337. } else {
  338. Invoke_Release(ppvObj);
  339. }
  340. }
  341. ExitOleProcPpv(ppvObj);
  342. return hres;
  343. }
  344. /*****************************************************************************
  345. *
  346. * @doc EXTERNAL
  347. *
  348. * @method HRESULT | IDirectInput | CreateDevice |
  349. *
  350. * Creates and initializes an instance of a device which is
  351. * specified by the GUID and IID.
  352. *
  353. * @cwrap LPDIRECTINPUT | lpDirectInput
  354. *
  355. * @parm REFGUID | rguid |
  356. * Identifies the instance of the
  357. * device for which the indicated interface
  358. * is requested. The <mf IDirectInput::EnumDevices> method
  359. * can be used to determine which instance GUIDs are supported by
  360. * the system.
  361. *
  362. * @parm OUT LPDIRECTINPUTDEVICE * | lplpDirectInputDevice |
  363. * Points to where to return
  364. * the pointer to the <i IDirectInputDevice> interface, if successful.
  365. *
  366. * @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown
  367. * for OLE aggregation, or 0 if the interface is not aggregated.
  368. * Most callers will pass 0.
  369. *
  370. * @comm Calling this function with <p punkOuter> = NULL
  371. * is equivalent to creating the object via
  372. * <f CoCreateInstance>(&CLSID_DirectInputDevice, NULL,
  373. * CLSCTX_INPROC_SERVER, <p riid>, <p lplpDirectInputDevice>);
  374. * then initializing it with <f Initialize>.
  375. *
  376. * Calling this function with <p punkOuter> != NULL
  377. * is equivalent to creating the object via
  378. * <f CoCreateInstance>(&CLSID_DirectInputDevice, <p punkOuter>,
  379. * CLSCTX_INPROC_SERVER, &IID_IUnknown, <p lplpDirectInputDevice>).
  380. * The aggregated object must be initialized manually.
  381. *
  382. * @returns
  383. *
  384. * Returns a COM error code. The following error codes are
  385. * intended to be illustrative and not necessarily comprehensive.
  386. *
  387. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  388. *
  389. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  390. * <p ppvOut> parameter is not a valid pointer.
  391. *
  392. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
  393. * Out of memory.
  394. *
  395. * <c DIERR_NOINTERFACE> = <c E_NOINTERFACE>
  396. * The specified interface is not supported by the object.
  397. *
  398. * <c DIERR_DEVICENOTREG> = The device instance does not
  399. * correspond to a device that is registered with DirectInput.
  400. *
  401. *****************************************************************************/
  402. STDMETHODIMP
  403. CDIObj_CreateDeviceW(PV pdiW, REFGUID rguid, PPDIDW ppdidW, PUNK punkOuter)
  404. {
  405. HRESULT hres;
  406. EnterProcR(IDirectInput::CreateDevice,
  407. (_ "pGp", pdiW, rguid, punkOuter));
  408. if (SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW))) {
  409. PDDI this = _thisPvNm(pdiW, diW);
  410. hres = CDIObj_CreateDeviceHelper(this, rguid, (PPV)ppdidW,
  411. punkOuter, &IID_IDirectInputDeviceW);
  412. }
  413. ExitOleProcPpv(ppdidW);
  414. return hres;
  415. }
  416. STDMETHODIMP
  417. CDIObj_CreateDeviceA(PV pdiA, REFGUID rguid, PPDIDA ppdidA, PUNK punkOuter)
  418. {
  419. HRESULT hres;
  420. EnterProcR(IDirectInput::CreateDevice,
  421. (_ "pGp", pdiA, rguid, punkOuter));
  422. if (SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA))) {
  423. PDDI this = _thisPvNm(pdiA, diA);
  424. hres = CDIObj_CreateDeviceHelper(this, rguid, (PPV)ppdidA,
  425. punkOuter, &IID_IDirectInputDeviceA);
  426. }
  427. ExitOleProcPpv(ppdidA);
  428. return hres;
  429. }
  430. /*****************************************************************************
  431. *
  432. * @doc EXTERNAL
  433. *
  434. * @method HRESULT | IDirectInput | CreateDeviceEx |
  435. *
  436. * Creates and initializes an instance of a device which is
  437. * specified by the GUID. CreateDeviceEx allows an app to
  438. * directly create a IID_IDirectInputDevice7 interface without
  439. * going through a CreateDevice() and QI the interface
  440. * for an IID_IDirectInput7.
  441. *
  442. * @cwrap LPDIRECTINPUT | lpDirectInput
  443. *
  444. * @parm REFGUID | rguid |
  445. * Identifies the instance of the
  446. * device for which the indicated interface
  447. * is requested. The <mf IDirectInput::EnumDevices> method
  448. * can be used to determine which instance GUIDs are supported by
  449. * the system.
  450. *
  451. * @parm REFIID | riid |
  452. * Identifies the REFIID for the interface. Currently accepted values
  453. * are IID_IDirectInputDevice, IID_IDirectInputDevice2, IID_IDirectInputDevice7.
  454. *
  455. *
  456. * @parm OUT LPVOID * | pvOut |
  457. * Points to where to return
  458. * the pointer to the <i IDirectInputDevice#> interface, if successful.
  459. *
  460. * @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown
  461. * for OLE aggregation, or 0 if the interface is not aggregated.
  462. * Most callers will pass 0.
  463. *
  464. * @comm Calling this function with <p punkOuter> = NULL
  465. * is equivalent to creating the object via
  466. * <f CoCreateInstance>(&CLSID_DirectInputDevice, NULL,
  467. * CLSCTX_INPROC_SERVER, <p riid>, <p lplpDirectInputDevice>);
  468. * then initializing it with <f Initialize>.
  469. *
  470. * Calling this function with <p punkOuter> != NULL
  471. * is equivalent to creating the object via
  472. * <f CoCreateInstance>(&CLSID_DirectInputDevice, <p punkOuter>,
  473. * CLSCTX_INPROC_SERVER, &IID_IUnknown, <p lplpDirectInputDevice>).
  474. * The aggregated object must be initialized manually.
  475. *
  476. * @returns
  477. *
  478. * Returns a COM error code. The following error codes are
  479. * intended to be illustrative and not necessarily comprehensive.
  480. *
  481. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  482. *
  483. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  484. * <p ppvOut> parameter is not a valid pointer.
  485. *
  486. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
  487. * Out of memory.
  488. *
  489. * <c DIERR_NOINTERFACE> = <c E_NOINTERFACE>
  490. * The specified interface is not supported by the object.
  491. *
  492. * <c DIERR_DEVICENOTREG> = The device instance does not
  493. * correspond to a device that is registered with DirectInput.
  494. *
  495. *****************************************************************************/
  496. STDMETHODIMP
  497. CDIObj_CreateDeviceExW(PV pdiW, REFGUID rguid, REFIID riid, LPVOID * pvOut, PUNK punkOuter)
  498. {
  499. HRESULT hres;
  500. EnterProcR(IDirectInput::CreateDeviceEx,
  501. (_ "pGGp", pdiW, rguid, riid, punkOuter));
  502. if(SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW)))
  503. {
  504. PDDI this = _thisPvNm(pdiW, diW);
  505. hres = CDIObj_CreateDeviceHelper(this, rguid, pvOut,
  506. punkOuter, riid);
  507. }
  508. ExitOleProcPpv(pvOut);
  509. return hres;
  510. }
  511. STDMETHODIMP
  512. CDIObj_CreateDeviceExA(PV pdiA, REFGUID rguid, REFIID riid, LPVOID * pvOut, PUNK punkOuter)
  513. {
  514. HRESULT hres;
  515. EnterProcR(IDirectInput::CreateDevice,
  516. (_ "pGp", pdiA, rguid, riid, punkOuter));
  517. if(SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA)))
  518. {
  519. PDDI this = _thisPvNm(pdiA, diA);
  520. hres = CDIObj_CreateDeviceHelper(this, rguid, pvOut,
  521. punkOuter, riid);
  522. }
  523. ExitOleProcPpv(pvOut);
  524. return hres;
  525. }
  526. /*****************************************************************************
  527. *
  528. * @doc INTERNAL
  529. *
  530. * @func HRESULT | CDIObj_TestDeviceFlags |
  531. *
  532. * Determines whether the device matches the specified flags.
  533. * Phantom devices are treated as not really there.
  534. *
  535. * @parm PDIDW | pdidW |
  536. *
  537. * Device to be queried.
  538. *
  539. * @parm DWORD | edfl |
  540. *
  541. * Enumeration flags. It is one or more <c DIEDFL_*> values.
  542. *
  543. * The bits in the enumeration flags are in two categories.*
  544. *
  545. * Normal flags are the ones whose presence requires that
  546. * the corresponding bit in the device flags also be set.
  547. *
  548. * Inverted flags (<c DIEDFL_INCLUDEMASK>) are the ones whose
  549. * absence requires that the corresponding bit in the device
  550. * flags also be absent.
  551. *
  552. * By inverting the inclusion flags in both the enumeration
  553. * flags and the actual device flags, and then treating the
  554. * whole thing as a bunch of normal flags, we get the desired
  555. * behavior for the inclusion flags.
  556. *
  557. * @returns
  558. *
  559. * <c S_OK> if the device meets the criteria.
  560. *
  561. * <c S_FALSE> if the device does not meet the criteria.
  562. * Note that <mf DirectInput::GetDeviceStatus> relies on
  563. * this specific return value.
  564. *
  565. * Other error code as appropriate.
  566. *
  567. *****************************************************************************/
  568. HRESULT EXTERNAL
  569. CDIObj_TestDeviceFlags(PDIDW pdidW, DWORD edfl)
  570. {
  571. HRESULT hres;
  572. DIDEVCAPS_DX3 dc;
  573. EnterProcI(CDIObj_TestDeviceFlags, (_ "px", pdidW, edfl));
  574. /*
  575. * We intentionally use a DIDEVCAPS_DX3 because going for
  576. * a full DIDEVCAPS_DX5 requires us to load the force
  577. * feedback driver which is pointless for our current
  578. * goal.
  579. */
  580. dc.dwSize = cbX(dc);
  581. hres = IDirectInputDevice_GetCapabilities(pdidW, (PV)&dc);
  582. AssertF(dc.dwSize == cbX(dc));
  583. CAssertF(DIEDFL_ATTACHEDONLY == DIDC_ATTACHED);
  584. CAssertF(DIEDFL_FORCEFEEDBACK == DIDC_FORCEFEEDBACK);
  585. CAssertF(DIEDFL_INCLUDEALIASES == DIDC_ALIAS);
  586. CAssertF(DIEDFL_INCLUDEPHANTOMS == DIDC_PHANTOM);
  587. if (SUCCEEDED(hres)) {
  588. if (fHasAllBitsFlFl(dc.dwFlags ^ DIEDFL_INCLUDEMASK,
  589. edfl ^ DIEDFL_INCLUDEMASK)) {
  590. hres = S_OK;
  591. } else {
  592. /*
  593. * Note: DX3 and DX5 returned E_DEVICENOTREG for
  594. * phantom devices. Now we return S_FALSE. Let's
  595. * hope nobody gets upset.
  596. */
  597. hres = S_FALSE;
  598. }
  599. }
  600. ExitOleProc();
  601. return hres;
  602. }
  603. /*****************************************************************************
  604. *
  605. * @doc EXTERNAL
  606. *
  607. * @method HRESULT | IDirectInput | EnumDevices |
  608. *
  609. * Enumerates the DirectInput devices that are attached to
  610. * or could be attached to the computer.
  611. *
  612. * For example, an external game port may support a joystick
  613. * or a steering wheel, but only one can be plugged in at a
  614. * time. <mf IDirectInput::EnumDevices> will enumerate both
  615. * devices.
  616. *
  617. * @cwrap LPDIRECTINPUT | lpDirectInput
  618. *
  619. * @parm DWORD | dwDevType |
  620. *
  621. * Device type filter. If 0, then all device types are
  622. * enumerated. Otherwise, it is a <c DIDEVTYPE_*> value,
  623. * indicating the device type that should be enumerated.
  624. *
  625. * @parm LPDIENUMDEVICESCALLBACK | lpCallback |
  626. * Points to an application-defined callback function.
  627. * For more information, see the description of the
  628. * <f DIEnumDevicesProc> callback function.
  629. *
  630. * @parm IN LPVOID | pvRef |
  631. * Specifies a 32-bit application-defined
  632. * value to be passed to the callback function. This value
  633. * may be any 32-bit value; it is prototyped as an <t LPVOID>
  634. * for convenience.
  635. *
  636. * @parm DWORD | fl |
  637. * Optional flags which control the enumeration. The
  638. * following flags are defined and may be combined.
  639. *
  640. * <c DIEDFL_ATTACHEDONLY>: Enumerate only attached devices.
  641. *
  642. * <c DIEDFL_FORCEFEEDBACK>: Enumerate only devices which
  643. * support force feedback. This flag is new for DirectX 5.0.
  644. *
  645. * <c DIEDFL_INCLUDEALIASES>: Include alias devices in the
  646. * enumeration. If this flag is not specified, then devices
  647. * which are aliases of other devices (indicated by the
  648. * <c DIDC_ALIAS> flag in the <e DIDEVCAPS.dwFlags> field
  649. * of the <t DIDEVCAPS> structure) will be excluded from
  650. * the enumeration. This flag is new for DirectX 5.0a.
  651. *
  652. * <c DIEDFL_INCLUDEPHANTOMS>: Include phantom devices in the
  653. * enumeration. If this flag is not specified, then devices
  654. * which are phantoms (indicated by the
  655. * <c DIDC_PHANTOM> flag in the <e DIDEVCAPS.dwFlags> field
  656. * of the <t DIDEVCAPS> structure) will be excluded from
  657. * the enumeration. This flag is new for DirectX 5.0a.
  658. *
  659. * The default is
  660. * <c DIEDFL_ALLDEVICES>: Enumerate all installed devices.
  661. *
  662. * @returns
  663. *
  664. * Returns a COM error code. The following error codes are
  665. * intended to be illustrative and not necessarily comprehensive.
  666. *
  667. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  668. * Note that if the callback stops the enumeration prematurely,
  669. * the enumeration is considered to have succeeded.
  670. *
  671. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  672. * <p fl> parameter contains invalid flags, or the callback
  673. * procedure returned an invalid status code.
  674. *
  675. * @cb BOOL CALLBACK | DIEnumDevicesProc |
  676. *
  677. * An application-defined callback function that receives
  678. * DirectInput devices as a result of a call to the
  679. * <om IDirectInput::EnumDevices> method.
  680. *
  681. * @parm IN LPDIDEVICEINSTANCE | lpddi |
  682. *
  683. * Structure that describes the device instance.
  684. *
  685. *
  686. * @parm IN OUT LPVOID | pvRef |
  687. * Specifies the application-defined value given in the
  688. * <mf IDirectInput::EnumDevices> function.
  689. *
  690. * @returns
  691. *
  692. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  693. * or <c DIENUM_STOP> to stop the enumeration.
  694. *
  695. *//**************************************************************************
  696. *
  697. * In DEBUG/RDEBUG, if the callback returns a bogus value, raise
  698. * a validation exception.
  699. *
  700. *****************************************************************************/
  701. HRESULT INLINE
  702. CDIObj_EnumDevices_IsValidTypeFilter(DWORD dwDevType)
  703. {
  704. HRESULT hres;
  705. /*
  706. * First make sure the type mask is okay.
  707. */
  708. if ((dwDevType & DIDEVTYPE_TYPEMASK) < DIDEVTYPE_MAX) {
  709. /*
  710. * Now make sure attribute masks are okay.
  711. */
  712. if (dwDevType & DIDEVTYPE_ENUMMASK & ~DIDEVTYPE_ENUMVALID) {
  713. RPF("IDirectInput::EnumDevices: Invalid dwDevType");
  714. hres = E_INVALIDARG;
  715. } else {
  716. hres = S_OK;
  717. }
  718. } else {
  719. RPF("IDirectInput::EnumDevices: Invalid dwDevType");
  720. hres = E_INVALIDARG;
  721. }
  722. return hres;
  723. }
  724. STDMETHODIMP
  725. CDIObj_EnumDevicesW(PV pdiW, DWORD dwDevType,
  726. LPDIENUMDEVICESCALLBACKW pec, LPVOID pvRef, DWORD fl)
  727. {
  728. HRESULT hres;
  729. EnterProcR(IDirectInput::EnumDevices,
  730. (_ "pxppx", pdiW, dwDevType, pec, pvRef, fl));
  731. if (SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW)) &&
  732. SUCCEEDED(hres = hresFullValidPfn(pec, 2)) &&
  733. SUCCEEDED(hres = CDIObj_EnumDevices_IsValidTypeFilter(dwDevType)) &&
  734. SUCCEEDED(hres = hresFullValidFl(fl, DIEDFL_VALID, 4))) {
  735. PDDI this = _thisPvNm(pdiW, diW);
  736. if(SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion))) {
  737. CDIDEnum *pde;
  738. hres = CDIDEnum_New(&this->diW, dwDevType, fl, this->dwVersion, &pde);
  739. if (SUCCEEDED(hres)) {
  740. DIDEVICEINSTANCEW ddiW;
  741. ddiW.dwSize = cbX(ddiW);
  742. while ((hres = CDIDEnum_Next(pde, &ddiW)) == S_OK) {
  743. BOOL fRc;
  744. /*
  745. * WARNING! "goto" here! Make sure that nothing
  746. * is held while we call the callback.
  747. */
  748. fRc = Callback(pec, &ddiW, pvRef);
  749. switch (fRc) {
  750. case DIENUM_STOP: goto enumdoneok;
  751. case DIENUM_CONTINUE: break;
  752. default:
  753. RPF("%s: Invalid return value from callback", s_szProc);
  754. ValidationException();
  755. break;
  756. }
  757. }
  758. AssertF(hres == S_FALSE);
  759. enumdoneok:;
  760. CDIDEnum_Release(pde);
  761. hres = S_OK;
  762. }
  763. }
  764. }
  765. ExitOleProcR();
  766. return hres;
  767. }
  768. /*****************************************************************************
  769. *
  770. * @doc INTERNAL
  771. *
  772. * @func BOOL | CDIObj_EnumDevicesCallbackA |
  773. *
  774. * Wrapper function for <mf IDirectInput::EnumDevices>
  775. * which translates the UNICODE parameters to ANSI.
  776. *
  777. * @parm IN LPCDIDECICEINSTANCEW | pdiW |
  778. *
  779. * Same as <mf IDirectInput::EnumDevices>.
  780. *
  781. * @parm IN OUT PV | pvRef |
  782. *
  783. * Pointer to <t struct ENUMDEVICESINFO> which describes
  784. * the original callback.
  785. *
  786. * @returns
  787. *
  788. * Returns whatever the original callback returned.
  789. *
  790. *****************************************************************************/
  791. typedef struct ENUMDEVICESINFO {
  792. LPDIENUMDEVICESCALLBACKA pecA;
  793. PV pvRef;
  794. } ENUMDEVICESINFO, *PENUMDEVICESINFO;
  795. BOOL CALLBACK
  796. CDIObj_EnumDevicesCallback(LPCDIDEVICEINSTANCEW pdiW, PV pvRef)
  797. {
  798. PENUMDEVICESINFO pedi = pvRef;
  799. BOOL fRc;
  800. DIDEVICEINSTANCEA diA;
  801. EnterProc(CDIObj_EnumDevicesCallback,
  802. (_ "GGxWWp", &pdiW->guidInstance, &pdiW->guidProduct,
  803. &pdiW->dwDevType,
  804. pdiW->tszProductName, pdiW->tszInstanceName,
  805. pvRef));
  806. diA.dwSize = cbX(diA);
  807. DeviceInfoWToA(&diA, pdiW);
  808. fRc = pedi->pecA(&diA, pedi->pvRef);
  809. ExitProcX(fRc);
  810. return fRc;
  811. }
  812. /*****************************************************************************
  813. *
  814. * @doc INTERNAL
  815. *
  816. * @method HRESULT | IDirectInputA | EnumDevices |
  817. *
  818. * ANSI version of <mf IDirectInput::EnumDevices>.
  819. * We wrap the operation.
  820. *
  821. * @parm IN LPGUID | lpGUIDDeviceType |
  822. * Same as <mf IDirectInput::EnumDevices>.
  823. *
  824. * @parm LPDIENUMDEVICESCALLBACKA | lpCallbackA |
  825. * Same as <mf IDirectInput::EnumDevices>, except ANSI.
  826. *
  827. * @parm IN LPVOID | pvRef |
  828. * Same as <mf IDirectInput::EnumDevices>.
  829. *
  830. * @parm DWORD | fl |
  831. * Same as <mf IDirectInput::EnumDevices>.
  832. *
  833. *****************************************************************************/
  834. STDMETHODIMP
  835. CDIObj_EnumDevicesA(PV pdiA, DWORD dwDevType,
  836. LPDIENUMDEVICESCALLBACKA pec, LPVOID pvRef, DWORD fl)
  837. {
  838. HRESULT hres;
  839. EnterProcR(IDirectInput::EnumDevices,
  840. (_ "pxppx", pdiA, dwDevType, pec, pvRef, fl));
  841. /*
  842. * EnumDevicesW will validate the rest.
  843. */
  844. if (SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA)) &&
  845. SUCCEEDED(hres = hresFullValidPfn(pec, 1))) {
  846. ENUMDEVICESINFO edi = { pec, pvRef };
  847. PDDI this = _thisPvNm(pdiA, diA);
  848. hres = CDIObj_EnumDevicesW(&this->diW, dwDevType,
  849. CDIObj_EnumDevicesCallback, &edi, fl);
  850. }
  851. ExitOleProcR();
  852. return hres;
  853. }
  854. /*****************************************************************************
  855. *
  856. * @doc EXTERNAL
  857. *
  858. * @method HRESULT | IDirectInput | GetDeviceStatus |
  859. *
  860. * Determine whether a device is currently attached.
  861. *
  862. * @cwrap LPDIRECTINPUT | lpDirectInput
  863. *
  864. * @parm REFGUID | rguid |
  865. *
  866. * Identifies the instance of the
  867. * device whose status is being checked.
  868. *
  869. * @returns
  870. *
  871. * Returns a COM error code. The following error codes are
  872. * intended to be illustrative and not necessarily comprehensive.
  873. *
  874. * <c DI_OK> = <c S_OK>: The device is attached.
  875. *
  876. * <c DI_NOTATTACHED> = <c S_FALSE>: The device is not
  877. * attached.
  878. *
  879. * <c E_FAIL>: DirectInput could not determine
  880. * whether the device is attached.
  881. *
  882. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  883. * device does not exist.
  884. *
  885. *****************************************************************************/
  886. STDMETHODIMP
  887. CDIObj_GetDeviceStatus(PV pdi, REFGUID rguid _THAT)
  888. {
  889. HRESULT hres;
  890. EnterProcR(IDirectInput::GetDeviceStatus, (_ "pG", pdi, rguid));
  891. if (SUCCEEDED(hres = hresPvT(pdi))) {
  892. PDDI this = _thisPv(pdi);
  893. PDIDW pdidW;
  894. hres = IDirectInput_CreateDevice(&this->diW, rguid, (PV)&pdidW, 0);
  895. if (SUCCEEDED(hres)) {
  896. hres = CDIObj_TestDeviceFlags(pdidW, DIEDFL_ATTACHEDONLY);
  897. OLE_Release(pdidW);
  898. }
  899. }
  900. ExitOleProc();
  901. return hres;
  902. }
  903. #ifdef XDEBUG
  904. CSET_STUBS(GetDeviceStatus, (PV pdi, REFGUID rguid), (pdi, rguid THAT_))
  905. #else
  906. #define CDIObj_GetDeviceStatusA CDIObj_GetDeviceStatus
  907. #define CDIObj_GetDeviceStatusW CDIObj_GetDeviceStatus
  908. #endif
  909. #ifdef DO_THE_IMPOSSIBLE
  910. /*****************************************************************************
  911. *
  912. * @doc EXTERNAL
  913. *
  914. * @method HRESULT | IDirectInput | SetAttachedDevice |
  915. *
  916. * Informs DirectInput that a new device has been attached
  917. * to the system by the user. This is useful when an application
  918. * asks the user to attach a currently installed device but does
  919. * not want to launch the DirectInput control panel.
  920. *
  921. * DirectInput needs to be informed that the device has
  922. * been attached for internal bookkeeping purposes.
  923. *
  924. * @cwrap LPDIRECTINPUT | lpDirectInput
  925. *
  926. * @parm IN LPDIRECTINPUTDEVICE | lpDIDevice |
  927. *
  928. * Identifies the device which has been attached.
  929. *
  930. * @returns
  931. *
  932. * Returns a COM error code. The following error codes are
  933. * intended to be illustrative and not necessarily comprehensive.
  934. *
  935. * <c DI_OK> = <c S_OK>: The device is attached.
  936. *
  937. * @devnote
  938. *
  939. * This method is not implemented in the current release
  940. * of DirectInput.
  941. *
  942. * This won't work. We need to receive a port, too.
  943. * And how can the app create a <p lpDIDevice> in the
  944. * first place for a device that does not exist?
  945. * I guess I just don't understand.
  946. *
  947. *****************************************************************************/
  948. STDMETHODIMP
  949. CDIObj_SetAttachedDevice(PV pdi, PV pdid _THAT)
  950. {
  951. HRESULT hres;
  952. EnterProcR(IDirectInput::SetAttachedDevice, (_ "pp", pdi, pdid));
  953. if (SUCCEEDED(hres = hresPvT(pdi))) {
  954. PDDI this = _thisPv(pdi);
  955. hres = E_NOTIMPL;
  956. }
  957. ExitOleProc();
  958. return hres;
  959. }
  960. #ifdef XDEBUG
  961. CSET_STUBS(SetAttachedDevice, (PV pdi, PV pdid), (pdi, pdid THAT_))
  962. #else
  963. #define CDIObj_SetAttachedDeviceA CDIObj_SetAttachedDevice
  964. #define CDIObj_SetAttachedDeviceW CDIObj_SetAttachedDevice
  965. #endif
  966. #endif
  967. /*****************************************************************************
  968. *
  969. * @doc EXTERNAL
  970. *
  971. * @method HRESULT | IDirectInput | RunControlPanel |
  972. *
  973. * Run the DirectInput control panel so that the user can
  974. * install a new input device or modify the setup.
  975. *
  976. * This function will not run third-party control panels.
  977. *
  978. * @cwrap LPDIRECTINPUT | lpDirectInput
  979. *
  980. * @parm IN HWND | hwndOwner |
  981. *
  982. * Identifies the window handle that will be used as the
  983. * parent window for subsequent UI. NULL is a valid parameter,
  984. * indicating that there is no parent window.
  985. *
  986. * @parm DWORD | dwFlags |
  987. *
  988. * No flags are currently defined. This parameter "must" be
  989. * zero.
  990. *
  991. * @returns
  992. * Returns a COM error code. The following error codes are
  993. * intended to be illustrative and not necessarily comprehensive.
  994. *
  995. * <c DI_OK> = <c S_OK>: The device is attached.
  996. *
  997. * @devnote
  998. *
  999. * The <p dwFlags> is eventually going to allow
  1000. * <c DIRCP_MODAL> to request a modal control panel.
  1001. *
  1002. *****************************************************************************/
  1003. #pragma BEGIN_CONST_DATA
  1004. STDMETHODIMP
  1005. CDIObj_RunControlPanel(PV pdi, HWND hwndOwner, DWORD fl _THAT)
  1006. {
  1007. HRESULT hres;
  1008. EnterProcR(IDirectInput::RunControlPanel, (_ "pxx", pdi, hwndOwner, fl));
  1009. if (SUCCEEDED(hres = hresPvT(pdi)) &&
  1010. SUCCEEDED(hres = hresFullValidHwnd0(hwndOwner, 1)) &&
  1011. SUCCEEDED(hres = hresFullValidFl(fl, DIRCP_VALID, 2)) ) {
  1012. PDDI this = _thisPv(pdi);
  1013. if(SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion))) {
  1014. /*
  1015. * We used to run "directx.cpl,@0,3" but directx.cpl is not
  1016. * redistributable; it comes only with the SDK. So we just
  1017. * run the system control panel.
  1018. */
  1019. hres = hresRunControlPanel(TEXT(""));
  1020. }
  1021. }
  1022. ExitOleProc();
  1023. return hres;
  1024. }
  1025. #ifdef XDEBUG
  1026. CSET_STUBS(RunControlPanel, (PV pdi, HWND hwndOwner, DWORD fl),
  1027. (pdi, hwndOwner, fl THAT_))
  1028. #else
  1029. #define CDIObj_RunControlPanelA CDIObj_RunControlPanel
  1030. #define CDIObj_RunControlPanelW CDIObj_RunControlPanel
  1031. #endif
  1032. /*****************************************************************************
  1033. *
  1034. * @doc EXTERNAL
  1035. *
  1036. * @method HRESULT | IDirectInput | Initialize |
  1037. *
  1038. * Initialize a DirectInput object.
  1039. *
  1040. * The <f DirectInputCreate> method automatically
  1041. * initializes the DirectInput object device after creating it.
  1042. * Applications normally do not need to call this function.
  1043. *
  1044. * @cwrap LPDIRECTINPUT | lpDirectInput
  1045. *
  1046. * @parm IN HINSTANCE | hinst |
  1047. *
  1048. * Instance handle of the application or DLL that is creating
  1049. * the DirectInput object.
  1050. *
  1051. * See the section titled "Initialization and Versions"
  1052. * for more information.
  1053. *
  1054. * @parm DWORD | dwVersion |
  1055. *
  1056. * Version number of the dinput.h header file that was used.
  1057. *
  1058. * See the section titled "Initialization and Versions"
  1059. * for more information.
  1060. *
  1061. * @returns
  1062. * Returns a COM error code. The following error codes are
  1063. * intended to be illustrative and not necessarily comprehensive.
  1064. *
  1065. * <c DI_OK> = <c S_OK>: The device is attached.
  1066. *
  1067. * <c DIERR_DIERR_OLDDIRECTINPUTVERSION>: The application
  1068. * requires a newer version of DirectInput.
  1069. *
  1070. * <c DIERR_DIERR_BETADIRECTINPUTVERSION>: The application
  1071. * was written for an unsupported prerelease version
  1072. * of DirectInput.
  1073. *
  1074. *****************************************************************************/
  1075. STDMETHODIMP
  1076. CDIObj_Initialize(PV pdi, HINSTANCE hinst, DWORD dwVersion _THAT)
  1077. {
  1078. HRESULT hres;
  1079. EnterProcR(IDirectInput::Initialize, (_ "pxx", pdi, hinst, dwVersion));
  1080. AhAppRegister(dwVersion);
  1081. if (SUCCEEDED(hres = hresPvT(pdi))) {
  1082. PDDI this = _thisPv(pdi);
  1083. if (SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion))) {
  1084. this->dwVersion = dwVersion;
  1085. }
  1086. }
  1087. #ifndef DX_FINAL_RELEASE
  1088. {
  1089. #pragma message("BETA EXPIRATION TIME BOMB! Remove for final build!")
  1090. SYSTEMTIME st;
  1091. GetSystemTime(&st);
  1092. if ( st.wYear > DX_EXPIRE_YEAR ||
  1093. ((st.wYear == DX_EXPIRE_YEAR) && (MAKELONG(st.wDay, st.wMonth) > MAKELONG(DX_EXPIRE_DAY, DX_EXPIRE_MONTH)))
  1094. ) {
  1095. MessageBox(0, DX_EXPIRE_TEXT,
  1096. TEXT("Microsoft DirectInput"), MB_OK);
  1097. }
  1098. }
  1099. #endif
  1100. ExitOleProc();
  1101. return hres;
  1102. }
  1103. #ifdef XDEBUG
  1104. CSET_STUBS(Initialize, (PV pdi, HINSTANCE hinst, DWORD dwVersion),
  1105. (pdi, hinst, dwVersion THAT_))
  1106. #else
  1107. #define CDIObj_InitializeA CDIObj_Initialize
  1108. #define CDIObj_InitializeW CDIObj_Initialize
  1109. #endif
  1110. #ifdef IDirectInput2Vtbl
  1111. /*****************************************************************************
  1112. *
  1113. * @doc INTERNAL
  1114. *
  1115. * @func HRESULT | CDIObj_FindDeviceInternal |
  1116. *
  1117. * The worker function for
  1118. * <mf IDirectInput2::FindDevice> which works only for HID devices.
  1119. *
  1120. * For more details, see <mf IDirectInput2::FindDevice>.
  1121. *
  1122. * @parm LPCTSTR | ptszName |
  1123. *
  1124. * The name of the device relative to the class <t GUID>.
  1125. *
  1126. * @parm OUT LPGUID | pguidOut |
  1127. *
  1128. * Pointer to a <t GUID> which receives the instance
  1129. * <t GUID> for the device, if the device is found.
  1130. *
  1131. *****************************************************************************/
  1132. HRESULT EXTERNAL
  1133. CDIObj_FindDeviceInternal(LPCTSTR ptszName, LPGUID pguidOut)
  1134. {
  1135. HRESULT hres;
  1136. /*
  1137. * Look twice. If it's not found the first time,
  1138. * then refresh the cache and try again in case
  1139. * it was for a device that was recently added.
  1140. * (In fact, it will likely be a device that was
  1141. * recently added, because FindDevice is usually
  1142. * called in response to a Plug and Play event.)
  1143. */
  1144. hres = hresFindHIDDeviceInterface(ptszName, pguidOut);
  1145. if (FAILED(hres)) {
  1146. DIHid_BuildHidList(TRUE);
  1147. hres = hresFindHIDDeviceInterface(ptszName, pguidOut);
  1148. }
  1149. return hres;
  1150. }
  1151. /*****************************************************************************
  1152. *
  1153. * @doc EXTERNAL
  1154. *
  1155. * @method HRESULT | IDirectInput2 | FindDevice |
  1156. *
  1157. * Obtain the instance <t GUID> for a device given
  1158. * its class <t GUID> and an opaque name.
  1159. *
  1160. * This method can be used by applications which register
  1161. * for Plug and Play notifications and are notified by
  1162. * Plug and Play that a new device has been added
  1163. * to the system. The Plug and Play notification will
  1164. * be in the form of a class <t GUID> and a device name.
  1165. * The application can pass the <t GUID> and name to
  1166. * this method to obtain the instance <t GUID> for
  1167. * the device, which can then be passed to
  1168. * <mf IDirectInput::CreateDevice> or
  1169. * <mf IDirectInput::GetDeviceStatus>.
  1170. *
  1171. * @cwrap LPDIRECTINPUT2 | lpDirectInput2
  1172. *
  1173. * @parm REFGUID | rguidClass |
  1174. *
  1175. * Class <t GUID> identifying the device class
  1176. * for the device the application wishes to locate.
  1177. *
  1178. * The application obtains the class <t GUID> from the
  1179. * Plug and Play device arrival notification.
  1180. *
  1181. * @parm LPCTSTR | ptszName |
  1182. *
  1183. * The name of the device relative to the class <t GUID>.
  1184. *
  1185. * The application obtains the class name from the
  1186. * Plug and Play device arrival notification.
  1187. *
  1188. * @parm OUT LPGUID | pguidInstance |
  1189. *
  1190. * Pointer to a <t GUID> which receives the instance
  1191. * <t GUID> for the device, if the device is found.
  1192. *
  1193. * @returns
  1194. * Returns a COM error code. The following error codes are
  1195. * intended to be illustrative and not necessarily comprehensive.
  1196. *
  1197. * <c DI_OK> = <c S_OK>: The device was found, and its
  1198. * instance <t GUID> has been stored in <p pguidInstance>.
  1199. *
  1200. * <c DIERR_DEVICENOTREG> = The <t GUID> and name do not
  1201. * correspond to a device that is registered with DirectInput.
  1202. * For example, they may refer to a storage device rather
  1203. * than an input device.
  1204. *
  1205. *****************************************************************************/
  1206. #define cchNameMax MAX_PATH
  1207. STDMETHODIMP
  1208. TFORM(CDIObj_FindDevice)(PV pdiT, REFGUID rguid,
  1209. LPCTSTR ptszName, LPGUID pguidOut)
  1210. {
  1211. HRESULT hres;
  1212. EnterProcR(IDirectInput2::FindDevice,
  1213. (_ "pGs", pdiT, rguid, ptszName));
  1214. if (SUCCEEDED(hres = TFORM(hresPv)(pdiT)) &&
  1215. SUCCEEDED(hres = hresFullValidGuid(rguid, 1)) &&
  1216. SUCCEEDED(hres = TFORM(hresFullValidReadStr)(ptszName,
  1217. cchNameMax, 2)) &&
  1218. SUCCEEDED(hres = hresFullValidWritePvCb(pguidOut, cbX(GUID), 3))) {
  1219. if (IsEqualIID(rguid, &GUID_HIDClass)) {
  1220. hres = CDIObj_FindDeviceInternal(ptszName, pguidOut);
  1221. } else {
  1222. hres = DIERR_DEVICENOTREG;
  1223. }
  1224. }
  1225. ExitOleProc();
  1226. return hres;
  1227. }
  1228. STDMETHODIMP
  1229. SFORM(CDIObj_FindDevice)(PV pdiS, REFGUID rguid,
  1230. LPCSSTR psszName, LPGUID pguidOut)
  1231. {
  1232. HRESULT hres;
  1233. TCHAR tsz[cchNameMax];
  1234. EnterProcR(IDirectInput2::FindDevice,
  1235. (_ "pGS", pdiS, rguid, psszName));
  1236. /*
  1237. * TFORM(CDIObj_FindDevice) will validate the rguid and pguidOut.
  1238. */
  1239. if (SUCCEEDED(hres = SFORM(hresPv)(pdiS)) &&
  1240. SUCCEEDED(hres = SFORM(hresFullValidReadStr)(psszName, cA(tsz), 2))) {
  1241. PDDI this = _thisPvNm(pdiS, SFORM(di));
  1242. SToT(tsz, cA(tsz), psszName);
  1243. hres = TFORM(CDIObj_FindDevice)(&this->TFORM(di), rguid, tsz, pguidOut);
  1244. }
  1245. ExitOleProc();
  1246. return hres;
  1247. }
  1248. #endif
  1249. /*****************************************************************************
  1250. *
  1251. * @doc INTERNAL
  1252. *
  1253. * @mfunc HRESULT | IDirectInput | New |
  1254. *
  1255. * Create a new instance of an IDirectInput object.
  1256. *
  1257. * @parm IN PUNK | punkOuter |
  1258. *
  1259. * Controlling unknown for aggregation.
  1260. *
  1261. * @parm IN RIID | riid |
  1262. * Desired interface to new object.
  1263. *
  1264. * @parm OUT PPV | ppvObj |
  1265. * Output pointer for new object.
  1266. *
  1267. * @returns
  1268. *
  1269. * Standard OLE <t HRESULT>.
  1270. *
  1271. *****************************************************************************/
  1272. STDMETHODIMP
  1273. CDIObj_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  1274. {
  1275. HRESULT hres;
  1276. EnterProcR(IDirectInput::CreateInstance, (_ "Gp", riid, ppvObj));
  1277. hres = Excl_Init();
  1278. if (SUCCEEDED(hres)) {
  1279. /*
  1280. * Note that we cannot use Common_NewRiid for an object
  1281. * that aggregates other interfaces!
  1282. *
  1283. * The reason is that Common_NewRiid will perform
  1284. * a QI as part of the initialization, but we cannot handle
  1285. * the QI until after we've been initialized and are
  1286. * ready to mess with aggregated goo.
  1287. */
  1288. if (SUCCEEDED(hres = hresFullValidRiid(riid, 2))) {
  1289. if (fLimpFF(punkOuter, IsEqualIID(riid, &IID_IUnknown))) {
  1290. hres = Common_New(CDIObj, punkOuter, ppvObj);
  1291. if (SUCCEEDED(hres)) {
  1292. PDDI this = _thisPv(*ppvObj);
  1293. this->fCritInited = fInitializeCriticalSection(&this->crst);
  1294. if( this->fCritInited )
  1295. {
  1296. /*
  1297. * Only after the object is ready do we QI for the
  1298. * requested interface. And the reason is that the
  1299. * QI might cause us to create an aggregated buddy,
  1300. * which we can't do until we've been initialized.
  1301. *
  1302. * Don't do this extra QI if we are ourselves aggregated,
  1303. * or we will end up giving the wrong punk to the caller!
  1304. */
  1305. if (punkOuter == 0) {
  1306. hres = OLE_QueryInterface(this, riid, ppvObj);
  1307. OLE_Release(this);
  1308. }
  1309. if (FAILED(hres)) {
  1310. Invoke_Release(ppvObj);
  1311. }
  1312. }
  1313. else
  1314. {
  1315. Common_Unhold(this);
  1316. *ppvObj = NULL;
  1317. hres = E_OUTOFMEMORY;
  1318. }
  1319. }
  1320. } else {
  1321. RPF("CreateDevice: IID must be IID_IUnknown if created for aggregation");
  1322. *ppvObj = 0;
  1323. hres = CLASS_E_NOAGGREGATION;
  1324. }
  1325. }
  1326. }
  1327. ExitOleProcPpvR(ppvObj);
  1328. return hres;
  1329. }
  1330. /*****************************************************************************
  1331. *
  1332. * The long-awaited vtbls and templates
  1333. *
  1334. *****************************************************************************/
  1335. #pragma BEGIN_CONST_DATA
  1336. #define CDIObj_Signature 0x504E4944 /* "DINP" */
  1337. Interface_Template_Begin(CDIObj)
  1338. Primary_Interface_Template(CDIObj, TFORM(ThisInterfaceT))
  1339. Secondary_Interface_Template(CDIObj, SFORM(ThisInterfaceT))
  1340. Interface_Template_End(CDIObj)
  1341. Primary_Interface_Begin(CDIObj, TFORM(ThisInterfaceT))
  1342. TFORM(CDIObj_CreateDevice),
  1343. TFORM(CDIObj_EnumDevices),
  1344. TFORM(CDIObj_GetDeviceStatus),
  1345. TFORM(CDIObj_RunControlPanel),
  1346. TFORM(CDIObj_Initialize),
  1347. #ifdef IDirectInput2Vtbl
  1348. TFORM(CDIObj_FindDevice),
  1349. #ifdef IDirectInput7Vtbl
  1350. TFORM(CDIObj_CreateDeviceEx),
  1351. #endif
  1352. #endif
  1353. Primary_Interface_End(CDIObj, TFORM(ThisInterfaceT))
  1354. Secondary_Interface_Begin(CDIObj, SFORM(ThisInterfaceT), SFORM(di))
  1355. SFORM(CDIObj_CreateDevice),
  1356. SFORM(CDIObj_EnumDevices),
  1357. SFORM(CDIObj_GetDeviceStatus),
  1358. SFORM(CDIObj_RunControlPanel),
  1359. SFORM(CDIObj_Initialize),
  1360. #ifdef IDirectInput2Vtbl
  1361. SFORM(CDIObj_FindDevice),
  1362. #ifdef IDirectInput7Vtbl
  1363. SFORM(CDIObj_CreateDeviceEx),
  1364. #endif
  1365. #endif
  1366. Secondary_Interface_End(CDIObj, SFORM(ThisInterfaceT), SFORM(di))