Leaked source code of windows server 2003
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.

3490 lines
111 KiB

  1. /*****************************************************************************
  2. *
  3. * DIObj.c
  4. *
  5. * Copyright (c) 1996 - 2000 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. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflDi
  23. #define DIDEVTYPE_DEVICE_ORDER 1
  24. #define DIDEVTYPE_HID_MOUSE_ORDER 2
  25. #define DIDEVTYPE_HID_KEYBOARD_ORDER 3
  26. #define DIDEVTYPE_MOUSE_ORDER 4
  27. #define DIDEVTYPE_KEYBOARD_ORDER 5
  28. #define DIDEVTYPE_SUPPLEMENTAL_ORDER 6
  29. #define MAX_ORDER (DI8DEVTYPE_MAX - DI8DEVTYPE_MIN + DIDEVTYPE_SUPPLEMENTAL_ORDER + 2)
  30. #define INVALID_ORDER (MAX_ORDER + 1)
  31. #define MAX_DEVICENUM 32
  32. DIORDERDEV g_DiDevices[MAX_DEVICENUM]; //all devices that are attached
  33. int g_nCurDev;
  34. /*****************************************************************************
  35. *
  36. * @doc INTERNAL
  37. *
  38. * @struct CDIObj |
  39. *
  40. * The <i IDirectInput> object, from which other things come.
  41. *
  42. * The A and W versions are simply alternate interfaces on the same
  43. * underlying object.
  44. *
  45. * There really isn't anything interesting in the structure
  46. * itself.
  47. *
  48. *
  49. * @field IDirectInputA | diA |
  50. *
  51. * ANSI DirectInput object (containing vtbl).
  52. *
  53. * @field IDirectInputW | diW |
  54. *
  55. * UNICODE DirectInput object (containing vtbl).
  56. *
  57. * @field IDirectInputJoyConfig *| pdjc |
  58. *
  59. * Aggregated joystick configuration interface (if created).
  60. *
  61. * @field BOOL | fCritInited:1 |
  62. *
  63. * Set if the critical section has been initialized.
  64. *
  65. * @field CRITICAL_SECTION | crst |
  66. *
  67. * Critical section that guards thread-sensitive data.
  68. *****************************************************************************/
  69. typedef struct CDIObj
  70. {
  71. /* Supported interfaces */
  72. TFORM(IDirectInput8) TFORM(di);
  73. SFORM(IDirectInput8) SFORM(di);
  74. DWORD dwVersion;
  75. IDirectInputJoyConfig *pdjc;
  76. BOOL fCritInited:1;
  77. CRITICAL_SECTION crst;
  78. } CDIObj, DDI, *PDDI;
  79. #define ThisClass CDIObj
  80. #define ThisInterface TFORM(IDirectInput8)
  81. #define ThisInterfaceA IDirectInput8A
  82. #define ThisInterfaceW IDirectInput8W
  83. #define ThisInterfaceT IDirectInput8
  84. /*****************************************************************************
  85. *
  86. * Declare the interfaces we will be providing.
  87. *
  88. *****************************************************************************/
  89. Primary_Interface(CDIObj, TFORM(ThisInterfaceT));
  90. Secondary_Interface(CDIObj, SFORM(ThisInterfaceT));
  91. /*****************************************************************************
  92. *
  93. * @doc EXTERNAL
  94. *
  95. * @method HRESULT | IDirectInput | QueryInterface |
  96. *
  97. * Gives a client access to other interfaces on an object.
  98. *
  99. * @cwrap LPDIRECTINPUT | lpDirectInput
  100. *
  101. * @parm IN REFIID | riid |
  102. *
  103. * The requested interface's IID.
  104. *
  105. * @parm OUT LPVOID * | ppvObj |
  106. *
  107. * Receives a pointer to the obtained interface.
  108. *
  109. * @returns
  110. *
  111. * Returns a COM error code.
  112. *
  113. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  114. *
  115. *//**************************************************************************
  116. *
  117. * @doc EXTERNAL
  118. *
  119. * @method HRESULT | IDirectInput | AddRef |
  120. *
  121. * Increments the reference count for the interface.
  122. *
  123. * @cwrap LPDIRECTINPUT | lpDirectInput
  124. *
  125. * @returns
  126. *
  127. * Returns the object reference count.
  128. *
  129. * @xref OLE documentation for <mf IUnknown::AddRef>.
  130. *
  131. *****************************************************************************
  132. *
  133. * @doc EXTERNAL
  134. *
  135. * @method HRESULT | IDirectInput | Release |
  136. *
  137. * Decrements the reference count for the interface.
  138. * If the reference count on the object falls to zero,
  139. * the object is freed from memory.
  140. *
  141. * @cwrap LPDIRECTINPUT | lpDirectInput
  142. *
  143. * @returns
  144. *
  145. * Returns the object reference count.
  146. *
  147. * @xref OLE documentation for <mf IUnknown::Release>.
  148. *
  149. *****************************************************************************/
  150. #ifdef DEBUG
  151. Default_QueryInterface(CDIObj)
  152. Default_AddRef(CDIObj)
  153. Default_Release(CDIObj)
  154. #else
  155. #define CDIObj_QueryInterface Common_QueryInterface
  156. #define CDIObj_AddRef Common_AddRef
  157. #define CDIObj_Release Common_Release
  158. #endif
  159. #define CDIObj_AppFinalize Common_AppFinalize
  160. /*****************************************************************************
  161. *
  162. * @doc INTERNAL
  163. *
  164. * @mfunc void | CDIObj | EnterCrit |
  165. *
  166. * Enter the object critical section.
  167. *
  168. * @doc INTERNAL
  169. *
  170. * @mfunc void | CDIObj | LeaveCrit |
  171. *
  172. * Leave the object critical section.
  173. *
  174. *****************************************************************************/
  175. void INLINE
  176. CDIObj_EnterCrit(PDDI this)
  177. {
  178. EnterCriticalSection(&this->crst);
  179. }
  180. void INLINE
  181. CDIObj_LeaveCrit(PDDI this)
  182. {
  183. LeaveCriticalSection(&this->crst);
  184. }
  185. /*****************************************************************************
  186. *
  187. * @doc INTERNAL
  188. *
  189. * @mfunc HRESULT | IDirectInput | QIHelper |
  190. *
  191. * We will dynamically create <i IDirectInputJoyConfig>
  192. * and aggregate it with us.
  193. *
  194. * @parm IN REFIID | riid |
  195. *
  196. * The requested interface's IID.
  197. *
  198. * @parm OUT LPVOID * | ppvObj |
  199. *
  200. * Receives a pointer to the obtained interfacethis->pdix[iobj].dwOfs.
  201. *
  202. *****************************************************************************/
  203. STDMETHODIMP
  204. CDIObj_QIHelper(PDDI this, RIID riid, PPV ppvObj)
  205. {
  206. HRESULT hres;
  207. EnterProcI(CDIObj_QIHelper, (_ "pG", this, riid));
  208. if ( IsEqualIID(riid, &IID_IDirectInputJoyConfig8) )
  209. {
  210. *ppvObj = 0; /* In case the New fails */
  211. CDIObj_EnterCrit(this);
  212. if ( this->pdjc == 0 )
  213. {
  214. hres = CJoyCfg_New((PUNK)this, &IID_IUnknown, (PPV)&this->pdjc);
  215. } else
  216. {
  217. hres = S_OK;
  218. }
  219. CDIObj_LeaveCrit(this);
  220. if ( SUCCEEDED(hres) )
  221. {
  222. /*
  223. * This QI will addref us if it succeeds.
  224. */
  225. hres = OLE_QueryInterface(this->pdjc, riid, ppvObj);
  226. } else
  227. {
  228. this->pdjc = 0;
  229. }
  230. } else
  231. {
  232. hres = Common_QIHelper(this, riid, ppvObj);
  233. }
  234. ExitOleProcPpv(ppvObj);
  235. return(hres);
  236. }
  237. /*****************************************************************************
  238. *
  239. * @doc INTERNAL
  240. *
  241. * @func void | CDIObj_Finalize |
  242. *
  243. * Clean up our instance data.
  244. *
  245. * @parm PV | pvObj |
  246. *
  247. * Object being released. Note that it may not have been
  248. * completely initialized, so everything should be done
  249. * carefully.
  250. *
  251. *****************************************************************************/
  252. void INTERNAL
  253. CDIObj_Finalize(PV pvObj)
  254. {
  255. PDDI this = pvObj;
  256. Invoke_Release(&this->pdjc);
  257. if ( this->fCritInited )
  258. {
  259. DeleteCriticalSection(&this->crst);
  260. }
  261. }
  262. /*****************************************************************************
  263. *
  264. * @doc INTERNAL
  265. *
  266. * @method HRESULT | IDirectInput | CreateDeviceHelper |
  267. *
  268. * Creates and initializes an instance of a device which is
  269. * specified by the GUID and IID.
  270. *
  271. * @cwrap LPDIRECTINPUT | lpDirectInput
  272. *
  273. * @parm IN PCGUID | pguid |
  274. *
  275. * See <mf IDirectInput::CreateDevice>.
  276. *
  277. * @parm OUT PPV | ppvObj |
  278. *
  279. * See <mf IDirectInput::CreateDevice>.
  280. *
  281. * @parm IN LPUNKNOWN | punkOuter |
  282. *
  283. * See <mf IDirectInput::CreateDevice>.
  284. *
  285. * @parm IN RIID | riid |
  286. *
  287. * The interface the application wants to create. This will
  288. * be either <i IDirectInputDeviceA> or <i IDirectInputDeviceW>.
  289. * If the object is aggregated, then this parameter is ignored.
  290. *
  291. * @returns
  292. *
  293. * Returns a COM error code.
  294. *
  295. *****************************************************************************/
  296. STDMETHODIMP
  297. CDIObj_CreateDeviceHelper(PDDI this, PCGUID pguid, PPV ppvObj,
  298. PUNK punkOuter, RIID riid)
  299. {
  300. HRESULT hres;
  301. EnterProc(CDIObj_CreateDeviceHelper,
  302. (_ "pGxG", this, pguid, punkOuter, riid));
  303. /*
  304. * CDIDev_New will validate the punkOuter and ppvObj.
  305. *
  306. * IDirectInputDevice_Initialize will validate the pguid.
  307. *
  308. * riid is known good (since it came from CDIObj_CreateDeviceW
  309. * or CDIObj_CreateDeviceA).
  310. */
  311. hres = CDIDev_New(punkOuter, punkOuter ? &IID_IUnknown : riid, ppvObj);
  312. if ( SUCCEEDED(hres) && punkOuter == 0 )
  313. {
  314. PDID pdid = *ppvObj;
  315. hres = IDirectInputDevice_Initialize(pdid, g_hinst,
  316. this->dwVersion, pguid);
  317. if ( SUCCEEDED(hres) )
  318. {
  319. } else
  320. {
  321. Invoke_Release(ppvObj);
  322. }
  323. }
  324. ExitOleProcPpv(ppvObj);
  325. return(hres);
  326. }
  327. /*****************************************************************************
  328. *
  329. * @doc EXTERNAL
  330. *
  331. * @method HRESULT | IDirectInput | CreateDevice |
  332. *
  333. * Creates and initializes an instance of a device which is
  334. * specified by the GUID and IID.
  335. *
  336. * @cwrap LPDIRECTINPUT | lpDirectInput
  337. *
  338. * @parm REFGUID | rguid |
  339. * Identifies the instance of the
  340. * device for which the indicated interface
  341. * is requested. The <mf IDirectInput::EnumDevices> method
  342. * can be used to determine which instance GUIDs are supported by
  343. * the system.
  344. *
  345. * @parm OUT LPDIRECTINPUTDEVICE * | lplpDirectInputDevice |
  346. * Points to where to return
  347. * the pointer to the <i IDirectInputDevice> interface, if successful.
  348. *
  349. * @parm IN LPUNKNOWN | punkOuter | Pointer to controlling unknown
  350. * for OLE aggregation, or 0 if the interface is not aggregated.
  351. * Most callers will pass 0.
  352. *
  353. * @comm Calling this function with <p punkOuter> = NULL
  354. * is equivalent to creating the object via
  355. * <f CoCreateInstance>(&CLSID_DirectInputDevice, NULL,
  356. * CLSCTX_INPROC_SERVER, <p riid>, <p lplpDirectInputDevice>);
  357. * then initializing it with <f Initialize>.
  358. *
  359. * Calling this function with <p punkOuter> != NULL
  360. * is equivalent to creating the object via
  361. * <f CoCreateInstance>(&CLSID_DirectInputDevice, <p punkOuter>,
  362. * CLSCTX_INPROC_SERVER, &IID_IUnknown, <p lplpDirectInputDevice>).
  363. * The aggregated object must be initialized manually.
  364. *
  365. * @returns
  366. *
  367. * Returns a COM error code. The following error codes are
  368. * intended to be illustrative and not necessarily comprehensive.
  369. *
  370. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  371. *
  372. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  373. * <p ppvOut> parameter is not a valid pointer.
  374. *
  375. * <c DIERR_OUTOFMEMORY> = <c E_OUTOFMEMORY>:
  376. * Out of memory.
  377. *
  378. * <c DIERR_NOINTERFACE> = <c E_NOINTERFACE>
  379. * The specified interface is not supported by the object.
  380. *
  381. * <c DIERR_DEVICENOTREG> = The device instance does not
  382. * correspond to a device that is registered with DirectInput.
  383. *
  384. *****************************************************************************/
  385. STDMETHODIMP
  386. CDIObj_CreateDeviceW(PV pdiW, REFGUID rguid, PPDIDW ppdidW, PUNK punkOuter)
  387. {
  388. HRESULT hres;
  389. EnterProcR(IDirectInput8::CreateDevice,
  390. (_ "pGp", pdiW, rguid, punkOuter));
  391. if ( SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW)) )
  392. {
  393. PDDI this = _thisPvNm(pdiW, diW);
  394. hres = CDIObj_CreateDeviceHelper(this, rguid, (PPV)ppdidW,
  395. punkOuter, &IID_IDirectInputDevice8W);
  396. }
  397. ExitOleProcPpv(ppdidW);
  398. return(hres);
  399. }
  400. STDMETHODIMP
  401. CDIObj_CreateDeviceA(PV pdiA, REFGUID rguid, PPDIDA ppdidA, PUNK punkOuter)
  402. {
  403. HRESULT hres;
  404. EnterProcR(IDirectInput8::CreateDevice,
  405. (_ "pGp", pdiA, rguid, punkOuter));
  406. if ( SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA)) )
  407. {
  408. PDDI this = _thisPvNm(pdiA, diA);
  409. hres = CDIObj_CreateDeviceHelper(this, rguid, (PPV)ppdidA,
  410. punkOuter, &IID_IDirectInputDevice8A);
  411. }
  412. ExitOleProcPpv(ppdidA);
  413. return(hres);
  414. }
  415. /*****************************************************************************
  416. *
  417. * @doc INTERNAL
  418. *
  419. * @func HRESULT | CDIObj_TestDeviceFlags |
  420. *
  421. * Determines whether the device matches the specified flags.
  422. * Phantom devices are treated as not really there.
  423. *
  424. * @parm PDIDW | pdidW |
  425. *
  426. * Device to be queried.
  427. *
  428. * @parm DWORD | edfl |
  429. *
  430. * Enumeration flags. It is one or more <c DIEDFL_*> values.
  431. *
  432. * The bits in the enumeration flags are in two categories.*
  433. *
  434. * Normal flags are the ones whose presence requires that
  435. * the corresponding bit in the device flags also be set.
  436. *
  437. * Inverted flags (<c DIEDFL_INCLUDEMASK>) are the ones whose
  438. * absence requires that the corresponding bit in the device
  439. * flags also be absent.
  440. *
  441. * By inverting the inclusion flags in both the enumeration
  442. * flags and the actual device flags, and then treating the
  443. * whole thing as a bunch of normal flags, we get the desired
  444. * behavior for the inclusion flags.
  445. *
  446. * @returns
  447. *
  448. * <c S_OK> if the device meets the criteria.
  449. *
  450. * <c S_FALSE> if the device does not meet the criteria.
  451. * Note that <mf DirectInput::GetDeviceStatus> relies on
  452. * this specific return value.
  453. *
  454. * Other error code as appropriate.
  455. *
  456. *****************************************************************************/
  457. HRESULT EXTERNAL
  458. CDIObj_TestDeviceFlags(PDIDW pdidW, DWORD edfl)
  459. {
  460. HRESULT hres;
  461. DIDEVCAPS_DX3 dc;
  462. EnterProcI(CDIObj_TestDeviceFlags, (_ "px", pdidW, edfl));
  463. /*
  464. * We intentionally use a DIDEVCAPS_DX3 because going for
  465. * a full DIDEVCAPS_DX5 requires us to load the force
  466. * feedback driver which is pointless for our current
  467. * goal.
  468. */
  469. dc.dwSize = cbX(dc);
  470. hres = IDirectInputDevice_GetCapabilities(pdidW, (PV)&dc);
  471. AssertF(dc.dwSize == cbX(dc));
  472. CAssertF(DIEDFL_ATTACHEDONLY == DIDC_ATTACHED);
  473. CAssertF(DIEDFL_FORCEFEEDBACK == DIDC_FORCEFEEDBACK);
  474. CAssertF(DIEDFL_INCLUDEALIASES == DIDC_ALIAS);
  475. CAssertF(DIEDFL_INCLUDEPHANTOMS == DIDC_PHANTOM);
  476. CAssertF(DIEDFL_INCLUDEHIDDEN == DIDC_HIDDEN);
  477. if ( SUCCEEDED(hres) )
  478. {
  479. if ( fHasAllBitsFlFl(dc.dwFlags ^ DIEDFL_INCLUDEMASK,
  480. edfl ^ DIEDFL_INCLUDEMASK) )
  481. {
  482. hres = S_OK;
  483. } else
  484. {
  485. /*
  486. * Note: DX3 and DX5 returned E_DEVICENOTREG for
  487. * phantom devices. Now we return S_FALSE. Let's
  488. * hope nobody gets upset.
  489. */
  490. hres = S_FALSE;
  491. }
  492. }
  493. ExitOleProc();
  494. return(hres);
  495. }
  496. /*****************************************************************************
  497. *
  498. * @doc EXTERNAL
  499. *
  500. * @method HRESULT | IDirectInput | EnumDevices |
  501. *
  502. * Enumerates the DirectInput devices that are attached to
  503. * or could be attached to the computer.
  504. *
  505. * For example, an external game port may support a joystick
  506. * or a steering wheel, but only one can be plugged in at a
  507. * time. <mf IDirectInput::EnumDevices> will enumerate both
  508. * devices.
  509. *
  510. * @cwrap LPDIRECTINPUT | lpDirectInput
  511. *
  512. * @parm DWORD | dwDevType |
  513. *
  514. * Device type filter. If 0, then all device types are
  515. * enumerated. Otherwise, it is either a <c DIDEVCLASS_*> value,
  516. * indicating the device class that should be enumerated or a
  517. * <c DIDEVTYPE_*> value, indicating the device type that should be
  518. * enumerated.
  519. *
  520. * @parm LPDIENUMDEVICESCALLBACK | lpCallback |
  521. * Points to an application-defined callback function.
  522. * For more information, see the description of the
  523. * <f DIEnumDevicesProc> callback function.
  524. *
  525. * @parm IN LPVOID | pvRef |
  526. * Specifies a 32-bit application-defined
  527. * value to be passed to the callback function. This value
  528. * may be any 32-bit value; it is prototyped as an <t LPVOID>
  529. * for convenience.
  530. *
  531. * @parm DWORD | fl |
  532. * Optional flags which control the enumeration. The
  533. * following flags are defined and may be combined.
  534. *
  535. * <c DIEDFL_ATTACHEDONLY>: Enumerate only attached devices.
  536. *
  537. * <c DIEDFL_FORCEFEEDBACK>: Enumerate only devices which
  538. * support force feedback. This flag is new for DirectX 5.0.
  539. *
  540. * <c DIEDFL_INCLUDEALIASES>: Include alias devices in the
  541. * enumeration. If this flag is not specified, then devices
  542. * which are aliases of other devices (indicated by the
  543. * <c DIDC_ALIAS> flag in the <e DIDEVCAPS.dwFlags> field
  544. * of the <t DIDEVCAPS> structure) will be excluded from
  545. * the enumeration. This flag is new for DirectX 5.0a.
  546. *
  547. * <c DIEDFL_INCLUDEPHANTOMS>: Include phantom devices in the
  548. * enumeration. If this flag is not specified, then devices
  549. * which are phantoms (indicated by the
  550. * <c DIDC_PHANTOM> flag in the <e DIDEVCAPS.dwFlags> field
  551. * of the <t DIDEVCAPS> structure) will be excluded from
  552. * the enumeration. This flag is new for DirectX 5.0a.
  553. *
  554. * The default is
  555. * <c DIEDFL_ALLDEVICES>: Enumerate all installed devices.
  556. *
  557. * @returns
  558. *
  559. * Returns a COM error code. The following error codes are
  560. * intended to be illustrative and not necessarily comprehensive.
  561. *
  562. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  563. * Note that if the callback stops the enumeration prematurely,
  564. * the enumeration is considered to have succeeded.
  565. *
  566. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  567. * <p fl> parameter contains invalid flags, or the callback
  568. * procedure returned an invalid status code.
  569. *
  570. * @cb BOOL CALLBACK | DIEnumDevicesProc |
  571. *
  572. * An application-defined callback function that receives
  573. * DirectInput devices as a result of a call to the
  574. * <om IDirectInput::EnumDevices> method.
  575. *
  576. * @parm IN LPDIDEVICEINSTANCE | lpddi |
  577. *
  578. * Structure that describes the device instance.
  579. *
  580. *
  581. * @parm IN OUT LPVOID | pvRef |
  582. * Specifies the application-defined value given in the
  583. * <mf IDirectInput::EnumDevices> function.
  584. *
  585. * @returns
  586. *
  587. * Returns <c DIENUM_CONTINUE> to continue the enumeration
  588. * or <c DIENUM_STOP> to stop the enumeration.
  589. *
  590. *//**************************************************************************
  591. *
  592. * In DEBUG/RDEBUG, if the callback returns a bogus value, raise
  593. * a validation exception.
  594. *
  595. *****************************************************************************/
  596. HRESULT INLINE
  597. CDIObj_EnumDevices_IsValidTypeFilter(DWORD dwDevType)
  598. {
  599. HRESULT hres;
  600. /*
  601. * First make sure the type mask is okay.
  602. */
  603. if( ( GET_DIDEVICE_TYPE( dwDevType ) < DI8DEVCLASS_MAX )
  604. || ( ( GET_DIDEVICE_TYPE( dwDevType ) >= DI8DEVTYPE_MIN )
  605. && ( GET_DIDEVICE_TYPE( dwDevType ) < DI8DEVTYPE_MAX ) ) )
  606. {
  607. /*
  608. * Now make sure attribute masks are okay.
  609. */
  610. if ( dwDevType & DIDEVTYPE_ENUMMASK & ~DIDEVTYPE_ENUMVALID )
  611. {
  612. RPF("IDirectInput::EnumDevices: Invalid dwDevType");
  613. hres = E_INVALIDARG;
  614. } else
  615. {
  616. hres = S_OK;
  617. }
  618. } else
  619. {
  620. RPF("IDirectInput::EnumDevices: Invalid dwDevType");
  621. hres = E_INVALIDARG;
  622. }
  623. return(hres);
  624. }
  625. STDMETHODIMP
  626. CDIObj_EnumDevicesW(PV pdiW, DWORD dwDevType,
  627. LPDIENUMDEVICESCALLBACKW pec, LPVOID pvRef, DWORD fl)
  628. {
  629. HRESULT hres;
  630. EnterProcR(IDirectInput8::EnumDevices,
  631. (_ "pxppx", pdiW, dwDevType, pec, pvRef, fl));
  632. if ( SUCCEEDED(hres = hresPvI(pdiW, ThisInterfaceW)) &&
  633. SUCCEEDED(hres = hresFullValidPfn(pec, 2)) &&
  634. SUCCEEDED(hres = CDIObj_EnumDevices_IsValidTypeFilter(dwDevType)) &&
  635. SUCCEEDED(hres = hresFullValidFl(fl, DIEDFL_VALID, 4)) )
  636. {
  637. PDDI this = _thisPvNm(pdiW, diW);
  638. if ( SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion)) )
  639. {
  640. CDIDEnum *pde;
  641. hres = CDIDEnum_New(&this->diW, dwDevType, fl, this->dwVersion, &pde);
  642. if ( SUCCEEDED(hres) )
  643. {
  644. DIDEVICEINSTANCEW ddiW;
  645. ddiW.dwSize = cbX(ddiW);
  646. while ( (hres = CDIDEnum_Next(pde, &ddiW)) == S_OK )
  647. {
  648. BOOL fRc;
  649. /*
  650. * WARNING! "goto" here! Make sure that nothing
  651. * is held while we call the callback.
  652. */
  653. fRc = Callback(pec, &ddiW, pvRef);
  654. switch ( fRc )
  655. {
  656. case DIENUM_STOP: goto enumdoneok;
  657. case DIENUM_CONTINUE: break;
  658. default:
  659. RPF("%s: Invalid return value from callback", s_szProc);
  660. ValidationException();
  661. break;
  662. }
  663. }
  664. AssertF(hres == S_FALSE);
  665. enumdoneok:;
  666. CDIDEnum_Release(pde);
  667. hres = S_OK;
  668. }
  669. }
  670. }
  671. ExitOleProcR();
  672. return(hres);
  673. }
  674. BOOL INTERNAL CDIObj_InternalDeviceEnumProcW(LPDIDEVICEINSTANCEW pddiW, LPDIRECTINPUTDEVICE8W pdid8W, LPVOID pv);
  675. STDMETHODIMP
  676. CDIObj_InternalEnumDevicesW(PV pdiW, DWORD dwDevType, LPVOID pvRef, DWORD fl)
  677. {
  678. HRESULT hres;
  679. CDIDEnum *pde;
  680. PDDI this = _thisPvNm(pdiW, diW);
  681. hres = CDIDEnum_New(&this->diW, dwDevType, fl, this->dwVersion, &pde);
  682. if ( SUCCEEDED(hres) )
  683. {
  684. DIDEVICEINSTANCEW ddiW;
  685. LPDIRECTINPUTDEVICE8W pdid8W;
  686. ddiW.dwSize = cbX(ddiW);
  687. while ( (hres = CDIDEnum_InternalNext(pde, &ddiW, &pdid8W)) == S_OK )
  688. {
  689. BOOL fRc;
  690. fRc = CDIObj_InternalDeviceEnumProcW(&ddiW, pdid8W, pvRef);
  691. switch ( fRc )
  692. {
  693. case DIENUM_STOP: goto enumdoneok;
  694. case DIENUM_CONTINUE: break;
  695. default:
  696. ValidationException();
  697. break;
  698. }
  699. }
  700. AssertF(hres == S_FALSE);
  701. enumdoneok:;
  702. CDIDEnum_Release(pde);
  703. hres = S_OK;
  704. }
  705. return(hres);
  706. }
  707. /*****************************************************************************
  708. *
  709. * @doc INTERNAL
  710. *
  711. * @func BOOL | CDIObj_EnumDevicesCallbackA |
  712. *
  713. * Wrapper function for <mf IDirectInput::EnumDevices>
  714. * which translates the UNICODE parameters to ANSI.
  715. *
  716. * @parm IN LPCDIDECICEINSTANCEW | pdiW |
  717. *
  718. * Same as <mf IDirectInput::EnumDevices>.
  719. *
  720. * @parm IN OUT PV | pvRef |
  721. *
  722. * Pointer to <t struct ENUMDEVICESINFO> which describes
  723. * the original callback.
  724. *
  725. * @returns
  726. *
  727. * Returns whatever the original callback returned.
  728. *
  729. *****************************************************************************/
  730. typedef struct ENUMDEVICESINFO
  731. {
  732. LPDIENUMDEVICESCALLBACKA pecA;
  733. PV pvRef;
  734. } ENUMDEVICESINFO, *PENUMDEVICESINFO;
  735. BOOL CALLBACK
  736. CDIObj_EnumDevicesCallback(LPCDIDEVICEINSTANCEW pdiW, PV pvRef)
  737. {
  738. PENUMDEVICESINFO pedi = pvRef;
  739. BOOL fRc;
  740. DIDEVICEINSTANCEA diA;
  741. EnterProc(CDIObj_EnumDevicesCallback,
  742. (_ "GGxWWp", &pdiW->guidInstance, &pdiW->guidProduct,
  743. &pdiW->dwDevType,
  744. pdiW->tszProductName, pdiW->tszInstanceName,
  745. pvRef));
  746. diA.dwSize = cbX(diA);
  747. DeviceInfoWToA(&diA, pdiW);
  748. fRc = pedi->pecA(&diA, pedi->pvRef);
  749. ExitProcX(fRc);
  750. return(fRc);
  751. }
  752. /*****************************************************************************
  753. *
  754. * @doc INTERNAL
  755. *
  756. * @method HRESULT | IDirectInputA | EnumDevices |
  757. *
  758. * ANSI version of <mf IDirectInput::EnumDevices>.
  759. * We wrap the operation.
  760. *
  761. * @parm IN LPGUID | lpGUIDDeviceType |
  762. * Same as <mf IDirectInput::EnumDevices>.
  763. *
  764. * @parm LPDIENUMDEVICESCALLBACKA | lpCallbackA |
  765. * Same as <mf IDirectInput::EnumDevices>, except ANSI.
  766. *
  767. * @parm IN LPVOID | pvRef |
  768. * Same as <mf IDirectInput::EnumDevices>.
  769. *
  770. * @parm DWORD | fl |
  771. * Same as <mf IDirectInput::EnumDevices>.
  772. *
  773. *****************************************************************************/
  774. STDMETHODIMP
  775. CDIObj_EnumDevicesA(PV pdiA, DWORD dwDevType,
  776. LPDIENUMDEVICESCALLBACKA pec, LPVOID pvRef, DWORD fl)
  777. {
  778. HRESULT hres;
  779. EnterProcR(IDirectInput8::EnumDevices,
  780. (_ "pxppx", pdiA, dwDevType, pec, pvRef, fl));
  781. /*
  782. * EnumDevicesW will validate the rest.
  783. */
  784. if ( SUCCEEDED(hres = hresPvI(pdiA, ThisInterfaceA)) &&
  785. SUCCEEDED(hres = hresFullValidPfn(pec, 1)) )
  786. {
  787. ENUMDEVICESINFO edi = { pec, pvRef};
  788. PDDI this = _thisPvNm(pdiA, diA);
  789. hres = CDIObj_EnumDevicesW(&this->diW, dwDevType,
  790. CDIObj_EnumDevicesCallback, &edi, fl);
  791. }
  792. ExitOleProcR();
  793. return(hres);
  794. }
  795. /*****************************************************************************
  796. *
  797. * @doc EXTERNAL
  798. *
  799. * @method HRESULT | IDirectInput | GetDeviceStatus |
  800. *
  801. * Determine whether a device is currently attached.
  802. *
  803. * @cwrap LPDIRECTINPUT | lpDirectInput
  804. *
  805. * @parm REFGUID | rguid |
  806. *
  807. * Identifies the instance of the
  808. * device whose status is being checked.
  809. *
  810. * @returns
  811. *
  812. * Returns a COM error code. The following error codes are
  813. * intended to be illustrative and not necessarily comprehensive.
  814. *
  815. * <c DI_OK> = <c S_OK>: The device is attached.
  816. *
  817. * <c DI_NOTATTACHED> = <c S_FALSE>: The device is not
  818. * attached.
  819. *
  820. * <c E_FAIL>: DirectInput could not determine
  821. * whether the device is attached.
  822. *
  823. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  824. * device does not exist.
  825. *
  826. *****************************************************************************/
  827. STDMETHODIMP
  828. CDIObj_GetDeviceStatus(PV pdi, REFGUID rguid _THAT)
  829. {
  830. HRESULT hres;
  831. EnterProcR(IDirectInput8::GetDeviceStatus, (_ "pG", pdi, rguid));
  832. if ( SUCCEEDED(hres = hresPvT(pdi)) )
  833. {
  834. PDDI this = _thisPv(pdi);
  835. PDIDW pdidW;
  836. hres = IDirectInput_CreateDevice(&this->diW, rguid, (PV)&pdidW, 0);
  837. if ( SUCCEEDED(hres) )
  838. {
  839. hres = CDIObj_TestDeviceFlags(pdidW, DIEDFL_ATTACHEDONLY);
  840. OLE_Release(pdidW);
  841. }
  842. }
  843. ExitOleProc();
  844. return(hres);
  845. }
  846. #ifdef XDEBUG
  847. CSET_STUBS(GetDeviceStatus, (PV pdi, REFGUID rguid), (pdi, rguid THAT_))
  848. #else
  849. #define CDIObj_GetDeviceStatusA CDIObj_GetDeviceStatus
  850. #define CDIObj_GetDeviceStatusW CDIObj_GetDeviceStatus
  851. #endif
  852. #ifdef DO_THE_IMPOSSIBLE
  853. /*****************************************************************************
  854. *
  855. * @doc EXTERNAL
  856. *
  857. * @method HRESULT | IDirectInput | SetAttachedDevice |
  858. *
  859. * Informs DirectInput that a new device has been attached
  860. * to the system by the user. This is useful when an application
  861. * asks the user to attach a currently installed device but does
  862. * not want to launch the DirectInput control panel.
  863. *
  864. * DirectInput needs to be informed that the device has
  865. * been attached for internal bookkeeping purposes.
  866. *
  867. * @cwrap LPDIRECTINPUT | lpDirectInput
  868. *
  869. * @parm IN LPDIRECTINPUTDEVICE | lpDIDevice |
  870. *
  871. * Identifies the device which has been attached.
  872. *
  873. * @returns
  874. *
  875. * Returns a COM error code. The following error codes are
  876. * intended to be illustrative and not necessarily comprehensive.
  877. *
  878. * <c DI_OK> = <c S_OK>: The device is attached.
  879. *
  880. * @devnote
  881. *
  882. * This method is not implemented in the current release
  883. * of DirectInput.
  884. *
  885. * This won't work. We need to receive a port, too.
  886. * And how can the app create a <p lpDIDevice> in the
  887. * first place for a device that does not exist?
  888. * I guess I just don't understand.
  889. *
  890. *****************************************************************************/
  891. STDMETHODIMP
  892. CDIObj_SetAttachedDevice(PV pdi, PV pdid _THAT)
  893. {
  894. HRESULT hres;
  895. EnterProcR(IDirectInput8::SetAttachedDevice, (_ "pp", pdi, pdid));
  896. if ( SUCCEEDED(hres = hresPvT(pdi)) )
  897. {
  898. PDDI this = _thisPv(pdi);
  899. hres = E_NOTIMPL;
  900. }
  901. ExitOleProc();
  902. return(hres);
  903. }
  904. #ifdef XDEBUG
  905. CSET_STUBS(SetAttachedDevice, (PV pdi, PV pdid), (pdi, pdid THAT_))
  906. #else
  907. #define CDIObj_SetAttachedDeviceA CDIObj_SetAttachedDevice
  908. #define CDIObj_SetAttachedDeviceW CDIObj_SetAttachedDevice
  909. #endif
  910. #endif
  911. /*****************************************************************************
  912. *
  913. * @doc EXTERNAL
  914. *
  915. * @method HRESULT | IDirectInput | RunControlPanel |
  916. *
  917. * Run the DirectInput control panel so that the user can
  918. * install a new input device or modify the setup.
  919. *
  920. * This function will not run third-party control panels.
  921. *
  922. * @cwrap LPDIRECTINPUT | lpDirectInput
  923. *
  924. * @parm IN HWND | hwndOwner |
  925. *
  926. * Identifies the window handle that will be used as the
  927. * parent window for subsequent UI. NULL is a valid parameter,
  928. * indicating that there is no parent window.
  929. *
  930. * @parm DWORD | dwFlags |
  931. *
  932. * No flags are currently defined. This parameter "must" be
  933. * zero.
  934. *
  935. * @returns
  936. * Returns a COM error code. The following error codes are
  937. * intended to be illustrative and not necessarily comprehensive.
  938. *
  939. * <c DI_OK> = <c S_OK>: The device is attached.
  940. *
  941. * @devnote
  942. *
  943. * The <p dwFlags> is eventually going to allow
  944. * <c DIRCP_MODAL> to request a modal control panel.
  945. *
  946. *****************************************************************************/
  947. #pragma BEGIN_CONST_DATA
  948. STDMETHODIMP
  949. CDIObj_RunControlPanel(PV pdi, HWND hwndOwner, DWORD fl _THAT)
  950. {
  951. HRESULT hres;
  952. EnterProcR(IDirectInput8::RunControlPanel, (_ "pxx", pdi, hwndOwner, fl));
  953. if ( SUCCEEDED(hres = hresPvT(pdi)) &&
  954. SUCCEEDED(hres = hresFullValidHwnd0(hwndOwner, 1)) &&
  955. SUCCEEDED(hres = hresFullValidFl(fl, DIRCP_VALID, 2)) )
  956. {
  957. PDDI this = _thisPv(pdi);
  958. if ( SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion)) )
  959. {
  960. /*
  961. * We used to run "directx.cpl,@0,3" but directx.cpl is not
  962. * redistributable; it comes only with the SDK. So we just
  963. * run the system control panel.
  964. */
  965. hres = hresRunControlPanel(TEXT(""));
  966. }
  967. }
  968. ExitOleProc();
  969. return(hres);
  970. }
  971. #ifdef XDEBUG
  972. CSET_STUBS(RunControlPanel, (PV pdi, HWND hwndOwner, DWORD fl),
  973. (pdi, hwndOwner, fl THAT_))
  974. #else
  975. #define CDIObj_RunControlPanelA CDIObj_RunControlPanel
  976. #define CDIObj_RunControlPanelW CDIObj_RunControlPanel
  977. #endif
  978. /*****************************************************************************
  979. *
  980. * @doc EXTERNAL
  981. *
  982. * @method HRESULT | IDirectInput | Initialize |
  983. *
  984. * Initialize a DirectInput object.
  985. *
  986. * The <f DirectInputCreate> method automatically
  987. * initializes the DirectInput object device after creating it.
  988. * Applications normally do not need to call this function.
  989. *
  990. * @cwrap LPDIRECTINPUT | lpDirectInput
  991. *
  992. * @parm IN HINSTANCE | hinst |
  993. *
  994. * Instance handle of the application or DLL that is creating
  995. * the DirectInput object.
  996. *
  997. * See the section titled "Initialization and Versions"
  998. * for more information.
  999. *
  1000. * @parm DWORD | dwVersion |
  1001. *
  1002. * Version number of the dinput.h header file that was used.
  1003. *
  1004. * See the section titled "Initialization and Versions"
  1005. * for more information.
  1006. *
  1007. * @returns
  1008. * Returns a COM error code. The following error codes are
  1009. * intended to be illustrative and not necessarily comprehensive.
  1010. *
  1011. * <c DI_OK> = <c S_OK>: The device is attached.
  1012. *
  1013. * <c DIERR_DIERR_OLDDIRECTINPUTVERSION>: The application
  1014. * requires a newer version of DirectInput.
  1015. *
  1016. * <c DIERR_DIERR_BETADIRECTINPUTVERSION>: The application
  1017. * was written for an unsupported prerelease version
  1018. * of DirectInput.
  1019. *
  1020. *****************************************************************************/
  1021. STDMETHODIMP
  1022. CDIObj_Initialize(PV pdi, HINSTANCE hinst, DWORD dwVersion _THAT)
  1023. {
  1024. HRESULT hres;
  1025. EnterProcR(IDirectInput8::Initialize, (_ "pxx", pdi, hinst, dwVersion));
  1026. if ( SUCCEEDED(hres = hresPvT(pdi)) )
  1027. {
  1028. PDDI this = _thisPv(pdi);
  1029. if ( SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion)) )
  1030. {
  1031. this->dwVersion = dwVersion;
  1032. }
  1033. }
  1034. #ifndef DX_FINAL_RELEASE
  1035. {
  1036. #pragma message("BETA EXPIRATION TIME BOMB! Remove for final build!")
  1037. SYSTEMTIME st;
  1038. GetSystemTime(&st);
  1039. if ( st.wYear > DX_EXPIRE_YEAR ||
  1040. ((st.wYear == DX_EXPIRE_YEAR) && (MAKELONG(st.wDay, st.wMonth) > MAKELONG(DX_EXPIRE_DAY, DX_EXPIRE_MONTH)))
  1041. ) {
  1042. MessageBox(0, DX_EXPIRE_TEXT,
  1043. TEXT("Microsoft DirectInput"), MB_OK);
  1044. }
  1045. }
  1046. #endif
  1047. ExitOleProc();
  1048. return(hres);
  1049. }
  1050. #ifdef XDEBUG
  1051. CSET_STUBS(Initialize, (PV pdi, HINSTANCE hinst, DWORD dwVersion),
  1052. (pdi, hinst, dwVersion THAT_))
  1053. #else
  1054. #define CDIObj_InitializeA CDIObj_Initialize
  1055. #define CDIObj_InitializeW CDIObj_Initialize
  1056. #endif
  1057. /*****************************************************************************
  1058. *
  1059. * @doc INTERNAL
  1060. *
  1061. * @func HRESULT | CDIObj_FindDeviceInternal |
  1062. *
  1063. * The worker function for
  1064. * <mf IDirectInput2::FindDevice> which works only for HID devices.
  1065. *
  1066. * For more details, see <mf IDirectInput2::FindDevice>.
  1067. *
  1068. * @parm LPCTSTR | ptszName |
  1069. *
  1070. * The name of the device relative to the class <t GUID>.
  1071. *
  1072. * @parm OUT LPGUID | pguidOut |
  1073. *
  1074. * Pointer to a <t GUID> which receives the instance
  1075. * <t GUID> for the device, if the device is found.
  1076. *
  1077. *****************************************************************************/
  1078. HRESULT EXTERNAL
  1079. CDIObj_FindDeviceInternal(LPCTSTR ptszName, LPGUID pguidOut)
  1080. {
  1081. HRESULT hres;
  1082. /*
  1083. * Look twice. If it's not found the first time,
  1084. * then refresh the cache and try again in case
  1085. * it was for a device that was recently added.
  1086. * (In fact, it will likely be a device that was
  1087. * recently added, because FindDevice is usually
  1088. * called in response to a Plug and Play event.)
  1089. */
  1090. hres = hresFindHIDDeviceInterface(ptszName, pguidOut);
  1091. if ( FAILED(hres) )
  1092. {
  1093. DIHid_BuildHidList(TRUE);
  1094. hres = hresFindHIDDeviceInterface(ptszName, pguidOut);
  1095. }
  1096. return(hres);
  1097. }
  1098. /*****************************************************************************
  1099. *
  1100. * @doc EXTERNAL
  1101. *
  1102. * @method HRESULT | IDirectInput2 | FindDevice |
  1103. *
  1104. * Obtain the instance <t GUID> for a device given
  1105. * its class <t GUID> and an opaque name.
  1106. *
  1107. * This method can be used by applications which register
  1108. * for Plug and Play notifications and are notified by
  1109. * Plug and Play that a new device has been added
  1110. * to the system. The Plug and Play notification will
  1111. * be in the form of a class <t GUID> and a device name.
  1112. * The application can pass the <t GUID> and name to
  1113. * this method to obtain the instance <t GUID> for
  1114. * the device, which can then be passed to
  1115. * <mf IDirectInput::CreateDevice> or
  1116. * <mf IDirectInput::GetDeviceStatus>.
  1117. *
  1118. * @cwrap LPDIRECTINPUT2 | lpDirectInput2
  1119. *
  1120. * @parm REFGUID | rguidClass |
  1121. *
  1122. * Class <t GUID> identifying the device class
  1123. * for the device the application wishes to locate.
  1124. *
  1125. * The application obtains the class <t GUID> from the
  1126. * Plug and Play device arrival notification.
  1127. *
  1128. * @parm LPCTSTR | ptszName |
  1129. *
  1130. * The name of the device relative to the class <t GUID>.
  1131. *
  1132. * The application obtains the class name from the
  1133. * Plug and Play device arrival notification.
  1134. *
  1135. * @parm OUT LPGUID | pguidInstance |
  1136. *
  1137. * Pointer to a <t GUID> which receives the instance
  1138. * <t GUID> for the device, if the device is found.
  1139. *
  1140. * @returns
  1141. * Returns a COM error code. The following error codes are
  1142. * intended to be illustrative and not necessarily comprehensive.
  1143. *
  1144. * <c DI_OK> = <c S_OK>: The device was found, and its
  1145. * instance <t GUID> has been stored in <p pguidInstance>.
  1146. *
  1147. * <c DIERR_DEVICENOTREG> = The <t GUID> and name do not
  1148. * correspond to a device that is registered with DirectInput.
  1149. * For example, they may refer to a storage device rather
  1150. * than an input device.
  1151. *
  1152. *****************************************************************************/
  1153. #define cchNameMax MAX_PATH
  1154. STDMETHODIMP
  1155. TFORM(CDIObj_FindDevice)(PV pdiT, REFGUID rguid,
  1156. LPCTSTR ptszName, LPGUID pguidOut)
  1157. {
  1158. HRESULT hres;
  1159. EnterProcR(IDirectInput8::FindDevice,
  1160. (_ "pGs", pdiT, rguid, ptszName));
  1161. if ( SUCCEEDED(hres = TFORM(hresPv)(pdiT)) &&
  1162. SUCCEEDED(hres = hresFullValidGuid(rguid, 1)) &&
  1163. SUCCEEDED(hres = TFORM(hresFullValidReadStr)(ptszName,
  1164. cchNameMax, 2)) &&
  1165. SUCCEEDED(hres = hresFullValidWritePvCb(pguidOut, cbX(GUID), 3)) )
  1166. {
  1167. if ( IsEqualIID(rguid, &GUID_HIDClass) )
  1168. {
  1169. hres = CDIObj_FindDeviceInternal(ptszName, pguidOut);
  1170. } else
  1171. {
  1172. hres = DIERR_DEVICENOTREG;
  1173. }
  1174. }
  1175. ExitOleProc();
  1176. return(hres);
  1177. }
  1178. STDMETHODIMP
  1179. SFORM(CDIObj_FindDevice)(PV pdiS, REFGUID rguid,
  1180. LPCSSTR psszName, LPGUID pguidOut)
  1181. {
  1182. HRESULT hres;
  1183. TCHAR tsz[cchNameMax];
  1184. EnterProcR(IDirectInput8::FindDevice,
  1185. (_ "pGS", pdiS, rguid, psszName));
  1186. /*
  1187. * TFORM(CDIObj_FindDevice) will validate the rguid and pguidOut.
  1188. */
  1189. if ( SUCCEEDED(hres = SFORM(hresPv)(pdiS)) &&
  1190. SUCCEEDED(hres = SFORM(hresFullValidReadStr)(psszName, cA(tsz), 2)) )
  1191. {
  1192. PDDI this = _thisPvNm(pdiS, SFORM(di));
  1193. SToT(tsz, cA(tsz), psszName);
  1194. hres = TFORM(CDIObj_FindDevice)(&this->TFORM(di), rguid, tsz, pguidOut);
  1195. }
  1196. ExitOleProc();
  1197. return(hres);
  1198. }
  1199. /*****************************************************************************
  1200. *
  1201. * @doc INTERNAL
  1202. *
  1203. * @mfunc HRESULT | IDirectInput | New |
  1204. *
  1205. * Create a new instance of an IDirectInput object.
  1206. *
  1207. * @parm IN PUNK | punkOuter |
  1208. *
  1209. * Controlling unknown for aggregation.
  1210. *
  1211. * @parm IN RIID | riid |
  1212. * Desired interface to new object.
  1213. *
  1214. * @parm OUT PPV | ppvObj |
  1215. * Output pointer for new object.
  1216. *
  1217. * @returns
  1218. *
  1219. * Standard OLE <t HRESULT>.
  1220. *
  1221. *****************************************************************************/
  1222. STDMETHODIMP
  1223. CDIObj_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  1224. {
  1225. HRESULT hres;
  1226. EnterProcR(IDirectInput8::CreateInstance, (_ "Gp", riid, ppvObj));
  1227. hres = Excl_Init();
  1228. if ( SUCCEEDED(hres) )
  1229. {
  1230. /*
  1231. * Note that we cannot use Common_NewRiid for an object
  1232. * that aggregates other interfaces!
  1233. *
  1234. * The reason is that Common_NewRiid will perform
  1235. * a QI as part of the initialization, but we cannot handle
  1236. * the QI until after we've been initialized and are
  1237. * ready to mess with aggregated goo.
  1238. */
  1239. if ( SUCCEEDED(hres = hresFullValidRiid(riid, 2)) )
  1240. {
  1241. if ( fLimpFF(punkOuter, IsEqualIID(riid, &IID_IUnknown)) )
  1242. {
  1243. hres = Common_New(CDIObj, punkOuter, ppvObj);
  1244. if ( SUCCEEDED(hres) )
  1245. {
  1246. PDDI this = _thisPv(*ppvObj);
  1247. this->fCritInited = fInitializeCriticalSection(&this->crst);
  1248. if ( this->fCritInited )
  1249. {
  1250. /*
  1251. * Only after the object is ready do we QI for the
  1252. * requested interface. And the reason is that the
  1253. * QI might cause us to create an aggregated buddy,
  1254. * which we can't do until we've been initialized.
  1255. *
  1256. * Don't do this extra QI if we are ourselves aggregated,
  1257. * or we will end up giving the wrong punk to the caller!
  1258. */
  1259. if ( punkOuter == 0 )
  1260. {
  1261. hres = OLE_QueryInterface(this, riid, ppvObj);
  1262. OLE_Release(this);
  1263. }
  1264. if ( FAILED(hres) )
  1265. {
  1266. Invoke_Release(ppvObj);
  1267. }
  1268. } else
  1269. {
  1270. Common_Unhold(this);
  1271. *ppvObj = NULL;
  1272. hres = E_OUTOFMEMORY;
  1273. }
  1274. }
  1275. } else
  1276. {
  1277. RPF("CreateDevice: IID must be IID_IUnknown if created for aggregation");
  1278. *ppvObj = 0;
  1279. hres = CLASS_E_NOAGGREGATION;
  1280. }
  1281. }
  1282. }
  1283. ExitOleProcPpvR(ppvObj);
  1284. return(hres);
  1285. }
  1286. /*****************************************************************************
  1287. *
  1288. * @doc INTERNAL
  1289. *
  1290. * @func BOOL | CDIObj_IsDeviceUsedByUser |
  1291. *
  1292. * To Test whether the device is used by the user as specified by pdm->lpszUserName.
  1293. *
  1294. * @parm IN LPDIDEVICEINSTANCEW | pddiW |
  1295. *
  1296. * Device Instance.
  1297. *
  1298. * @parm IN LPDIMAPPER | pdm |
  1299. *
  1300. * pointer to DIMAPPER structure
  1301. *
  1302. * @returns
  1303. *
  1304. * TRUE: device is used by the user
  1305. * FALSE: otherwise
  1306. *
  1307. *****************************************************************************/
  1308. BOOL INTERNAL
  1309. CDIObj_IsDeviceUsedByUser( LPDIDEVICEINSTANCEW pddiW, LPDIMAPPER pdm )
  1310. {
  1311. HRESULT hres;
  1312. BOOL fRtn = FALSE;
  1313. WCHAR wszUserName[UNLEN+1];
  1314. hres = CMap_GetDeviceUserName( &pddiW->guidInstance, wszUserName );
  1315. if( hres == S_OK ) {
  1316. DWORD dwLen = 0;
  1317. dwLen = lstrlenW(pdm->lpszUserName);
  1318. if(memcmp(pdm->lpszUserName, wszUserName, dwLen*2) == 0)
  1319. {
  1320. fRtn = TRUE;
  1321. }
  1322. }
  1323. return(fRtn);
  1324. }
  1325. /*****************************************************************************
  1326. *
  1327. * @doc INTERNAL
  1328. *
  1329. * @func BOOL | CDIObj_IsDeviceAvailable |
  1330. *
  1331. * To Test whether the device is still available.
  1332. *
  1333. * @parm IN LPDIDEVICEINSTANCEW | pddiW |
  1334. *
  1335. * Device Instance.
  1336. *
  1337. * @parm IN LPDIMAPPER | pdm |
  1338. *
  1339. * pointer to DIMAPPER structure
  1340. *
  1341. * @returns
  1342. *
  1343. * TRUE: device is available
  1344. * FALSE: not available
  1345. *
  1346. *****************************************************************************/
  1347. BOOL INTERNAL
  1348. CDIObj_IsDeviceAvailable( LPDIDEVICEINSTANCEW pddiW, LPDIMAPPER pdm )
  1349. {
  1350. HRESULT hres;
  1351. BOOL fAvailable = FALSE;
  1352. WCHAR wszUserName[UNLEN+1];
  1353. hres = CMap_GetDeviceUserName( &pddiW->guidInstance, wszUserName );
  1354. if( hres != S_OK ) {
  1355. fAvailable = TRUE;
  1356. }
  1357. return(fAvailable);
  1358. }
  1359. /*****************************************************************************
  1360. *
  1361. * @doc INTERNAL
  1362. *
  1363. * @func BOOL | CDIObj_IsUserConfigured |
  1364. *
  1365. * To Test whether the device has been configured by user.
  1366. *
  1367. * @parm IN LPDIDEVICEINSTANCEW | pddiW |
  1368. *
  1369. * Device Instance.
  1370. *
  1371. * @parm IN LPDIMAPPER | pdm |
  1372. *
  1373. * pointer to DIMAPPER structure
  1374. *
  1375. * @returns
  1376. *
  1377. * TRUE: user configured
  1378. * FALSE: not configured
  1379. *
  1380. *****************************************************************************/
  1381. BOOL INTERNAL
  1382. CDIObj_IsUserConfigured( LPDIDEVICEINSTANCEW pddiW, LPDIMAPPER pdm )
  1383. {
  1384. LPDIACTIONFORMATW pdiaf = pdm->pDiActionFormat;
  1385. BOOL fConfigured = FALSE;
  1386. DWORD i;
  1387. for ( i=0; i<pdiaf->dwNumActions; i++ )
  1388. {
  1389. if ( IsEqualGUID(&pdiaf->rgoAction[i].guidInstance, &pddiW->guidInstance) )
  1390. {
  1391. fConfigured = (pdiaf->rgoAction[i].dwHow & DIAH_USERCONFIG) ? TRUE: FALSE;
  1392. break;
  1393. }
  1394. }
  1395. return(fConfigured);
  1396. }
  1397. /*****************************************************************************
  1398. *
  1399. * @doc INTERNAL
  1400. *
  1401. * @func int | CDIObj_GetMappedActionNum |
  1402. *
  1403. * Get the number of the actions which have been mapped to controls.
  1404. *
  1405. * @parm IN LPDIDEVICEINSTANCEW | pddiW |
  1406. *
  1407. * Device Instance.
  1408. *
  1409. * @parm IN LPDIMAPPER | pdm |
  1410. *
  1411. * Pointer to DIMAPPER structure
  1412. *
  1413. * @returns
  1414. *
  1415. * Number of mapped actions
  1416. *
  1417. *****************************************************************************/
  1418. int INTERNAL
  1419. CDIObj_GetMappedActionNum( LPDIDEVICEINSTANCEW pddiW, LPDIMAPPER pdm )
  1420. {
  1421. LPDIACTIONFORMATW pdiaf = pdm->pDiActionFormat;
  1422. DWORD i;
  1423. int num = 0;
  1424. for ( i=0; i<pdiaf->dwNumActions; i++ )
  1425. {
  1426. if ( IsEqualGUID(&pdiaf->rgoAction[i].guidInstance, &pddiW->guidInstance) )
  1427. {
  1428. if ( pdiaf->rgoAction[i].dwHow & DIAH_MAPMASK )
  1429. {
  1430. num++;
  1431. }
  1432. }
  1433. }
  1434. return(num);
  1435. }
  1436. /*****************************************************************************
  1437. *
  1438. * @doc INTERNAL
  1439. *
  1440. * @func DWORD | CDIObj_GetMappedPriorities |
  1441. *
  1442. * Get the priorities of the mapeed actions.
  1443. *
  1444. * @parm IN LPDIDEVICEINSTANCEW | pddiW |
  1445. *
  1446. * Device Instance.
  1447. *
  1448. * @parm IN LPDIMAPPER | pdm |
  1449. *
  1450. * Pointer to DIMAPPER structure
  1451. *
  1452. * @returns
  1453. *
  1454. * The priorities of mapped actions. Can be DIEDBS_MAPPEDPRI1,
  1455. * DIEDBS_MAPPEDPRI2, or the OR of both.
  1456. *
  1457. *****************************************************************************/
  1458. DWORD INTERNAL
  1459. CDIObj_GetMappedPriorities( LPDIDEVICEINSTANCEW pddiW, LPDIMAPPER pdm )
  1460. {
  1461. LPDIACTIONFORMATW pdiaf = pdm->pDiActionFormat;
  1462. DWORD i;
  1463. DWORD pri = 0;
  1464. for ( i=0; i<pdiaf->dwNumActions; i++ )
  1465. {
  1466. if( pri == ( DIEDBS_MAPPEDPRI1 | DIEDBS_MAPPEDPRI2 ) ) {
  1467. break;
  1468. }
  1469. if ( IsEqualGUID(&pdiaf->rgoAction[i].guidInstance, &pddiW->guidInstance) &&
  1470. pdiaf->rgoAction[i].dwHow & DIAH_MAPMASK
  1471. )
  1472. {
  1473. if( DISEM_PRI_GET(pdiaf->rgoAction[i].dwSemantic) == 0 )
  1474. {
  1475. pri |= DIEDBS_MAPPEDPRI1;
  1476. } else if( DISEM_PRI_GET(pdiaf->rgoAction[i].dwSemantic) == 1 ) {
  1477. pri |= DIEDBS_MAPPEDPRI2;
  1478. }
  1479. }
  1480. }
  1481. return(pri);
  1482. }
  1483. /*****************************************************************************
  1484. *
  1485. * @doc INTERNAL
  1486. *
  1487. * @func int | CDIObj_GetDeviceOrder |
  1488. *
  1489. * Get the number of the actions which have been mapped to controls.
  1490. *
  1491. * @parm IN LPDIDEVICEINSTANCEW | pddiW |
  1492. *
  1493. * Device Instance.
  1494. *
  1495. * @parm IN LPDIMAPPER | pdm |
  1496. *
  1497. * pointer to DIMAPPER structure
  1498. *
  1499. * @returns
  1500. *
  1501. * The order of the device
  1502. *
  1503. * @comm
  1504. * The order (DWORD) is consisted of three parts:
  1505. * HIWORD: HIBYTE: the order defined in the genre
  1506. * LOWBYTE: none, can be used later
  1507. * LOWORD: HIBYTE - mapped action number
  1508. * LOWBYTE - Force Feedback (1) or not (0)
  1509. *
  1510. *****************************************************************************/
  1511. #define GET_MAPPED_ACTION_NUM(x) ((x & 0x0000ff00) >> 8)
  1512. DWORD INTERNAL
  1513. CDIObj_GetDeviceOrder( LPDIDEVICEINSTANCEW pddiW, LPDIMAPPER pdm )
  1514. {
  1515. WORD wHighWord, wLowWord;
  1516. BYTE byDevOrder, byFF, byMappedActions;
  1517. DWORD dwGenre, dwJoyType;
  1518. BYTE byOrder;
  1519. AssertF(pddiW);
  1520. AssertF(pdm->pDiActionFormat);
  1521. if ( CDIObj_IsUserConfigured( pddiW, pdm ) )
  1522. {
  1523. byDevOrder = MAX_ORDER;
  1524. } else
  1525. {
  1526. switch( GET_DIDEVICE_TYPE(pddiW->dwDevType) )
  1527. {
  1528. case DI8DEVTYPE_DEVICE:
  1529. if( !(pdm->dwFlags & DIEDBSFL_NONGAMINGDEVICES) )
  1530. {
  1531. byDevOrder = INVALID_ORDER;
  1532. } else {
  1533. byDevOrder = DIDEVTYPE_DEVICE_ORDER;
  1534. }
  1535. break;
  1536. case DI8DEVTYPE_MOUSE:
  1537. if( pddiW->dwDevType & DIDEVTYPE_HID )
  1538. {
  1539. if( !(pdm->dwFlags & DIEDBSFL_MULTIMICEKEYBOARDS) ) {
  1540. byDevOrder = INVALID_ORDER;
  1541. } else {
  1542. byDevOrder = DIDEVTYPE_HID_MOUSE_ORDER;
  1543. }
  1544. } else {
  1545. byDevOrder = DIDEVTYPE_MOUSE_ORDER;
  1546. }
  1547. break;
  1548. case DI8DEVTYPE_KEYBOARD:
  1549. if( pddiW->dwDevType & DIDEVTYPE_HID )
  1550. {
  1551. if( !(pdm->dwFlags & DIEDBSFL_MULTIMICEKEYBOARDS) ) {
  1552. byDevOrder = INVALID_ORDER;
  1553. } else {
  1554. byDevOrder = DIDEVTYPE_HID_KEYBOARD_ORDER;
  1555. }
  1556. } else {
  1557. byDevOrder = DIDEVTYPE_KEYBOARD_ORDER;
  1558. }
  1559. break;
  1560. case DI8DEVTYPE_JOYSTICK:
  1561. case DI8DEVTYPE_GAMEPAD:
  1562. case DI8DEVTYPE_DRIVING:
  1563. case DI8DEVTYPE_FLIGHT:
  1564. case DI8DEVTYPE_1STPERSON:
  1565. case DI8DEVTYPE_SCREENPOINTER:
  1566. case DI8DEVTYPE_REMOTE:
  1567. case DI8DEVTYPE_DEVICECTRL:
  1568. dwJoyType = GET_DIDEVICE_TYPE(pddiW->dwDevType);
  1569. dwGenre = DISEM_VIRTUAL_GET(pdm->pDiActionFormat->dwGenre);
  1570. AssertF(dwGenre <= DISEM_MAX_GENRE);
  1571. AssertF(dwJoyType < DI8DEVTYPE_MAX);
  1572. AssertF(dwJoyType != 0);
  1573. for ( byOrder=DI8DEVTYPE_MIN; byOrder<DI8DEVTYPE_MAX; byOrder++ )
  1574. {
  1575. if ( DiGenreDeviceOrder[dwGenre][byOrder-DI8DEVTYPE_MIN] == dwJoyType )
  1576. {
  1577. break;
  1578. }
  1579. }
  1580. /*
  1581. * If the device is not on the default list, set its order as
  1582. * DIDEVTYPE_NOTDEFAULTDEVICE_ORDER + 1
  1583. */
  1584. byDevOrder = DI8DEVTYPE_MAX - byOrder + DIDEVTYPE_SUPPLEMENTAL_ORDER + 1;
  1585. break;
  1586. case DI8DEVTYPE_SUPPLEMENTAL:
  1587. byDevOrder = DIDEVTYPE_SUPPLEMENTAL_ORDER;
  1588. break;
  1589. }
  1590. }
  1591. if( byDevOrder != INVALID_ORDER ) {
  1592. byFF = IsEqualGUID(&pddiW->guidFFDriver, &GUID_Null) ? 0 : 1;
  1593. byMappedActions = (UCHAR) CDIObj_GetMappedActionNum( pddiW, pdm );
  1594. wLowWord = MAKEWORD( byFF, byMappedActions );
  1595. wHighWord = MAKEWORD( 0, byDevOrder );
  1596. return(MAKELONG( wLowWord, wHighWord ));
  1597. } else {
  1598. return 0;
  1599. }
  1600. }
  1601. /*****************************************************************************
  1602. *
  1603. * CDIObj_DeviceEnumProc
  1604. *
  1605. * Device enumeration procedure which is called one for each device.
  1606. *
  1607. *****************************************************************************/
  1608. BOOL INTERNAL
  1609. CDIObj_InternalDeviceEnumProcW(LPDIDEVICEINSTANCEW pddiW, LPDIRECTINPUTDEVICE8W pdid8W, LPVOID pv)
  1610. {
  1611. LPDIMAPPER pdm = pv;
  1612. HRESULT hres = S_OK;
  1613. BOOL fRc = DIENUM_CONTINUE;
  1614. BOOL fContinue = FALSE;
  1615. DWORD dwDevOrder;
  1616. if ( g_nCurDev >= MAX_DEVICENUM )
  1617. {
  1618. fRc = DIENUM_STOP;
  1619. goto _done;
  1620. }
  1621. AssertF(pdid8W);
  1622. AssertF(pdm->pDiActionFormat);
  1623. hres = pdid8W->lpVtbl->BuildActionMap(pdid8W, pdm->pDiActionFormat, pdm->lpszUserName,
  1624. pdm->lpszUserName ? DIDBAM_DEFAULT : DIDBAM_HWDEFAULTS);
  1625. if ( SUCCEEDED(hres) )
  1626. {
  1627. if ( (pdm->dwFlags & DIEDBSFL_AVAILABLEDEVICES) ||
  1628. (pdm->dwFlags & DIEDBSFL_THISUSER) )
  1629. {
  1630. if( ((pdm->dwFlags & DIEDBSFL_AVAILABLEDEVICES) && CDIObj_IsDeviceAvailable(pddiW,pdm)) ||
  1631. ((pdm->dwFlags & DIEDBSFL_THISUSER) && CDIObj_IsDeviceUsedByUser(pddiW,pdm))
  1632. ) {
  1633. fContinue = TRUE;
  1634. }
  1635. } else {
  1636. fContinue = TRUE;
  1637. }
  1638. if( fContinue &&
  1639. ((dwDevOrder = CDIObj_GetDeviceOrder(pddiW, pdm)) != 0) )
  1640. {
  1641. #ifdef DEBUG
  1642. DWORD dbgRef;
  1643. #endif
  1644. #ifdef DEBUG
  1645. dbgRef =
  1646. #endif
  1647. pdid8W->lpVtbl->AddRef(pdid8W);
  1648. g_DiDevices[g_nCurDev].dwOrder = dwDevOrder;
  1649. g_DiDevices[g_nCurDev].dwFlags = CDIObj_GetMappedPriorities( pddiW, pdm );
  1650. g_DiDevices[g_nCurDev].pdid8W = pdid8W;
  1651. memcpy( &g_DiDevices[g_nCurDev].ftTimeStamp, &pdm->pDiActionFormat->ftTimeStamp, sizeof(FILETIME) );
  1652. memcpy( &g_DiDevices[g_nCurDev].ddiW, pddiW, sizeof(*pddiW) );
  1653. g_nCurDev ++;
  1654. fRc = DIENUM_CONTINUE;
  1655. }
  1656. }
  1657. _done:
  1658. return(fRc);
  1659. }
  1660. /*****************************************************************************
  1661. *
  1662. * compare
  1663. *
  1664. * Compare func used in shortsort
  1665. *
  1666. *****************************************************************************/
  1667. int __cdecl compare( const void *arg1, const void *arg2 )
  1668. {
  1669. DWORD dw1 = ((LPDIORDERDEV)arg1)->dwOrder;
  1670. DWORD dw2 = ((LPDIORDERDEV)arg2)->dwOrder;
  1671. /*
  1672. * Compare the device order
  1673. * If necessary, we can compare seperately: devtype, mapped action number, FF device
  1674. */
  1675. if ( dw1 < dw2 )
  1676. {
  1677. return(1);
  1678. } else if ( dw1 > dw2 )
  1679. {
  1680. return(-1);
  1681. } else
  1682. {
  1683. return(0);
  1684. }
  1685. }
  1686. void FreeDiActionFormatW(LPDIACTIONFORMATW* lplpDiAfW )
  1687. {
  1688. FreePpv(lplpDiAfW);
  1689. }
  1690. /*****************************************************************************
  1691. *
  1692. * @doc INTERNAL
  1693. *
  1694. * @func HRESULT | IsValidMapObjectA |
  1695. *
  1696. * Validates a LPDIACTIONFORMATW including strings
  1697. *
  1698. * @parm const LPDIACTIONFORMATW | lpDiAfW |
  1699. *
  1700. * Original.
  1701. *
  1702. * @returns
  1703. *
  1704. * Standard OLE <t HRESULT>.
  1705. *
  1706. *****************************************************************************/
  1707. HRESULT
  1708. IsValidMapObjectA
  1709. (
  1710. LPDIACTIONFORMATA paf
  1711. #ifdef XDEBUG
  1712. comma LPCSTR pszProc
  1713. comma UINT argnum
  1714. #endif
  1715. )
  1716. {
  1717. HRESULT hres;
  1718. hres = CDIDev_ActionMap_IsValidMapObject
  1719. ( (LPDIACTIONFORMATW)paf
  1720. #ifdef XDEBUG
  1721. comma pszProc
  1722. comma argnum
  1723. #endif
  1724. );
  1725. if( SUCCEEDED( hres ) )
  1726. {
  1727. if( paf->dwSize != cbX(DIACTIONFORMATA) )
  1728. {
  1729. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMATA.dwSize 0x%08x",
  1730. pszProc, paf->dwSize ); )
  1731. hres = E_INVALIDARG;
  1732. }
  1733. }
  1734. if(SUCCEEDED(hres))
  1735. {
  1736. DWORD i;
  1737. LPDIACTIONA lpDiAA;
  1738. // Compute the size for each of the text strings in array of DIACTIONs
  1739. for ( i = 0x0, lpDiAA = paf->rgoAction;
  1740. i < paf->dwNumActions && SUCCEEDED(hres) ;
  1741. i++, lpDiAA++ )
  1742. {
  1743. // Handle the NULL ptr case
  1744. if ( NULL != lpDiAA->lptszActionName )
  1745. {
  1746. hres = hresFullValidReadStrA_(lpDiAA->lptszActionName, MAX_JOYSTRING, pszProc, argnum);
  1747. }
  1748. }
  1749. }
  1750. return hres;
  1751. }
  1752. /*****************************************************************************
  1753. *
  1754. * @doc INTERNAL
  1755. *
  1756. * @func HRESULT | IsValidMapObjectW |
  1757. *
  1758. * Validates a LPDIACTIONFORMATW including strings
  1759. *
  1760. * @parm const LPDIACTIONFORMATW | lpDiAfW |
  1761. *
  1762. * Original.
  1763. *
  1764. * @returns
  1765. *
  1766. * Standard OLE <t HRESULT>.
  1767. *
  1768. *****************************************************************************/
  1769. HRESULT
  1770. IsValidMapObjectW
  1771. (
  1772. LPDIACTIONFORMATW paf
  1773. #ifdef XDEBUG
  1774. comma LPCSTR pszProc
  1775. comma UINT argnum
  1776. #endif
  1777. )
  1778. {
  1779. HRESULT hres;
  1780. hres = CDIDev_ActionMap_IsValidMapObject
  1781. ( paf
  1782. #ifdef XDEBUG
  1783. comma pszProc
  1784. comma argnum
  1785. #endif
  1786. );
  1787. if( SUCCEEDED( hres ) )
  1788. {
  1789. if( paf->dwSize != cbX(DIACTIONFORMATW) )
  1790. {
  1791. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMATW.dwSize 0x%08x",
  1792. pszProc, paf->dwSize ); )
  1793. hres = E_INVALIDARG;
  1794. }
  1795. }
  1796. if(SUCCEEDED(hres))
  1797. {
  1798. DWORD i;
  1799. LPDIACTIONW lpDiAW;
  1800. // Compute the size for each of the text strings in array of DIACTIONs
  1801. for ( i = 0x0, lpDiAW = paf->rgoAction;
  1802. i < paf->dwNumActions && SUCCEEDED(hres) ;
  1803. i++, lpDiAW++ )
  1804. {
  1805. // Handle the NULL ptr case
  1806. if ( NULL != lpDiAW->lptszActionName )
  1807. {
  1808. hres = hresFullValidReadStrW_(lpDiAW->lptszActionName, MAX_JOYSTRING, pszProc, argnum);
  1809. }
  1810. }
  1811. }
  1812. return hres;
  1813. }
  1814. /*****************************************************************************
  1815. *
  1816. * @doc INTERNAL
  1817. *
  1818. * @func HRESULT | DiActionFormatWtoW |
  1819. *
  1820. * Copies LPDIACTIONFORMATW to LPDIACTIONFORMATW
  1821. *
  1822. * @parm const LPDIACTIONFORMATW | lpDiAfW |
  1823. *
  1824. * Original.
  1825. *
  1826. * @parm LPDIACTIONFORMATW* | lplpDiAfW |
  1827. *
  1828. * Address of a pointer to a <t DIACTIONFORMATW> that receives the converted
  1829. * ACTIONFORMAT.
  1830. * @returns
  1831. *
  1832. * Standard OLE <t HRESULT>.
  1833. *
  1834. *****************************************************************************/
  1835. HRESULT EXTERNAL DiActionFormatWtoW
  1836. (
  1837. const LPDIACTIONFORMATW lpDiAfW0,
  1838. LPDIACTIONFORMATW* lplpDiAfW
  1839. )
  1840. {
  1841. DWORD cbAlloc;
  1842. PDWORD pdwStrLen0, pdwStrLen;
  1843. LPDIACTIONFORMATW lpDiAfW;
  1844. LPDIACTIONW lpDiAW0;
  1845. LPDIACTIONW lpDiAW;
  1846. DWORD i;
  1847. HRESULT hres;
  1848. EnterProcI(DiActionFormatWtoW, (_ "xx", lpDiAfW0, lplpDiAfW));
  1849. // Internal function, no validation
  1850. *lplpDiAfW = NULL;
  1851. /*
  1852. * PREFIX complains (mb:37926 - items 3 & 4) that we could be requesting
  1853. * a zero byte allocation which would not allocate anything. This is
  1854. * never the case because CDIDev_ActionMap_IsValidMapObject tests that
  1855. * dwNumActions is less than 2^24. Assert in debug for extra safety.
  1856. */
  1857. AssertF( (lpDiAfW0->dwNumActions +1) * cbX(*pdwStrLen0) );
  1858. hres = AllocCbPpv( (lpDiAfW0->dwNumActions +1) * cbX(*pdwStrLen0) , &pdwStrLen0);
  1859. if ( SUCCEEDED(hres) )
  1860. {
  1861. pdwStrLen = pdwStrLen0;
  1862. // Compute the amount of memory required to clone the DIACTIONFORMATA
  1863. cbAlloc =
  1864. /* 1: The Action Format array */
  1865. lpDiAfW0->dwSize
  1866. /* 2: Each of the DIACTION arrays */
  1867. + lpDiAfW0->dwActionSize * lpDiAfW0->dwNumActions;
  1868. // Compute the size for each of the text strings in array of DIACTIONs
  1869. for ( i = 0x0, lpDiAW0 = lpDiAfW0->rgoAction;
  1870. i < lpDiAfW0->dwNumActions ;
  1871. i++, lpDiAW0++ )
  1872. {
  1873. // Handle the NULL ptr case
  1874. if ( !lpDiAW0->lptszActionName )
  1875. {
  1876. *pdwStrLen++ = 0;
  1877. }
  1878. else
  1879. {
  1880. if ( (UINT_PTR)lpDiAW0->lptszActionName > (UINT_PTR)0xFFFF )
  1881. {
  1882. /* 3: Text string in each DIACTION array*/
  1883. // Conversion from A to U, need multiplier
  1884. *pdwStrLen = cbX(lpDiAW0->lptszActionName[0]) * ( lstrlenW(lpDiAW0->lptszActionName) + 1 );
  1885. cbAlloc += *pdwStrLen++;
  1886. }
  1887. else
  1888. {
  1889. // Use resource strings
  1890. WCHAR wsz[MAX_PATH];
  1891. if (lpDiAfW0->hInstString > 0)
  1892. {
  1893. //find out the length of the string
  1894. *pdwStrLen = LoadStringW(lpDiAfW0->hInstString, lpDiAW0->uResIdString, (LPWSTR) &wsz, MAX_PATH);
  1895. }
  1896. else
  1897. {
  1898. *pdwStrLen = 0;
  1899. }
  1900. cbAlloc += *pdwStrLen++;
  1901. }
  1902. }
  1903. }
  1904. if ( SUCCEEDED( hres = AllocCbPpv(cbAlloc, &lpDiAfW) ) )
  1905. {
  1906. DWORD dwLen;
  1907. DWORD cb;
  1908. pdwStrLen = pdwStrLen0;
  1909. // 1: Copy the DIACTIONFORMAT
  1910. *lpDiAfW = *lpDiAfW0;
  1911. cb = lpDiAfW0->dwSize;
  1912. // 2: Block copy the DIACTION array
  1913. lpDiAfW->rgoAction = (LPDIACTIONW)( (char*)lpDiAfW + cb);
  1914. dwLen = lpDiAfW0->dwActionSize * lpDiAfW0->dwNumActions;
  1915. memcpy(lpDiAfW->rgoAction, lpDiAfW0->rgoAction, dwLen);
  1916. cb += dwLen;
  1917. // 3: ActionName
  1918. for ( i = 0x0, lpDiAW0=lpDiAfW0->rgoAction, lpDiAW=lpDiAfW->rgoAction;
  1919. i < lpDiAfW0->dwNumActions ;
  1920. i++, lpDiAW0++, lpDiAW++ )
  1921. {
  1922. if ( (UINT_PTR)lpDiAW0->lptszActionName > (UINT_PTR)0xFFFF )
  1923. {
  1924. WCHAR* wsz = (WCHAR*) ((char*)lpDiAfW+cb);
  1925. lpDiAW->lptszActionName = wsz;
  1926. dwLen = *pdwStrLen++;
  1927. memcpy(wsz, lpDiAW0->lptszActionName, dwLen);
  1928. cb += dwLen ;
  1929. } else
  1930. {
  1931. // Handle resource strings
  1932. // OK for now, as long as UI always uses CloneDiActionFormatW
  1933. WCHAR* wsz = (WCHAR*) ((char*)lpDiAfW+cb);
  1934. dwLen = *pdwStrLen++;
  1935. if ((dwLen != 0) && (LoadStringW(lpDiAfW0->hInstString, lpDiAW0->uResIdString, wsz, dwLen)))
  1936. {
  1937. //If we found a length last time there must be a resource module
  1938. AssertF( lpDiAfW0->hInstString > 0 );
  1939. //Found and loaded the string
  1940. lpDiAW->lptszActionName = wsz;
  1941. }
  1942. else
  1943. {
  1944. //No hinstance or length 0 or didn't load the string
  1945. lpDiAW->lptszActionName = NULL;
  1946. }
  1947. cb += dwLen;
  1948. }
  1949. }
  1950. // If we have not done something goofy, the memory allocates should match
  1951. // the memory we used
  1952. AssertF(cbAlloc == cb );
  1953. *lplpDiAfW = lpDiAfW;
  1954. }
  1955. FreePpv(&pdwStrLen0);
  1956. }
  1957. ExitOleProc();
  1958. return(hres);
  1959. }
  1960. /*****************************************************************************
  1961. *
  1962. * CDIMap_EnumDevicesBySemantics
  1963. *
  1964. * Enum Suitable Devices.
  1965. *
  1966. *****************************************************************************/
  1967. STDMETHODIMP CDIObj_EnumDevicesBySemanticsW(
  1968. PV pDiW,
  1969. LPCWSTR lpszUserName,
  1970. LPDIACTIONFORMATW pDiActionFormat,
  1971. LPDIENUMDEVICESBYSEMANTICSCBW pecW,
  1972. LPVOID pvRef,
  1973. DWORD dwFlags
  1974. )
  1975. {
  1976. HRESULT hres;
  1977. EnterProcR(IDirectInput8::EnumDevicesBySemantics,
  1978. (_ "pppppx", pDiW, lpszUserName, pDiActionFormat, pecW, pvRef, dwFlags));
  1979. if ( SUCCEEDED(hres = hresPvI(pDiW, ThisInterfaceW)) &&
  1980. SUCCEEDED(hres = IsValidMapObjectW(pDiActionFormat D(comma s_szProc comma 2))) &&
  1981. (lpszUserName == NULL || SUCCEEDED(hres = hresFullValidReadStrW(lpszUserName, UNLEN+1, 1))) &&
  1982. SUCCEEDED(hres = hresFullValidPfn(pecW, 3)) &&
  1983. SUCCEEDED(hres = hresFullValidFl(dwFlags, DIEDBSFL_VALID, 5)) &&
  1984. SUCCEEDED(hres = CMap_ValidateActionMapSemantics(pDiActionFormat, DIDBAM_PRESERVE))
  1985. )
  1986. {
  1987. PDDI this = _thisPvNm(pDiW, diW);
  1988. if ( SUCCEEDED(hres = hresValidInstanceVer(g_hinst, this->dwVersion)) )
  1989. {
  1990. DIMAPPER dm;
  1991. LPDIACTIONFORMATW lpDiAfW;
  1992. if ( SUCCEEDED(hres= DiActionFormatWtoW(pDiActionFormat, &lpDiAfW)) )
  1993. {
  1994. dm.lpszUserName = lpszUserName;
  1995. dm.pDiActionFormat = lpDiAfW;
  1996. dm.pecW = pecW;
  1997. dm.pvRef = pvRef;
  1998. dm.dwFlags = dwFlags;
  1999. if( dwFlags == 0 ) {
  2000. dwFlags |= DIEDFL_ATTACHEDONLY;
  2001. }
  2002. dwFlags &= ~DIEDBSFL_AVAILABLEDEVICES;
  2003. dwFlags &= ~DIEDBSFL_THISUSER;
  2004. dwFlags &= ~DIEDBSFL_MULTIMICEKEYBOARDS;
  2005. dwFlags &= ~DIEDBSFL_NONGAMINGDEVICES;
  2006. ZeroX(g_DiDevices);
  2007. g_nCurDev = 0;
  2008. hres = CDIObj_InternalEnumDevicesW( pDiW,
  2009. 0, //enum all tyeps of devices
  2010. (LPVOID)&dm,
  2011. dwFlags //only enum attached devices
  2012. );
  2013. /*
  2014. * For short array sorting (size <= 8), shortsort is better than qsort.
  2015. */
  2016. if ( SUCCEEDED(hres) && g_nCurDev )
  2017. {
  2018. int ndev;
  2019. int nNewDev = -1;
  2020. FILETIME ft = { 0, 0 };
  2021. FILETIME ftMostRecent;
  2022. shortsort( (char *)&g_DiDevices[0], (char *)&g_DiDevices[g_nCurDev-1], sizeof(DIORDERDEV), compare );
  2023. SquirtSqflPtszV(sqflDi | sqflVerbose,
  2024. TEXT("EnumDevicesBySemantics: %d devices enumed"), g_nCurDev );
  2025. for ( ndev=0; ndev<g_nCurDev; ndev++ )
  2026. {
  2027. if( (g_DiDevices[ndev].ftTimeStamp.dwHighDateTime != DIAFTS_NEWDEVICEHIGH) &&
  2028. (g_DiDevices[ndev].ftTimeStamp.dwLowDateTime != DIAFTS_NEWDEVICELOW) &&
  2029. (CompareFileTime(&g_DiDevices[ndev].ftTimeStamp, &ft) == 1) ) // first device is newer
  2030. {
  2031. nNewDev = ndev;
  2032. memcpy( &ft, &g_DiDevices[ndev].ftTimeStamp, sizeof(FILETIME) );
  2033. }
  2034. }
  2035. if( nNewDev != -1 ) {
  2036. g_DiDevices[nNewDev].dwFlags |= DIEDBS_RECENTDEVICE;
  2037. memcpy( &ftMostRecent, &g_DiDevices[nNewDev].ftTimeStamp, sizeof(FILETIME) );
  2038. }
  2039. for ( ndev=0; ndev<g_nCurDev; ndev++ )
  2040. {
  2041. // find RECENT devices and set flag.
  2042. if( (nNewDev != -1) && (ndev != nNewDev) ) {
  2043. if( (ftMostRecent.dwHighDateTime == g_DiDevices[ndev].ftTimeStamp.dwHighDateTime) &&
  2044. (ftMostRecent.dwLowDateTime - g_DiDevices[ndev].ftTimeStamp.dwLowDateTime < 100000000 ) )//10 seconds difference
  2045. {
  2046. g_DiDevices[ndev].dwFlags |= DIEDBS_RECENTDEVICE;
  2047. }
  2048. }
  2049. // find NEW devices and set flag
  2050. if( (g_DiDevices[ndev].ftTimeStamp.dwLowDateTime == DIAFTS_NEWDEVICELOW) &&
  2051. (g_DiDevices[ndev].ftTimeStamp.dwHighDateTime == DIAFTS_NEWDEVICEHIGH) )
  2052. {
  2053. g_DiDevices[ndev].dwFlags |= DIEDBS_NEWDEVICE;
  2054. }
  2055. }
  2056. if( !IsBadCodePtr((PV)pecW) ) {
  2057. for ( ndev=0; ndev<g_nCurDev; ndev++ )
  2058. {
  2059. LPDIDEVICEINSTANCEW pddiW = &g_DiDevices[ndev].ddiW;
  2060. SquirtSqflPtszV(sqflDi | sqflVerbose,
  2061. TEXT("EnumDevicesBySemantics: device %d - %s: %d action(s) mapped"),
  2062. ndev+1, pddiW->tszProductName, GET_MAPPED_ACTION_NUM(g_DiDevices[ndev].dwOrder) );
  2063. if ( pddiW )
  2064. {
  2065. #ifdef DEBUG
  2066. DWORD dbgRef;
  2067. #endif
  2068. DWORD dwDeviceRemaining = g_nCurDev-ndev-1;
  2069. AssertF(g_DiDevices[ndev].pdid8W);
  2070. AssertF(g_DiDevices[ndev].pdid8W->lpVtbl);
  2071. if( g_DiDevices[ndev].pdid8W && g_DiDevices[ndev].pdid8W->lpVtbl )
  2072. {
  2073. BOOL fRc;
  2074. fRc = pecW(pddiW, g_DiDevices[ndev].pdid8W, g_DiDevices[ndev].dwFlags, dwDeviceRemaining, pvRef);
  2075. if( fRc == DIENUM_STOP ) {
  2076. for ( ; ndev<g_nCurDev; ndev++ ) {
  2077. g_DiDevices[ndev].pdid8W->lpVtbl->Release(g_DiDevices[ndev].pdid8W);
  2078. }
  2079. break;
  2080. }
  2081. #ifdef DEBUG
  2082. dbgRef =
  2083. #endif
  2084. g_DiDevices[ndev].pdid8W->lpVtbl->Release(g_DiDevices[ndev].pdid8W);
  2085. }
  2086. }
  2087. }
  2088. }
  2089. }
  2090. FreeDiActionFormatW(&lpDiAfW);
  2091. }
  2092. }
  2093. }
  2094. ExitOleProcR();
  2095. return(hres);
  2096. }
  2097. /*****************************************************************************
  2098. *
  2099. * @doc INTERNAL
  2100. *
  2101. * @func BOOL | CDIObj_EnumDevicesBySemanticsCallbackA |
  2102. *
  2103. * Wrapper function for <mf IDirectInput::EnumDevicesBySemantics>
  2104. * which translates the UNICODE parameters to ANSI.
  2105. *
  2106. * @parm IN LPCDIDECICEINSTANCEW | pdiW |
  2107. *
  2108. * Same as <mf IDirectInput::EnumDevices>.
  2109. *
  2110. * @parm IN OUT PV | pvRef |
  2111. *
  2112. * Pointer to <t struct ENUMDEVICESBYSEMANTICSINFO> which describes
  2113. * the original callback.
  2114. *
  2115. * @returns
  2116. *
  2117. * Returns whatever the original callback returned.
  2118. *
  2119. *****************************************************************************/
  2120. typedef struct ENUMDEVICESBYSEMANTICSINFO
  2121. {
  2122. LPDIENUMDEVICESBYSEMANTICSCBA pecA;
  2123. PV pvRef;
  2124. } ENUMDEVICESBYSEMANTICSINFO, *PENUMDEVICESBYSEMANTICSINFO;
  2125. BOOL CALLBACK
  2126. CDIObj_EnumDevicesBySemanticsCallback(LPCDIDEVICEINSTANCEW pdiW, LPDIRECTINPUTDEVICE8W pdid8W, DWORD dwFlags, DWORD dwDeviceRemaining, PV pvRef)
  2127. {
  2128. PENUMDEVICESBYSEMANTICSINFO pesdi = pvRef;
  2129. BOOL fRc;
  2130. DIDEVICEINSTANCEA diA;
  2131. LPDIRECTINPUTDEVICE8A pdid8A = NULL;
  2132. EnterProc(CDIObj_EnumDevicesBySemanticsCallback,
  2133. (_ "GGxWWp", &pdiW->guidInstance, &pdiW->guidProduct,
  2134. &pdiW->dwDevType,
  2135. pdiW->tszProductName, pdiW->tszInstanceName,
  2136. pvRef));
  2137. diA.dwSize = cbX(diA);
  2138. DeviceInfoWToA(&diA, pdiW);
  2139. Device8WTo8A(&pdid8A, pdid8W);
  2140. fRc = pesdi->pecA(&diA, pdid8A, dwFlags, dwDeviceRemaining, pesdi->pvRef);
  2141. ExitProcX(fRc);
  2142. return(fRc);
  2143. }
  2144. /*****************************************************************************
  2145. *
  2146. * @doc EXTERNAL
  2147. *
  2148. * @method HRESULT | IDirectInput | EnumDevicesBySemantics |
  2149. *
  2150. * Enumerates devices suitable for the application specified
  2151. * <t DIACTIONFORMAT>.
  2152. *
  2153. * @cwrap LPDIRECTINPUT | lpDirectInput
  2154. *
  2155. * ISSUE-2001/03/29-timgill Need to fix auto docs
  2156. * @parm LPTSTR | lptszActionMap |
  2157. *
  2158. * Friendly name for the application.
  2159. *
  2160. * @parm REFGUID | rguid |
  2161. *
  2162. * Unique GUID to identify the application.
  2163. *
  2164. * @returns
  2165. *
  2166. * Standard OLE <t HRESULT>.
  2167. *
  2168. *****************************************************************************/
  2169. STDMETHODIMP CDIObj_EnumDevicesBySemanticsA
  2170. (
  2171. PV pDiA,
  2172. LPCSTR lpszUserName,
  2173. LPDIACTIONFORMATA pDiActionFormat,
  2174. LPDIENUMDEVICESBYSEMANTICSCBA pecA,
  2175. LPVOID pvRef,
  2176. DWORD dwFlags
  2177. )
  2178. {
  2179. HRESULT hres;
  2180. EnterProcR(IDirectInput8::EnumDevicesBySemantics,
  2181. (_ "pppppx", pDiA, lpszUserName, pDiActionFormat, pecA, pvRef, dwFlags));
  2182. /*
  2183. * EnumDevicesBySemanticsW will validate the rest.
  2184. */
  2185. if ( SUCCEEDED(hres = hresPvI(pDiA, ThisInterfaceA)) &&
  2186. SUCCEEDED(hres = IsValidMapObjectA(pDiActionFormat D(comma s_szProc comma 2))) &&
  2187. (lpszUserName == NULL || SUCCEEDED(hres = hresFullValidReadStrA(lpszUserName, UNLEN+1, 1))) &&
  2188. SUCCEEDED(hres = hresFullValidPfn(pecA, 3)) &&
  2189. SUCCEEDED(hres = hresFullValidFl(dwFlags, DIEDBSFL_VALID, 5))
  2190. )
  2191. {
  2192. PDDI this = _thisPvNm(pDiA, diA);
  2193. ENUMDEVICESBYSEMANTICSINFO esdi = { pecA, pvRef};
  2194. WCHAR wszUserName[MAX_PATH];
  2195. DIACTIONFORMATW diafW;
  2196. LPDIACTIONW rgoActionW;
  2197. wszUserName[0] = L'\0';
  2198. if( lpszUserName ) {
  2199. AToU(wszUserName, MAX_PATH, lpszUserName);
  2200. }
  2201. /*
  2202. * Assert that the structure can be copied as:
  2203. * a) dwSize
  2204. * b) everything else
  2205. * c) the app name
  2206. */
  2207. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, dwSize ) == 0 );
  2208. CAssertF( FIELD_OFFSET( DIACTIONFORMATA, dwSize ) == 0 );
  2209. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, dwSize ) + cbX( ((LPDIACTIONFORMATW)0)->dwSize )
  2210. == FIELD_OFFSET( DIACTIONFORMATW, dwActionSize ) );
  2211. #if defined(_WIN64)
  2212. CAssertF( ( ( cbX( DIACTIONFORMATW ) - cbX( ((LPDIACTIONFORMATW)0)->tszActionMap ) )
  2213. - ( cbX( DIACTIONFORMATA ) - cbX( ((LPDIACTIONFORMATA)0)->tszActionMap ) )
  2214. < MAX_NATURAL_ALIGNMENT ) );
  2215. #else
  2216. CAssertF( ( cbX( DIACTIONFORMATW ) - cbX( ((LPDIACTIONFORMATW)0)->tszActionMap ) )
  2217. == ( cbX( DIACTIONFORMATA ) - cbX( ((LPDIACTIONFORMATA)0)->tszActionMap ) ) );
  2218. #endif
  2219. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, tszActionMap )
  2220. == FIELD_OFFSET( DIACTIONFORMATA, tszActionMap ) );
  2221. CAssertF( cA( ((LPDIACTIONFORMATW)0)->tszActionMap ) == cA( ((LPDIACTIONFORMATA)0)->tszActionMap ) );
  2222. //Init diafW fields
  2223. diafW.dwSize = cbX(DIACTIONFORMATW);
  2224. memcpy( &diafW.dwActionSize, &pDiActionFormat->dwActionSize,
  2225. FIELD_OFFSET( DIACTIONFORMATW, tszActionMap ) - FIELD_OFFSET( DIACTIONFORMATW, dwActionSize ) );
  2226. AToU(diafW.tszActionMap, cbX(pDiActionFormat->tszActionMap), pDiActionFormat->tszActionMap);
  2227. if ( SUCCEEDED( hres = AllocCbPpv( cbCxX(pDiActionFormat->dwNumActions, DIACTIONW), &rgoActionW) ) )
  2228. {
  2229. memcpy( rgoActionW, pDiActionFormat->rgoAction, sizeof(DIACTIONA) * pDiActionFormat->dwNumActions );
  2230. diafW.rgoAction = rgoActionW;
  2231. hres = CDIObj_EnumDevicesBySemanticsW(&this->diW, wszUserName,
  2232. &diafW,
  2233. CDIObj_EnumDevicesBySemanticsCallback,
  2234. &esdi, dwFlags);
  2235. FreePpv(&rgoActionW);
  2236. }
  2237. }
  2238. ExitOleProcR();
  2239. return(hres);
  2240. }
  2241. /*****************************************************************************
  2242. *
  2243. * @doc INTERNAL
  2244. *
  2245. * @func HRESULT | hresValidSurface |
  2246. *
  2247. * Tests the interface pointer for a valid surface of sufficient
  2248. * dimensions to display the UI and with a supported pixel format.
  2249. *
  2250. * @parm IUnknown* | lpUnkDDSTarget |
  2251. *
  2252. * Pointer to an interface which must be validated as a COM object
  2253. * before calling this function.
  2254. *
  2255. * @returns
  2256. *
  2257. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2258. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  2259. * <p lpUnkDDSTarget> parameter is not valid.
  2260. * A DirectDraw or D3D error if one was returned.
  2261. * or a Standard OLE <t HRESULT>.
  2262. *
  2263. *****************************************************************************/
  2264. HRESULT INLINE hresValidSurface
  2265. (
  2266. IUnknown* lpUnkDDSTarget
  2267. )
  2268. {
  2269. HRESULT hres;
  2270. IUnknown* lpSurface = NULL;
  2271. /*
  2272. * Short on time, so take short-cuts in validation debug error messages
  2273. */
  2274. #ifdef XDEBUG
  2275. CHAR s_szProc[] = "IDirectInput8::ConfigureDevices";
  2276. #endif
  2277. #define ArgIS 2
  2278. if( SUCCEEDED( hres = lpUnkDDSTarget->lpVtbl->QueryInterface(
  2279. lpUnkDDSTarget, &IID_IDirect3DSurface8, (LPVOID*)&lpSurface ) ) )
  2280. {
  2281. D3DSURFACE_DESC SurfDesc;
  2282. hres = ((IDirect3DSurface8*)lpSurface)->lpVtbl->GetDesc( ((IDirect3DSurface8*)lpSurface), &SurfDesc );
  2283. if( FAILED( hres ) )
  2284. {
  2285. RPF( "%s: Arg %d: Unable to GetDesc on surface, error 0x%08x", s_szProc, ArgIS, hres );
  2286. /*
  2287. * D3D returns real HRESULTs which can be returned to the caller
  2288. */
  2289. }
  2290. else
  2291. {
  2292. if( ( SurfDesc.Width < 640 ) || ( SurfDesc.Height < 480 ) )
  2293. {
  2294. RPF( "%s: Arg %d: cannot use %d by %d surface",
  2295. s_szProc, ArgIS, SurfDesc.Width, SurfDesc.Height );
  2296. hres = E_INVALIDARG;
  2297. }
  2298. else
  2299. {
  2300. switch( SurfDesc.Format )
  2301. {
  2302. case D3DFMT_R8G8B8:
  2303. case D3DFMT_A8R8G8B8:
  2304. case D3DFMT_X8R8G8B8:
  2305. case D3DFMT_R5G6B5:
  2306. case D3DFMT_X1R5G5B5:
  2307. case D3DFMT_A1R5G5B5:
  2308. SquirtSqflPtszV(sqfl | sqflVerbose,
  2309. TEXT("ConfigureDevices: validated %d by %d format %d surface"),
  2310. SurfDesc.Width, SurfDesc.Height, SurfDesc.Format );
  2311. break;
  2312. default:
  2313. RPF( "%s: Arg %d: cannot use surface format %d ", s_szProc, ArgIS, SurfDesc.Format );
  2314. hres = E_INVALIDARG;
  2315. break;
  2316. }
  2317. }
  2318. }
  2319. }
  2320. else
  2321. {
  2322. DDSURFACEDESC2 SurfDesc;
  2323. SurfDesc.dwSize = cbX( SurfDesc );
  2324. if( SUCCEEDED(hres = lpUnkDDSTarget->lpVtbl->QueryInterface(
  2325. lpUnkDDSTarget, &IID_IDirectDrawSurface7, (LPVOID*) &lpSurface)) )
  2326. {
  2327. hres = ((IDirectDrawSurface7*)lpSurface)->lpVtbl->GetSurfaceDesc( ((IDirectDrawSurface7*)lpSurface), &SurfDesc );
  2328. }
  2329. else if( SUCCEEDED(hres = lpUnkDDSTarget->lpVtbl->QueryInterface(
  2330. lpUnkDDSTarget, &IID_IDirectDrawSurface4, (LPVOID*) &lpSurface )) )
  2331. {
  2332. hres = ((IDirectDrawSurface4*)lpSurface)->lpVtbl->GetSurfaceDesc( ((IDirectDrawSurface4*)lpSurface), &SurfDesc );
  2333. }
  2334. if( FAILED( hres ) )
  2335. {
  2336. if( lpSurface )
  2337. {
  2338. RPF( "%s: Arg %d: failed GetSurfaceDesc, error 0x%08x", s_szProc, ArgIS, hres );
  2339. }
  2340. else
  2341. {
  2342. RPF( "%s: Arg %d: failed QI for supported surface interfaces from %p, error 0x%08x",
  2343. s_szProc, ArgIS, lpSurface, hres );
  2344. }
  2345. /*
  2346. * DDraw returns real HRESULTs which can be returned to the caller
  2347. */
  2348. }
  2349. else if( ( SurfDesc.dwWidth < 640 ) || ( SurfDesc.dwHeight < 480 ) )
  2350. {
  2351. RPF( "%s: Arg %d: cannot use %d by %d surface",
  2352. s_szProc, ArgIS, SurfDesc.dwWidth, SurfDesc.dwHeight );
  2353. hres = E_INVALIDARG;
  2354. }
  2355. else
  2356. {
  2357. /*
  2358. * Check for the eqivalent of the DX8 surfaces:
  2359. * A8R8G8B8, X8R8G8B8, R8G8B8, A1R5G5B5, X1R5G5B5, R5G6B5
  2360. */
  2361. if( SurfDesc.ddpfPixelFormat.dwFlags & DDPF_RGB )
  2362. {
  2363. if( SurfDesc.ddpfPixelFormat.dwRGBBitCount > 16 )
  2364. {
  2365. AssertF( ( SurfDesc.ddpfPixelFormat.dwRGBBitCount == 32 )
  2366. ||( SurfDesc.ddpfPixelFormat.dwRGBBitCount == 24 ) );
  2367. /*
  2368. * All of these must be R8 G8 B8
  2369. */
  2370. if( ( SurfDesc.ddpfPixelFormat.dwRBitMask == 0x00FF0000 )
  2371. && ( SurfDesc.ddpfPixelFormat.dwGBitMask == 0x0000FF00 )
  2372. && ( SurfDesc.ddpfPixelFormat.dwBBitMask == 0x000000FF ) )
  2373. {
  2374. SquirtSqflPtszV(sqfl | sqflVerbose,
  2375. TEXT("ConfigureDevices: validated %d by %d format R8G8B8 %d bit surface"),
  2376. SurfDesc.dwWidth, SurfDesc.dwHeight, SurfDesc.ddpfPixelFormat.dwRGBBitCount );
  2377. }
  2378. else
  2379. {
  2380. RPF( "%s: Arg %d: cannot use surface pixel format", s_szProc, ArgIS );
  2381. hres = E_INVALIDARG;
  2382. }
  2383. }
  2384. else
  2385. {
  2386. if( SurfDesc.ddpfPixelFormat.dwRGBBitCount == 16 )
  2387. {
  2388. /*
  2389. * Allow R5 G5 B5 and R5 G6 B5
  2390. */
  2391. if( ( SurfDesc.ddpfPixelFormat.dwBBitMask == 0x0000001F )
  2392. && ( ( SurfDesc.ddpfPixelFormat.dwGBitMask == 0x000003E0 )
  2393. && ( SurfDesc.ddpfPixelFormat.dwRBitMask == 0x00007C00 ) )
  2394. || ( ( SurfDesc.ddpfPixelFormat.dwGBitMask == 0x000007E0 )
  2395. && ( SurfDesc.ddpfPixelFormat.dwRBitMask == 0x0000F800 ) ) )
  2396. {
  2397. SquirtSqflPtszV(sqfl | sqflVerbose,
  2398. TEXT("ConfigureDevices: validated %d by %d format 16 bit surface"),
  2399. SurfDesc.dwWidth, SurfDesc.dwHeight );
  2400. }
  2401. else
  2402. {
  2403. RPF( "%s: Arg %d: cannot use 16 bit surface pixel format", s_szProc, ArgIS );
  2404. hres = E_INVALIDARG;
  2405. }
  2406. }
  2407. else
  2408. {
  2409. RPF( "%s: Arg %d: cannot use %d bit surface pixel format",
  2410. s_szProc, ArgIS, SurfDesc.ddpfPixelFormat.dwRGBBitCount );
  2411. hres = E_INVALIDARG;
  2412. }
  2413. }
  2414. }
  2415. else
  2416. {
  2417. RPF( "%s: Arg %d: cannot use non RGB surface, Surface.dwFlags = 0x%08x",
  2418. s_szProc, ArgIS, SurfDesc.ddpfPixelFormat.dwFlags );
  2419. hres = E_INVALIDARG;
  2420. }
  2421. }
  2422. }
  2423. if( lpSurface != NULL )
  2424. {
  2425. lpSurface->lpVtbl->Release( lpSurface );
  2426. }
  2427. return hres;
  2428. #undef ArgIS
  2429. }
  2430. /*****************************************************************************
  2431. *
  2432. * @doc EXTERNAL
  2433. *
  2434. * @method HRESULT | IDirectInput | ConfigureDevices |
  2435. *
  2436. * Configures the devices by attaching mappings provided in
  2437. * <t DIACTIONFORMAT> to appropriate device controls.
  2438. *
  2439. * @cwrap LPDIRECTINPUT | lpDirectInput
  2440. *
  2441. * @parm LPCTSTR | lpctszUserName |
  2442. *
  2443. * User Name.
  2444. *
  2445. * @parm LPDIACTIONFORMAT | lpDiActionFormat |
  2446. *
  2447. * Pointer to the <t DIACTIONFORMAT> structure containing the action map.
  2448. *
  2449. *
  2450. * @returns
  2451. *
  2452. * Standard OLE <t HRESULT>.
  2453. *
  2454. *****************************************************************************/
  2455. STDMETHODIMP CDIObj_ConfigureDevicesCore
  2456. (
  2457. PV pDiW,
  2458. LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
  2459. LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
  2460. DWORD dwFlags,
  2461. LPVOID pvRefData
  2462. )
  2463. {
  2464. //the real ConfigureDevices()
  2465. //some stuff should have been validated already
  2466. HRESULT hres = S_OK;
  2467. EnterProcI(IDirectInput8::ConfigureDevicesCore,
  2468. (_ "pppup", pDiW, lpdiCallback,lpdiCDParams, dwFlags, pvRefData));
  2469. if( SUCCEEDED( hres = hresFullValidFl( dwFlags, DICD_VALID, 3 ) )
  2470. && SUCCEEDED( hres = hresFullValidReadPvCb( &(lpdiCDParams->dics), sizeof(DICOLORSET), 2 ) ) )
  2471. {
  2472. /*
  2473. * lpUnkDDSTarget and lpdiCallback are "coupled", because the only
  2474. * function of the callback is to display the updates to the surface
  2475. * either they are both NULL, or they are both non-NULL and valid.
  2476. * otherwise, it is an error.
  2477. */
  2478. if( lpdiCallback == NULL )
  2479. {
  2480. if( lpdiCDParams->lpUnkDDSTarget == NULL )
  2481. {
  2482. hres = S_OK;
  2483. }
  2484. else
  2485. {
  2486. RPF( "%s: Arg %d or %d: neither or both of callback and surface must be NULL",
  2487. s_szProc, 1, 2 );
  2488. hres = E_INVALIDARG;
  2489. }
  2490. }
  2491. else if( lpdiCDParams->lpUnkDDSTarget == NULL )
  2492. {
  2493. RPF( "%s: Arg %d or %d: neither or both of surface and callback must be NULL",
  2494. s_szProc, 2, 1 );
  2495. hres = E_INVALIDARG;
  2496. }
  2497. else if( SUCCEEDED( hres = hresFullValidPfn( lpdiCallback, 1 ) )
  2498. && SUCCEEDED( hres = hresFullValidPitf( lpdiCDParams->lpUnkDDSTarget, 2 ) ) )
  2499. {
  2500. hres = hresValidSurface( lpdiCDParams->lpUnkDDSTarget );
  2501. }
  2502. if( SUCCEEDED( hres ) )
  2503. {
  2504. //load the framework
  2505. HINSTANCE hinst;
  2506. IDirectInputActionFramework* pDIAcFrame = NULL;
  2507. TCHAR tszName[ctchNameGuid];
  2508. TCHAR tszClsid[ctchGuid];
  2509. NameFromGUID(tszName, &CLSID_CDirectInputActionFramework);
  2510. memcpy(tszClsid, &tszName[ctchNamePrefix], cbX(tszClsid) );
  2511. hres = DICoCreateInstance(tszClsid, NULL, &IID_IDIActionFramework, (LPVOID*) & pDIAcFrame, &hinst);
  2512. if( SUCCEEDED(hres) )
  2513. {
  2514. //for getting default user name, if needed
  2515. LPWSTR pwszUserName = NULL;
  2516. //can't pass NULL user name down to the framework -- need to get the default user name
  2517. if( lpdiCDParams->lptszUserNames == NULL )
  2518. {
  2519. hres = GetWideUserName(NULL, NULL, &pwszUserName);
  2520. lpdiCDParams->lptszUserNames = pwszUserName;
  2521. lpdiCDParams->dwcUsers = 1;
  2522. }
  2523. if( SUCCEEDED(hres) )
  2524. {
  2525. //call the framework
  2526. hres = pDIAcFrame->lpVtbl->ConfigureDevices
  2527. (
  2528. pDIAcFrame,
  2529. lpdiCallback,
  2530. lpdiCDParams,
  2531. dwFlags,
  2532. pvRefData);
  2533. if( SUCCEEDED(hres) )
  2534. {
  2535. SquirtSqflPtszV( sqfl | sqflVerbose,
  2536. TEXT("Default Remapping UI returned 0x%08x"), hres );
  2537. }
  2538. else
  2539. {
  2540. SquirtSqflPtszV( sqfl | sqflError,
  2541. TEXT("Default Remapping UI returned error 0x%08x"), hres );
  2542. }
  2543. //release pwsUserName, if we have used it
  2544. FreePpv(&pwszUserName);
  2545. }
  2546. FreeLibrary( hinst );
  2547. }
  2548. }
  2549. }
  2550. ExitOleProc();
  2551. return hres;
  2552. }
  2553. STDMETHODIMP CDIObj_ConfigureDevicesW
  2554. (
  2555. PV pDiW,
  2556. LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
  2557. LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
  2558. DWORD dwFlags,
  2559. LPVOID pvRefData
  2560. )
  2561. {
  2562. HRESULT hres = S_OK;
  2563. EnterProcR(IDirectInput8::ConfigureDevices,
  2564. (_ "pppxp", pDiW, lpdiCallback,lpdiCDParams, dwFlags, pvRefData));
  2565. //validate all the ptrs
  2566. if ( (SUCCEEDED(hres = hresPvI(pDiW, ThisInterfaceW)) &&
  2567. (SUCCEEDED(hres = hresFullValidReadPvCb(lpdiCDParams, sizeof(DICONFIGUREDEVICESPARAMSW), 2))) &&
  2568. ((lpdiCDParams->lptszUserNames == NULL) || (SUCCEEDED(hres = hresFullValidReadStrW((LPWSTR)(lpdiCDParams->lptszUserNames), MAX_JOYSTRING * (lpdiCDParams->dwcUsers), 2)))) &&
  2569. (SUCCEEDED(hres = hresFullValidReadPvCb(lpdiCDParams->lprgFormats, lpdiCDParams->dwcFormats*sizeof(DIACTIONFORMATW), 2)))))
  2570. {
  2571. if( lpdiCDParams->dwSize != cbX(DICONFIGUREDEVICESPARAMSW) )
  2572. {
  2573. RPF("IDirectInput::%s: Invalid DICONFIGUREDEVICESPARAMSW.dwSize 0x%08x",
  2574. lpdiCDParams->dwSize );
  2575. hres = E_INVALIDARG;
  2576. }
  2577. if (SUCCEEDED(hres))
  2578. {
  2579. PDDI this = _thisPvNm(pDiW, diW);
  2580. //params structure
  2581. DICONFIGUREDEVICESPARAMSW diconfparamsW;
  2582. //to translate each DIACTIONFORMAT
  2583. LPDIACTIONFORMATW* lpDiAfW = NULL;
  2584. //the cloning array of DIACTIONFORMATs
  2585. LPDIACTIONFORMATW* lpDAFW = NULL;
  2586. //to traverse the old array
  2587. LPDIACTIONFORMATW lpDIFormat;
  2588. //to traverse the new array
  2589. LPDIACTIONFORMATW lpDIF;
  2590. //user names
  2591. LPWSTR lpUserNames = NULL;
  2592. //DIACTIONFORMATs cloned
  2593. DWORD clonedF = 0;
  2594. //length of user names
  2595. DWORD strLen = 0;
  2596. //zero out
  2597. ZeroMemory(&diconfparamsW, sizeof(DICONFIGUREDEVICESPARAMSW));
  2598. //set the size
  2599. diconfparamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW);
  2600. //1. Validate and translate each LPDIACTIONFORMAT in the array
  2601. lpDIFormat = (lpdiCDParams->lprgFormats);
  2602. //allocate the new array
  2603. hres = AllocCbPpv(lpdiCDParams->dwcFormats * sizeof(DIACTIONFORMATW), &diconfparamsW.lprgFormats);
  2604. if (FAILED(hres))
  2605. {
  2606. goto cleanup;
  2607. }
  2608. lpDIF = diconfparamsW.lprgFormats;
  2609. //allocate the cloning array
  2610. hres = AllocCbPpv(lpdiCDParams->dwcFormats * sizeof(DIACTIONFORMATW), &lpDAFW);
  2611. if (FAILED(hres))
  2612. {
  2613. goto cleanup;
  2614. }
  2615. lpDiAfW = lpDAFW;
  2616. //clone
  2617. for (clonedF = 0; clonedF < lpdiCDParams->dwcFormats; clonedF ++)
  2618. {
  2619. //validate
  2620. hres = IsValidMapObjectW(lpDIFormat D(comma s_szProc comma 2));
  2621. if (FAILED(hres))
  2622. {
  2623. goto cleanup;
  2624. }
  2625. //translate
  2626. hres = DiActionFormatWtoW(lpDIFormat, lpDiAfW);
  2627. if (FAILED(hres))
  2628. {
  2629. goto cleanup;
  2630. }
  2631. //save
  2632. *lpDIF = *(*lpDiAfW);
  2633. //move on
  2634. lpDIFormat++;
  2635. lpDiAfW++;
  2636. lpDIF++;
  2637. }
  2638. //if everything went fine, should have cloned all
  2639. AssertF(clonedF == lpdiCDParams->dwcFormats);
  2640. //2. Copy the user names
  2641. if (lpdiCDParams->lptszUserNames != NULL)
  2642. {
  2643. DWORD countN;
  2644. WCHAR* lpName = lpdiCDParams->lptszUserNames;
  2645. for (countN = 0; countN < lpdiCDParams->dwcUsers; countN ++)
  2646. {
  2647. DWORD Len;
  2648. hres = hresFullValidReadStrW(lpName, MAX_JOYSTRING, 2);
  2649. if (FAILED(hres))
  2650. {
  2651. goto cleanup;
  2652. }
  2653. Len = lstrlenW(lpName);
  2654. //if length is 0 -- and we haven't reached the correct user count yet -
  2655. //then it is an error
  2656. if (Len == 0)
  2657. {
  2658. hres = DIERR_INVALIDPARAM;
  2659. goto cleanup;
  2660. }
  2661. //move on to the next user name
  2662. strLen += Len + 1;
  2663. lpName += Len + 1;
  2664. }
  2665. //if everything went fine, should have traversed all the user names
  2666. AssertF(countN == lpdiCDParams->dwcUsers);
  2667. //allocate
  2668. hres = AllocCbPpv( (strLen + 1) * 2, &lpUserNames );
  2669. if (FAILED(hres))
  2670. {
  2671. goto cleanup;
  2672. }
  2673. //copy
  2674. memcpy(lpUserNames, lpdiCDParams->lptszUserNames, strLen*2);
  2675. diconfparamsW.lptszUserNames = lpUserNames;
  2676. }
  2677. //3. Populate the rest of the structure
  2678. diconfparamsW.dwcUsers = lpdiCDParams->dwcUsers;
  2679. diconfparamsW.dwcFormats = clonedF;
  2680. diconfparamsW.hwnd = lpdiCDParams->hwnd;
  2681. diconfparamsW.dics = lpdiCDParams->dics;
  2682. diconfparamsW.lpUnkDDSTarget = lpdiCDParams->lpUnkDDSTarget;
  2683. //4. Call the framework
  2684. hres = CDIObj_ConfigureDevicesCore
  2685. (
  2686. &this->diW,
  2687. lpdiCallback,
  2688. &diconfparamsW,
  2689. dwFlags,
  2690. pvRefData);
  2691. cleanup:;
  2692. //free the space for the new array
  2693. FreePpv(&diconfparamsW.lprgFormats);
  2694. //free as many DIACTIONFORMATs as were created
  2695. if (lpDAFW)
  2696. {
  2697. lpDiAfW = lpDAFW;
  2698. for (clonedF; clonedF > 0; clonedF--)
  2699. {
  2700. FreeDiActionFormatW(lpDiAfW);
  2701. lpDiAfW++;
  2702. }
  2703. //delete the entire block
  2704. FreePpv(&lpDAFW);
  2705. }
  2706. //delete the user names
  2707. FreePpv(&lpUserNames);
  2708. }
  2709. }
  2710. ExitOleProc();
  2711. return(hres);
  2712. }
  2713. /*****************************************************************************
  2714. *
  2715. * @doc INTERNAL
  2716. *
  2717. * @func HRESULT | DiActionFormatAtoW |
  2718. *
  2719. * Copies LPDIACTIONFORMATA to LPDIACTIONFORMATW
  2720. *
  2721. * @parm const LPDIACTIONFORMATA | lpDiAfA |
  2722. *
  2723. * Original.
  2724. *
  2725. * @parm LPDIACTIONFORMATW* | lplpDiAfW |
  2726. *
  2727. * Address of a pointer to a <t DIACTIONFORMATW> that receives the converted
  2728. * ACTIONFORMAT.
  2729. * @returns
  2730. *
  2731. * Standard OLE <t HRESULT>.
  2732. *
  2733. *****************************************************************************/
  2734. HRESULT EXTERNAL DiActionFormatAtoW
  2735. (
  2736. const LPDIACTIONFORMATA lpDiAfA,
  2737. LPDIACTIONFORMATW* lplpDiAfW
  2738. )
  2739. {
  2740. DWORD cbAlloc;
  2741. PDWORD pdwStrLen, pdwStrLen0;
  2742. LPDIACTIONFORMATW lpDiAfW;
  2743. LPDIACTIONA lpDiAA;
  2744. LPDIACTIONW lpDiAW;
  2745. DWORD i;
  2746. HRESULT hres;
  2747. EnterProcI(DiActionFormatAtoW, (_ "xx", lpDiAfA, lplpDiAfW));
  2748. // Internal function, no validation
  2749. *lplpDiAfW = NULL;
  2750. /*
  2751. * PREFIX complains (mb:37926 - item 2) that we could be requesting a
  2752. * zero byte allocation which would not allocate anything. This is
  2753. * never the case because CDIDev_ActionMap_IsValidMapObject tests that
  2754. * dwNumActions is less than 2^24. Assert in debug for extra safety.
  2755. */
  2756. AssertF( (lpDiAfA->dwNumActions +1)*cbX(*pdwStrLen0) );
  2757. hres = AllocCbPpv( (lpDiAfA->dwNumActions +1)*cbX(*pdwStrLen0) , &pdwStrLen0);
  2758. if ( SUCCEEDED(hres) )
  2759. {
  2760. // Compute the amount of memory required to clone the DIACTIONFORMATA
  2761. cbAlloc =
  2762. /* 1: The wide form of the Action Format array */
  2763. cbX(DIACTIONFORMATW)
  2764. /* 2: Each of the DIACTION arrays */
  2765. + lpDiAfA->dwActionSize * lpDiAfA->dwNumActions;
  2766. pdwStrLen = pdwStrLen0;
  2767. // Compute the size for each of the text strings in array of DIACTIONs
  2768. for ( i = 0x0, lpDiAA = lpDiAfA->rgoAction;
  2769. i < lpDiAfA->dwNumActions ;
  2770. i++, lpDiAA++ )
  2771. {
  2772. // Handle the NULL ptr case
  2773. if ( NULL != lpDiAA->lptszActionName )
  2774. {
  2775. /* 3: Text string in each DIACTION array*/
  2776. // Conversion from A to U, need multiplier
  2777. // ISSUE-2001/03/29-timgill (MarcAnd), A to U conversions are not always 1 to 1.
  2778. *pdwStrLen = lstrlenA(lpDiAA->lptszActionName) + 1;
  2779. cbAlloc += cbX(lpDiAW->lptszActionName[0]) * ( *pdwStrLen++ );
  2780. }
  2781. }
  2782. if ( SUCCEEDED( hres = AllocCbPpv(cbAlloc, &lpDiAfW) ) )
  2783. {
  2784. DWORD dwLen;
  2785. DWORD cb;
  2786. pdwStrLen = pdwStrLen0;
  2787. // 1: Copy the DIACTIONFORMAT
  2788. /*
  2789. * Assert that the structure can be copied as:
  2790. * a) dwSize
  2791. * b) everything else
  2792. * c) the app name
  2793. */
  2794. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, dwSize ) == 0 );
  2795. CAssertF( FIELD_OFFSET( DIACTIONFORMATA, dwSize ) == 0 );
  2796. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, dwSize ) + cbX( ((LPDIACTIONFORMATW)0)->dwSize )
  2797. == FIELD_OFFSET( DIACTIONFORMATW, dwActionSize ) );
  2798. #if defined(_WIN64)
  2799. CAssertF( ( ( cbX( DIACTIONFORMATW ) - cbX( ((LPDIACTIONFORMATW)0)->tszActionMap ) )
  2800. - ( cbX( DIACTIONFORMATA ) - cbX( ((LPDIACTIONFORMATA)0)->tszActionMap ) )
  2801. < MAX_NATURAL_ALIGNMENT ) );
  2802. #else
  2803. CAssertF( ( cbX( DIACTIONFORMATW ) - cbX( ((LPDIACTIONFORMATW)0)->tszActionMap ) )
  2804. == ( cbX( DIACTIONFORMATA ) - cbX( ((LPDIACTIONFORMATA)0)->tszActionMap ) ) );
  2805. #endif
  2806. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, tszActionMap )
  2807. == FIELD_OFFSET( DIACTIONFORMATA, tszActionMap ) );
  2808. CAssertF( cA( ((LPDIACTIONFORMATW)0)->tszActionMap ) == cA( ((LPDIACTIONFORMATA)0)->tszActionMap ) );
  2809. // Init counts and lpDiAfW fields
  2810. dwLen = lpDiAfA->dwActionSize * lpDiAfA->dwNumActions;
  2811. cb = lpDiAfW->dwSize = cbX(DIACTIONFORMATW);
  2812. memcpy( &lpDiAfW->dwActionSize, &lpDiAfA->dwActionSize,
  2813. FIELD_OFFSET( DIACTIONFORMATW, tszActionMap ) - FIELD_OFFSET( DIACTIONFORMATW, dwActionSize ) );
  2814. AToU(lpDiAfW->tszActionMap, cbX(lpDiAfA->tszActionMap), lpDiAfA->tszActionMap);
  2815. // 2: Block copy the DIACTION array
  2816. CAssertF(cbX(*lpDiAfW->rgoAction) == cbX(*lpDiAfA->rgoAction) )
  2817. lpDiAfW->rgoAction = (LPDIACTIONW)( (char*)lpDiAfW + cb);
  2818. dwLen = lpDiAfA->dwActionSize * lpDiAfA->dwNumActions;
  2819. memcpy(lpDiAfW->rgoAction, lpDiAfA->rgoAction, dwLen);
  2820. cb += dwLen;
  2821. // 3: ActionName
  2822. // Convert each of the strings in the ACTION array from A to W
  2823. for ( i = 0x0, lpDiAA=lpDiAfA->rgoAction, lpDiAW=lpDiAfW->rgoAction;
  2824. i < lpDiAfW->dwNumActions ;
  2825. i++, lpDiAA++, lpDiAW++ )
  2826. {
  2827. if ( lpDiAA->lptszActionName != NULL )
  2828. {
  2829. WCHAR* wsz = (WCHAR*) ((char*)lpDiAfW+cb);
  2830. lpDiAW->lptszActionName = wsz;
  2831. dwLen = (*pdwStrLen++);
  2832. AToU( wsz, dwLen, lpDiAA->lptszActionName);
  2833. cb += dwLen * cbX(lpDiAW->lptszActionName[0]) ;
  2834. } else
  2835. {
  2836. // Resource strings are handled in DiActionFormatWtoW
  2837. // OK for now, as long as UI always uses CloneDiActionFormatW
  2838. lpDiAW->lptszActionName = NULL;
  2839. }
  2840. }
  2841. // If we have not done something goofy, the memory allocates should match
  2842. // the memory we used
  2843. AssertF(cbAlloc == cb );
  2844. *lplpDiAfW = lpDiAfW;
  2845. }
  2846. FreePpv(&pdwStrLen0);
  2847. }
  2848. ExitOleProc();
  2849. return(hres);
  2850. }
  2851. STDMETHODIMP CDIObj_ConfigureDevicesA
  2852. (
  2853. PV pDiA,
  2854. LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
  2855. LPDICONFIGUREDEVICESPARAMSA lpdiCDParams,
  2856. DWORD dwFlags,
  2857. LPVOID pvRefData
  2858. )
  2859. {
  2860. HRESULT hres = S_OK;
  2861. EnterProcR(IDirectInput8::ConfigureDevices,
  2862. (_ "pppxp", pDiA, lpdiCallback, lpdiCDParams, dwFlags, pvRefData));
  2863. /*
  2864. * ConfigureDevicesCore will validate the rest.
  2865. */
  2866. if ( (SUCCEEDED(hres = hresPvI(pDiA, ThisInterfaceA)) &&
  2867. (SUCCEEDED(hres = hresFullValidReadPvCb(lpdiCDParams, sizeof(DICONFIGUREDEVICESPARAMSA), 2)) &&
  2868. ((lpdiCDParams->lptszUserNames == NULL) || (SUCCEEDED(hres = hresFullValidReadStrA((LPSTR)(lpdiCDParams->lptszUserNames), MAX_JOYSTRING * (lpdiCDParams->dwcUsers), 2)))) &&
  2869. (SUCCEEDED(hres = hresFullValidReadPvCb(lpdiCDParams->lprgFormats, lpdiCDParams->dwcFormats*sizeof(DIACTIONFORMATA), 2))))))
  2870. {
  2871. if( lpdiCDParams->dwSize != cbX(DICONFIGUREDEVICESPARAMSA) )
  2872. {
  2873. RPF("IDirectInput::%s: Invalid DICONFIGUREDEVICESPARAMSA.dwSize 0x%08x",
  2874. lpdiCDParams->dwSize );
  2875. hres = E_INVALIDARG;
  2876. }
  2877. if (SUCCEEDED(hres))
  2878. {
  2879. PDDI this = _thisPvNm(pDiA, diA);
  2880. //params structure
  2881. DICONFIGUREDEVICESPARAMSW diconfparamsW;
  2882. //to translate each DIACTIONFORMAT
  2883. LPDIACTIONFORMATW* lpDiAfW = NULL;
  2884. //the new array of DIACTIONFORMATs
  2885. LPDIACTIONFORMATW* lpDAFW = NULL;
  2886. //to traverse the old array
  2887. LPDIACTIONFORMATA lpDIFormat;
  2888. //to traverse the new array
  2889. LPDIACTIONFORMATW lpDIF;
  2890. //to keep the new user name
  2891. LPWSTR lpUserNames = NULL;
  2892. //to know how many DIACTIONFORMATS we have cloned successfully
  2893. DWORD clonedF = 0;
  2894. //kength of user names string
  2895. DWORD strLen = 0;
  2896. //zero out
  2897. ZeroMemory(&diconfparamsW, sizeof(DICONFIGUREDEVICESPARAMSW));
  2898. //set the size
  2899. diconfparamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW);
  2900. //1. Validate and translate each LPDIACTIONFORMAT in the array
  2901. lpDIFormat = (lpdiCDParams->lprgFormats);
  2902. //allocate the new array
  2903. hres = AllocCbPpv(lpdiCDParams->dwcFormats * sizeof(DIACTIONFORMATW), &diconfparamsW.lprgFormats);
  2904. if (FAILED(hres))
  2905. {
  2906. goto cleanup;
  2907. }
  2908. lpDIF = diconfparamsW.lprgFormats;
  2909. //allocate the cloning array
  2910. hres = AllocCbPpv(lpdiCDParams->dwcFormats * sizeof(DIACTIONFORMATW), &lpDAFW);
  2911. if (FAILED(hres))
  2912. {
  2913. goto cleanup;
  2914. }
  2915. lpDiAfW = lpDAFW;
  2916. //clone
  2917. for (clonedF = 0; clonedF < lpdiCDParams->dwcFormats; clonedF ++)
  2918. {
  2919. //validate
  2920. hres = IsValidMapObjectA(lpDIFormat D(comma s_szProc comma 2));
  2921. if (FAILED(hres))
  2922. {
  2923. goto cleanup;
  2924. }
  2925. //translate
  2926. hres = DiActionFormatAtoW(lpDIFormat, lpDiAfW);
  2927. if (FAILED(hres))
  2928. {
  2929. goto cleanup;
  2930. }
  2931. //save
  2932. *lpDIF = *(*lpDiAfW);
  2933. //move on
  2934. lpDIFormat++;
  2935. lpDiAfW++;
  2936. lpDIF++;
  2937. }
  2938. //if everything went fine, should have cloned all
  2939. AssertF(clonedF == lpdiCDParams->dwcFormats);
  2940. //2. Copy the user names
  2941. if (lpdiCDParams->lptszUserNames != NULL)
  2942. {
  2943. DWORD countN;
  2944. DWORD Len;
  2945. //to traverse new user names
  2946. WCHAR* lpNameW;
  2947. CHAR* lpName = lpdiCDParams->lptszUserNames;
  2948. //go throught all the user names
  2949. for ( countN = 0; countN < lpdiCDParams->dwcUsers; countN ++)
  2950. {
  2951. hres = hresFullValidReadStrA(lpName, MAX_JOYSTRING, 2);
  2952. if (FAILED(hres))
  2953. {
  2954. goto cleanup;
  2955. }
  2956. Len = lstrlenA(lpName);
  2957. //if length is 0 -- and we haven't reached the correct user count yet -
  2958. //then it is an error
  2959. if (Len == 0)
  2960. {
  2961. hres = DIERR_INVALIDPARAM;
  2962. goto cleanup;
  2963. }
  2964. //move on to the next user name
  2965. strLen += Len + 1;
  2966. lpName += Len + 1;
  2967. }
  2968. //if everything went fine, should have traversed all the user names
  2969. AssertF(countN == lpdiCDParams->dwcUsers);
  2970. //allocate
  2971. hres = AllocCbPpv( (strLen + 1) * 2, &lpUserNames );
  2972. if (FAILED(hres))
  2973. {
  2974. goto cleanup;
  2975. }
  2976. //translate
  2977. //AToU stops at the first '\0', so we have to go in a loop
  2978. lpName = lpdiCDParams->lptszUserNames;
  2979. lpNameW = lpUserNames;
  2980. //go throught all the user names
  2981. for ( countN = 0; countN < lpdiCDParams->dwcUsers; countN ++)
  2982. {
  2983. Len = lstrlenA(lpName);
  2984. AToU(lpNameW, Len + 1, lpName);
  2985. lpName += Len + 1;
  2986. lpNameW += Len + 1;
  2987. }
  2988. //save
  2989. diconfparamsW.lptszUserNames = lpUserNames;
  2990. }
  2991. //3. Populate the rest of the structure
  2992. diconfparamsW.dwcUsers = lpdiCDParams->dwcUsers;
  2993. diconfparamsW.dwcFormats = clonedF;
  2994. diconfparamsW.hwnd = lpdiCDParams->hwnd;
  2995. diconfparamsW.dics = lpdiCDParams->dics;
  2996. diconfparamsW.lpUnkDDSTarget = lpdiCDParams->lpUnkDDSTarget;
  2997. //4.Call the framework
  2998. hres = CDIObj_ConfigureDevicesCore
  2999. (
  3000. &this->diW,
  3001. lpdiCallback,
  3002. &diconfparamsW,
  3003. dwFlags,
  3004. pvRefData);
  3005. cleanup:;
  3006. //free the sapce for the array
  3007. FreePpv(&diconfparamsW.lprgFormats);
  3008. //free as many DIACTIONFORMATs as were created
  3009. if (lpDAFW)
  3010. {
  3011. lpDiAfW = lpDAFW;
  3012. for (clonedF; clonedF > 0; clonedF--)
  3013. {
  3014. FreeDiActionFormatW(lpDiAfW);
  3015. lpDiAfW++;
  3016. }
  3017. //delete the entire block
  3018. FreePpv(&lpDAFW);
  3019. }
  3020. //free the user names, if allocated
  3021. FreePpv(&lpUserNames);
  3022. }
  3023. }
  3024. ExitOleProc();
  3025. return(hres);
  3026. }
  3027. /*****************************************************************************
  3028. *
  3029. * The long-awaited vtbls and templates
  3030. *
  3031. *****************************************************************************/
  3032. #pragma BEGIN_CONST_DATA
  3033. #define CDIObj_Signature 0x504E4944 /* "DINP" */
  3034. Interface_Template_Begin(CDIObj)
  3035. Primary_Interface_Template(CDIObj, TFORM(ThisInterfaceT))
  3036. Secondary_Interface_Template(CDIObj, SFORM(ThisInterfaceT))
  3037. Interface_Template_End(CDIObj)
  3038. Primary_Interface_Begin(CDIObj, TFORM(ThisInterfaceT))
  3039. TFORM(CDIObj_CreateDevice),
  3040. TFORM(CDIObj_EnumDevices),
  3041. TFORM(CDIObj_GetDeviceStatus),
  3042. TFORM(CDIObj_RunControlPanel),
  3043. TFORM(CDIObj_Initialize),
  3044. TFORM(CDIObj_FindDevice),
  3045. TFORM(CDIObj_EnumDevicesBySemantics),
  3046. TFORM(CDIObj_ConfigureDevices),
  3047. Primary_Interface_End(CDIObj, TFORM(ThisInterfaceT))
  3048. Secondary_Interface_Begin(CDIObj, SFORM(ThisInterfaceT), SFORM(di))
  3049. SFORM(CDIObj_CreateDevice),
  3050. SFORM(CDIObj_EnumDevices),
  3051. SFORM(CDIObj_GetDeviceStatus),
  3052. SFORM(CDIObj_RunControlPanel),
  3053. SFORM(CDIObj_Initialize),
  3054. SFORM(CDIObj_FindDevice),
  3055. SFORM(CDIObj_EnumDevicesBySemantics),
  3056. SFORM(CDIObj_ConfigureDevices),
  3057. Secondary_Interface_End(CDIObj, SFORM(ThisInterfaceT), SFORM(di))