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

595 lines
16 KiB

  1. /*****************************************************************************
  2. *
  3. * DIDEnum.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The IDirectInput device enumerator.
  10. *
  11. * We don't bother making this an honest OLE enumerator because
  12. * there's no point. There's no way to access it from the outside.
  13. *
  14. * Contents:
  15. *
  16. * CDIDEnum_New
  17. * CDIDEnum_Next
  18. * CDIDEnum_Release
  19. *
  20. *****************************************************************************/
  21. #include "dinputpr.h"
  22. /*****************************************************************************
  23. *
  24. * The sqiffle for this file.
  25. *
  26. *****************************************************************************/
  27. #define sqfl sqflDEnum
  28. #if DIRECTINPUT_VERSION > 0x0400
  29. /*****************************************************************************
  30. *
  31. * @doc INTERNAL
  32. *
  33. * @struct CDIDEnum |
  34. *
  35. * Records the state of a device enumeration. Note that this
  36. * is not free-threaded.
  37. *
  38. * @field PDIW | pdiW |
  39. *
  40. * The <i IDirectInputW> object that owns the enumeration.
  41. *
  42. * @field DWORD | dwDevType |
  43. *
  44. * Device type filter.
  45. *
  46. * @field DWORD | edfl |
  47. *
  48. * Enumeration flags.
  49. *
  50. * @field int | idosdStatic |
  51. *
  52. * The next static device to enumerate. Static devices live
  53. * in <c c_rgdosdStatic>.
  54. *
  55. * @field DWORD | dwVer |
  56. *
  57. * Version of DirectX we are emulating.
  58. *
  59. * If we are emulating DirectX 3.0 or less, then don't
  60. * reveal joysticks.
  61. *
  62. #ifdef HID_SUPPORT
  63. * @field int | idosdDynamic |
  64. *
  65. * The next dynamic device to enumerate. Dyanmic devices
  66. * are kept in the <e CDIDEnum.rgdosdDynamic> array. They
  67. * are snapshotted into the enumeration structure to avoid
  68. * race conditions if a device comes or goes while we are
  69. * in the middle of an enumeration.
  70. *
  71. * @field PHIDDEVICELIST | phdl |
  72. *
  73. * List of HID devices to be returned by the enumeration.
  74. #endif
  75. *
  76. *****************************************************************************/
  77. typedef struct CDIDEnum
  78. {
  79. D(DWORD dwSig;)
  80. PDIW pdiW;
  81. DWORD dwDevType;
  82. DWORD edfl;
  83. int idosdStatic;
  84. DWORD dwVer;
  85. #ifdef HID_SUPPORT
  86. int idosdDynamic;
  87. PHIDDEVICELIST phdl;
  88. #endif
  89. } DENUM, *PDENUM, **PPDENUM;
  90. #define CDIDENUM_SIGNATURE 0x4D554E45 /* "ENUM" */
  91. #define AssertPde(pde) AssertF((pde)->dwSig == CDIDENUM_SIGNATURE)
  92. /*****************************************************************************
  93. *
  94. * @doc INTERNAL
  95. *
  96. * @global DIOBJECTSTATICDATA | c_rgdosdStatic[] |
  97. *
  98. * Right now, the list of device is static and hard-coded.
  99. * Eventually, we'll
  100. * use plug and play to enumerate devices of class "input" and
  101. * get information from their config/software keys.
  102. *
  103. *****************************************************************************/
  104. #pragma BEGIN_CONST_DATA
  105. /*
  106. * Our array of static joystick instance guids.
  107. *
  108. */
  109. GUID rgGUID_Joystick[cJoyMax] = {
  110. { 0x6F1D2B70,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  111. { 0x6F1D2B71,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  112. { 0x6F1D2B72,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  113. { 0x6F1D2B73,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  114. { 0x6F1D2B74,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  115. { 0x6F1D2B75,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  116. { 0x6F1D2B76,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  117. { 0x6F1D2B77,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  118. { 0x6F1D2B78,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  119. { 0x6F1D2B79,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  120. { 0x6F1D2B7A,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  121. { 0x6F1D2B7B,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  122. { 0x6F1D2B7C,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  123. { 0x6F1D2B7D,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  124. { 0x6F1D2B7E,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  125. { 0x6F1D2B7F,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00},
  126. };
  127. #if cJoyMax != 16
  128. #error rgGUID_Joystick supports only 16 joysticks.
  129. #endif
  130. /*
  131. * Note that we recycle the SysMouse GUID as the instance GUID too,
  132. * since there will never be more than one system mouse installed in
  133. * the system. Similarly for SysKeyboard.
  134. */
  135. DIOBJECTSTATICDATA c_rgdosdStatic[] = {
  136. { &GUID_SysMouse, DIDEVTYPE_MOUSE, CMouse_New,},
  137. { &GUID_SysMouseEm, DIDEVTYPE_MOUSE, CMouse_New,},
  138. { &GUID_SysMouseEm2, DIDEVTYPE_MOUSE, CMouse_New,},
  139. { &GUID_SysKeyboard, DIDEVTYPE_KEYBOARD, CKbd_New,},
  140. { &GUID_SysKeyboardEm, DIDEVTYPE_KEYBOARD, CKbd_New,},
  141. { &GUID_SysKeyboardEm2, DIDEVTYPE_KEYBOARD, CKbd_New,},
  142. #ifndef WINNT
  143. /*
  144. * On WINNT all joysticks are HID devices.
  145. * So it is pointless to include predefined
  146. * Joystick GUIDs
  147. */
  148. #define MAKEJOY(n) \
  149. { &rgGUID_Joystick[n],DIDEVTYPE_JOYSTICK, CJoy_New, }
  150. MAKEJOY( 0),
  151. MAKEJOY( 1),
  152. MAKEJOY( 2),
  153. MAKEJOY( 3),
  154. MAKEJOY( 4),
  155. MAKEJOY( 5),
  156. MAKEJOY( 6),
  157. MAKEJOY( 7),
  158. MAKEJOY( 8),
  159. MAKEJOY( 9),
  160. MAKEJOY(10),
  161. MAKEJOY(11),
  162. MAKEJOY(12),
  163. MAKEJOY(13),
  164. MAKEJOY(14),
  165. MAKEJOY(15),
  166. #undef MAKEJOY
  167. #endif
  168. };
  169. #pragma END_CONST_DATA
  170. /*****************************************************************************
  171. *
  172. * @doc INTERNAL
  173. *
  174. * @func HRESULT | hresFindInstanceGUID |
  175. *
  176. * Locates information given an instance GUID.
  177. *
  178. * @parm IN PCGUID | pguid |
  179. *
  180. * The instance GUID to be located.
  181. *
  182. * @parm OUT CREATEDCB * | pcdcb |
  183. *
  184. * Receives pointer to the <f CreateDcb> function for the object.
  185. *
  186. *****************************************************************************/
  187. HRESULT EXTERNAL
  188. hresFindInstanceGUID_(PCGUID pguid, CREATEDCB *pcdcb,
  189. LPCSTR s_szProc, int iarg)
  190. {
  191. HRESULT hres;
  192. EnterProcS(hresFindInstance, (_ "G", pguid));
  193. if(SUCCEEDED(hres = hresFullValidGuid(pguid, iarg)))
  194. {
  195. int idosd;
  196. /*
  197. * First try the list of static devices. Since this
  198. * list never changes, we don't need to protect it
  199. * with a critical section.
  200. */
  201. for(idosd = 0; idosd < cA(c_rgdosdStatic); idosd++)
  202. {
  203. if(IsEqualGUID(pguid, c_rgdosdStatic[idosd].rguidInstance))
  204. {
  205. *pcdcb = c_rgdosdStatic[idosd].CreateDcb;
  206. goto done;
  207. }
  208. }
  209. #ifdef HID_SUPPORT
  210. /*
  211. * So it wasn't one of the static devices. See if it's
  212. * one of the dynamic HID devices we've already found.
  213. */
  214. hres = hresFindHIDInstanceGUID(pguid, pcdcb);
  215. if(FAILED(hres))
  216. {
  217. /*
  218. * Not on our list of dynamic HID devices.
  219. * Re-enumerate them and try again. Maybe it was
  220. * for a device that we recently added.
  221. */
  222. DIHid_BuildHidList(TRUE);
  223. hres = hresFindHIDInstanceGUID(pguid, pcdcb);
  224. }
  225. if(FAILED(hres))
  226. {
  227. #ifdef WINNT
  228. /*
  229. * NT Bug#351951.
  230. * If they are directly asking for one of the predefined joystick
  231. * IDs then see if we have a device mapped to that ID. If so,
  232. * pretend they asked for that GUID instead.
  233. */
  234. /*
  235. * Weakly Assert the range of predefined static joystick instance GUIDs
  236. */
  237. AssertF( ( rgGUID_Joystick[0].Data1 & 0x0f ) == 0 );
  238. AssertF( ( rgGUID_Joystick[0x0f].Data1 & 0x0f ) == 0x0f );
  239. /*
  240. * Check the GUID is the same as the first static one ignoring LS 4 bits
  241. */
  242. if( ( (pguid->Data1 & 0xf0) == (rgGUID_Joystick[0].Data1 & 0xf0) )
  243. && !memcmp( ((PBYTE)&rgGUID_Joystick)+1, ((PBYTE)pguid)+1, sizeof(*pguid) - 1 ) )
  244. {
  245. RPF("%s: Using predefined instance GUIDs is bad and should not work!", s_szProc);
  246. if( phdiFindJoyId( pguid->Data1 & 0x0f ) )
  247. {
  248. *pcdcb = CHid_New;
  249. hres = S_OK;
  250. }
  251. else
  252. {
  253. *pcdcb = 0;
  254. hres = DIERR_DEVICENOTREG;
  255. }
  256. }
  257. else
  258. {
  259. RPF("%s: Warning: GUID is not installed in this system", s_szProc);
  260. *pcdcb = 0;
  261. hres = DIERR_DEVICENOTREG;
  262. }
  263. #else
  264. RPF("%s: Warning: GUID is not installed in this system", s_szProc);
  265. *pcdcb = 0;
  266. hres = DIERR_DEVICENOTREG;
  267. #endif //WINNT
  268. }
  269. #else
  270. RPF("%s: Warning: GUID is not installed in this system", s_szProc);
  271. *pcdcb = 0;
  272. hres = DIERR_DEVICENOTREG;
  273. #endif //HID_SUPPORT
  274. }
  275. done:;
  276. ExitOleProcPpv(pcdcb);
  277. return hres;
  278. }
  279. /*****************************************************************************
  280. *
  281. * @doc INTERNAL
  282. *
  283. * @func void | CDIDEnum_Release |
  284. *
  285. * Free the enumeration object and its associated resources.
  286. *
  287. * @parm CDIDEnum * | pde |
  288. *
  289. * The enumeration state to be released.
  290. *
  291. *****************************************************************************/
  292. void EXTERNAL
  293. CDIDEnum_Release(PDENUM pde)
  294. {
  295. EnterProcI(CDIDEnum_Release, (_ "p", pde));
  296. AssertPde(pde);
  297. OLE_Release(pde->pdiW);
  298. #ifdef HID_SUPPORT
  299. FreePpv(&pde->phdl);
  300. #endif
  301. FreePv(pde);
  302. }
  303. /*****************************************************************************
  304. *
  305. * @doc INTERNAL
  306. *
  307. * @func HRESULT | CDIDEnum_Next |
  308. *
  309. * Return the next device.
  310. *
  311. * Note that this is not the same as the OLE <mf IEnumXxx::Next>
  312. * function. Not that it'd be hard to convert over; it's just
  313. * not needed yet.
  314. *
  315. * @parm CDIDEnum * | pde |
  316. *
  317. * Maintains enumeration state.
  318. *
  319. * @parm LPGUID | pguid |
  320. *
  321. * Receives the enumerated GUID.
  322. *
  323. * @parm LPDIDEVICEINSTANCEW | pddiW |
  324. *
  325. * Receives device attributes.
  326. *
  327. * @returns
  328. *
  329. * Returns <c S_OK> if the object was successfully obtained,
  330. * or <c S_FALSE> if there aren't any more objects.
  331. *
  332. * Warning! <f CDIObj_EnumDevicesW> assumes that this function
  333. * cannot fail.
  334. *
  335. *****************************************************************************/
  336. #define S_SKIP hresUs(2)
  337. STDMETHODIMP
  338. CDIDEnum_Next(PDENUM pde, LPDIDEVICEINSTANCEW pddiW)
  339. {
  340. HRESULT hres;
  341. EnterProcI(CDIDEnum_Next, (_ "p", pde));
  342. AssertPde(pde);
  343. AssertF(pddiW->dwSize == cbX(*pddiW));
  344. /*
  345. * Keep going until something works.
  346. */
  347. do
  348. {
  349. PDIOBJECTSTATICDATA pdosd;
  350. /*
  351. * Pull one from the static list first.
  352. * If that is empty, then pull from the dynamic list.
  353. * If that is empty, then we're done.
  354. */
  355. if(pde->idosdStatic < cA(c_rgdosdStatic))
  356. {
  357. pdosd = &c_rgdosdStatic[pde->idosdStatic++];
  358. #ifdef HID_SUPPORT
  359. } else if(pde->phdl && pde->idosdDynamic < pde->phdl->chdi)
  360. {
  361. pdosd = &pde->phdl->rghdi[pde->idosdDynamic].osd;
  362. pdosd->rguidInstance = &pde->phdl->rghdi[pde->idosdDynamic].guid;
  363. pde->idosdDynamic++;
  364. #endif
  365. } else
  366. {
  367. hres = S_FALSE;
  368. goto done;
  369. }
  370. /*
  371. * If a devtype filter is provided, then it must match.
  372. *
  373. * If the version is 3.0 or less, then don't show joysticks
  374. * because DX3 didn't have (proper) joystick support.
  375. */
  376. if(fLimpFF(GET_DIDEVICE_TYPE(pde->dwDevType),
  377. GET_DIDEVICE_TYPE(pde->dwDevType) ==
  378. GET_DIDEVICE_TYPE(pdosd->dwDevType)) &&
  379. fLimpFF(pde->dwVer <= 0x0300,
  380. LOBYTE(pdosd->dwDevType) != DIDEVTYPE_JOYSTICK))
  381. {
  382. PDIDW pdidW;
  383. hres = IDirectInput_CreateDevice(pde->pdiW, pdosd->rguidInstance,
  384. (PV)&pdidW, 0);
  385. if(SUCCEEDED(hres))
  386. {
  387. if(CDIObj_TestDeviceFlags(pdidW, pde->edfl) == S_OK)
  388. {
  389. pddiW->dwSize = cbX(*pddiW);
  390. hres = IDirectInputDevice_GetDeviceInfo(pdidW, pddiW);
  391. AssertF(fLimpFF(SUCCEEDED(hres),
  392. IsEqualGUID(pdosd->rguidInstance,
  393. &pddiW->guidInstance)));
  394. if(SUCCEEDED(hres))
  395. {
  396. hres = S_OK;
  397. } else
  398. {
  399. hres = S_SKIP;
  400. }
  401. } else
  402. {
  403. hres = S_SKIP;
  404. }
  405. OLE_Release(pdidW);
  406. } else
  407. {
  408. hres = S_SKIP;
  409. }
  410. } else
  411. {
  412. hres = S_SKIP;
  413. }
  414. } while(hres == S_SKIP);
  415. done:;
  416. AssertF(hres == S_OK || hres == S_FALSE);
  417. ScrambleBit(&pddiW->dwDevType, DIDEVTYPE_RANDOM);
  418. return hres;
  419. }
  420. /*****************************************************************************
  421. *
  422. * @doc INTERNAL
  423. *
  424. * @func HRESULT | CDIDEnum_New |
  425. *
  426. * Create an enumeration object.
  427. *
  428. * The enumeration object snapshots the system device state
  429. * and farms them out one at a time.
  430. *
  431. * @parm PDIW | pdiW |
  432. *
  433. * Parent <i IDirectInputW> we piggyback off of for device
  434. * creation.
  435. *
  436. * @field DWORD | dwDevType |
  437. *
  438. * Device type filter.
  439. *
  440. * @field DWORD | edfl |
  441. *
  442. * Enumeration flags.
  443. *
  444. * @field DWORD | dwVer |
  445. *
  446. * Version of DirectX we are emulating.
  447. *
  448. * If we are emulating DirectX 3.0 or less, then don't
  449. * reveal joysticks.
  450. *
  451. * @parm CDIDEnum ** | ppde |
  452. *
  453. * Receives the enumeration object.
  454. *
  455. * @returns
  456. *
  457. * Returns <c S_OK> on success or an error code on failure.
  458. *
  459. *****************************************************************************/
  460. STDMETHODIMP
  461. CDIDEnum_New(PDIW pdiW, DWORD dwDevType, DWORD edfl, DWORD dwVer, PPDENUM ppde)
  462. {
  463. HRESULT hres;
  464. EnterProcI(CDIDEnum_New, (_ "pxx", pdiW, dwDevType, edfl));
  465. #ifdef HID_SUPPORT
  466. /*
  467. * Refresh the HID device list so the enumeration is fresh.
  468. */
  469. DIHid_BuildHidList(TRUE);
  470. #endif
  471. hres = AllocCbPpv(cbX(CDIDEnum), ppde);
  472. if(SUCCEEDED(hres))
  473. {
  474. PDENUM pde = *ppde;
  475. D(pde->dwSig = CDIDENUM_SIGNATURE);
  476. pde->pdiW = pdiW;
  477. pde->dwDevType = dwDevType;
  478. pde->edfl = edfl;
  479. pde->dwVer = dwVer;
  480. AssertF(pde->idosdStatic == 0);
  481. #ifdef HID_SUPPORT
  482. /*
  483. * If enumerating only HID devices, then skip over all
  484. * the static (non-HID) devices. This is important so
  485. * we don't go into infinite recursion death with WINMM.DLL,
  486. * which does an enumeration to find HID joysticks
  487. * in the first place.
  488. */
  489. if(pde->dwDevType & DIDEVTYPE_HID)
  490. {
  491. pde->idosdStatic = cA(c_rgdosdStatic);
  492. }
  493. AssertF(pde->idosdDynamic == 0);
  494. #endif
  495. #ifdef HID_SUPPORT
  496. /*
  497. * Clone the device list. This must be done under the
  498. * critical section to avoid races.
  499. */
  500. DllEnterCrit();
  501. if(g_phdl)
  502. {
  503. hres = AllocCbPpv(cbHdlChdi(g_phdl->chdi), &pde->phdl);
  504. if(SUCCEEDED(hres))
  505. {
  506. CopyMemory(pde->phdl, g_phdl, cbHdlChdi(g_phdl->chdi));
  507. SquirtSqflPtszV(sqfl, TEXT("%S: Have %d HID devices"),
  508. s_szProc, pde->phdl->chdi);
  509. hres = S_OK;
  510. }
  511. } else
  512. {
  513. hres = S_OK;
  514. }
  515. DllLeaveCrit();
  516. if(SUCCEEDED(hres))
  517. {
  518. OLE_AddRef(pde->pdiW);
  519. hres = S_OK;
  520. }
  521. #else
  522. OLE_AddRef(pde->pdiW);
  523. hres = S_OK;
  524. #endif
  525. }
  526. ExitOleProcPpv(ppde);
  527. return hres;
  528. }
  529. #endif