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.

746 lines
19 KiB

  1. /*****************************************************************************
  2. *
  3. * diqacq.c
  4. *
  5. * The dialog box that tinkers with the control panel interface.
  6. *
  7. *****************************************************************************/
  8. #include "diquick.h"
  9. #include <dinputd.h>
  10. #include <gameport.h>
  11. #define JOY_HWS_ISGAMEPORTDRIVER 0x04000000l
  12. #define JOY_HWS_ISANALOGPORTDRIVER 0x08000000l
  13. #define JOY_HWS_ISGAMEPORTBUS 0x80000000l
  14. /*****************************************************************************
  15. *
  16. * Mapping from class strings to class GUIDs.
  17. *
  18. *****************************************************************************/
  19. typedef struct CLASSMAP {
  20. UINT ids;
  21. REFGUID rguid;
  22. } CLASSMAP, *PCLASSMAP;
  23. #pragma BEGIN_CONST_DATA
  24. CLASSMAP c_rgcmap[] = {
  25. #ifdef DEBUG
  26. { IDS_INVALID, &GUID_SysKeyboard, }, /* Bogus class */
  27. #endif
  28. { IDS_CLASS_KBD, &GUID_KeyboardClass, },
  29. { IDS_CLASS_MEDIA, &GUID_MediaClass, },
  30. { IDS_CLASS_MOUSE, &GUID_MouseClass, },
  31. { IDS_CLASS_HID, &GUID_HIDClass, },
  32. };
  33. #pragma END_CONST_DATA
  34. /*****************************************************************************
  35. *
  36. * Control panel dialog instance data
  37. *
  38. * Instance data for control panel dialog box.
  39. *
  40. *****************************************************************************/
  41. typedef struct TYPENAME {
  42. WCHAR wsz[MAX_JOYSTRING];
  43. } TYPENAME, *PTYPENAME;
  44. typedef struct CPLDLGINFO {
  45. HWND hdlgOwner; /* Owner window */
  46. BOOL fOle; /* Should we create via OLE? */
  47. UINT flCreate; /* Flags */
  48. HWND hwndTypes; /* Listbox for types */
  49. HWND hwndConfigs; /* Listbox for configs */
  50. IDirectInputJoyConfig *pdjc;/* The thing we created */
  51. DARY daryTypes; /* Array of type names */
  52. } CPLDLGINFO, *PCPLDLGINFO;
  53. /*****************************************************************************
  54. *
  55. * Cpl_AddType
  56. *
  57. *****************************************************************************/
  58. void INTERNAL
  59. Cpl_AddType(LPCWSTR pwszType, LPCTSTR ptszName, PCPLDLGINFO pcpl)
  60. {
  61. int item;
  62. item = ListBox_AddString(pcpl->hwndTypes, ptszName);
  63. if (item >= 0) {
  64. int itype;
  65. itype = Dary_Append(&pcpl->daryTypes, (PTYPENAME)0);
  66. if (itype >= 0) {
  67. PTYPENAME ptype;
  68. ptype = Dary_GetPtr(&pcpl->daryTypes, itype, TYPENAME);
  69. /*
  70. * Must do this because Win95 doesn't have lstrcpyW.
  71. */
  72. CopyMemory(ptype->wsz, pwszType,
  73. sizeof(WCHAR) * (1 + lstrlenW(pwszType)));
  74. ListBox_SetItemData(pcpl->hwndTypes, item, itype);
  75. }
  76. }
  77. }
  78. /*****************************************************************************
  79. *
  80. * Cpl_TypeEnumProc
  81. *
  82. *****************************************************************************/
  83. BOOL CALLBACK
  84. Cpl_TypeEnumProc(LPCWSTR pwszType, LPVOID pvRef)
  85. {
  86. PCPLDLGINFO pcpl = pvRef;
  87. HRESULT hres;
  88. DIJOYTYPEINFO jti;
  89. jti.dwSize = cbX(jti);
  90. hres = pcpl->pdjc->lpVtbl->GetTypeInfo(pcpl->pdjc, pwszType, &jti,
  91. DITC_REGHWSETTINGS | DITC_CLSIDCONFIG |DITC_DISPLAYNAME);
  92. if (SUCCEEDED(hres)) {
  93. TCHAR tsz[MAX_JOYSTRING];
  94. ConvertString(TRUE, jti.wszDisplayName, tsz, cA(tsz));
  95. Cpl_AddType(pwszType, tsz, pcpl);
  96. }
  97. return DIENUM_CONTINUE;
  98. }
  99. /*****************************************************************************
  100. *
  101. * Cpl_OnInitDialog
  102. *
  103. *****************************************************************************/
  104. BOOL INTERNAL
  105. Cpl_OnInitDialog(HWND hdlg, LPARAM lp)
  106. {
  107. PCPLDLGINFO pcpl = (PV)lp;
  108. DIJOYTYPEINFO jti;
  109. DIJOYCONFIG jc;
  110. int icmap, ijoy;
  111. HWND hwnd;
  112. HRESULT hres;
  113. TCHAR tsz[MAX_JOYSTRING];
  114. SetDialogPtr(hdlg, pcpl);
  115. /*
  116. * Initialize the list of installable hardware.
  117. */
  118. hwnd = GetDlgItem(hdlg, IDC_CPL_CLASSES);
  119. for (icmap = 0; icmap < cA(c_rgcmap); icmap++) {
  120. int item;
  121. LoadString(g_hinst, c_rgcmap[icmap].ids, tsz, cA(tsz));
  122. item = ComboBox_AddString(hwnd, tsz);
  123. if (item >= 0) {
  124. ComboBox_SetItemData(hwnd, item, icmap);
  125. }
  126. }
  127. ComboBox_SetCurSel(hwnd, 0);
  128. /*
  129. * Initialize the cooperative level information.
  130. */
  131. pcpl->pdjc->lpVtbl->SetCooperativeLevel(pcpl->pdjc, hdlg,
  132. DISCL_EXCLUSIVE |
  133. DISCL_BACKGROUND);
  134. /*
  135. * Initialize the list of joystick types.
  136. */
  137. pcpl->hwndTypes = GetDlgItem(hdlg, IDC_CPL_TYPES);
  138. pcpl->pdjc->lpVtbl->EnumTypes(pcpl->pdjc, Cpl_TypeEnumProc, pcpl);
  139. #ifdef DEBUG
  140. /*
  141. * And add the obligatory invalid item.
  142. */
  143. Cpl_AddType(L"<invalid>", g_tszInvalid, pcpl);
  144. #endif
  145. /*
  146. * Initialize the list of joystick configs.
  147. */
  148. pcpl->hwndConfigs = GetDlgItem(hdlg, IDC_CPL_CONFIGS);
  149. jc.dwSize = cbX(jc);
  150. jti.dwSize = cbX(jti);
  151. for (ijoy = 0; ijoy<15; ijoy++) {
  152. hres = pcpl->pdjc->lpVtbl->GetConfig(pcpl->pdjc,
  153. ijoy, &jc,
  154. DIJC_GUIDINSTANCE |
  155. DIJC_REGHWCONFIGTYPE
  156. );
  157. if (hres == DI_OK) {
  158. hres = pcpl->pdjc->lpVtbl->GetTypeInfo(pcpl->pdjc,
  159. jc.wszType, &jti, DITC_DISPLAYNAME);
  160. if (SUCCEEDED(hres)) {
  161. int item;
  162. wsprintf(tsz, TEXT("%d (%ls)"), ijoy+1, jti.wszDisplayName);
  163. item = ListBox_AddString(pcpl->hwndConfigs, tsz);
  164. if (item >= 0) {
  165. ListBox_SetItemData(pcpl->hwndConfigs, item, ijoy);
  166. }
  167. }
  168. }
  169. }
  170. return 1;
  171. }
  172. //////////////////////////////////////////////////////////
  173. /*
  174. #if 0
  175. {
  176. HKEY hk;
  177. _asm int 3
  178. hres = pcpl->pdjc->lpVtbl->OpenConfigKey(pcpl->pdjc, ijoy,
  179. KEY_QUERY_VALUE, &hk);
  180. if (SUCCEEDED(hres)) RegCloseKey(hk);
  181. }
  182. #endif
  183. #if 0
  184. jti.dwSize = cbX(jti);
  185. jti.hws.dwFlags = 0x12345678;
  186. jti.hws.dwNumButtons = 0;
  187. CopyMemory(jti.wszDisplayName, L"Fred's Joystick", 2*16);
  188. jti.wszCallout[0] = TEXT('\0');
  189. jti.clsidConfig.Data1 = 1;
  190. pcpl->pdjc->lpVtbl->Acquire(pcpl->pdjc);
  191. // pcpl->pdjc->lpVtbl->SetTypeInfo(pcpl->pdjc, L"Fred", &jti, DITC_CLSIDCONFIG);
  192. pcpl->pdjc->lpVtbl->SendNotify(pcpl->pdjc);
  193. // pcpl->pdjc->lpVtbl->Unacquire(pcpl->pdjc);
  194. #endif
  195. #if 0
  196. // memset(&jc, 0xCC, cbX(jc));
  197. jc.dwSize = cbX(jc);
  198. pcpl->pdjc->lpVtbl->GetConfig(pcpl->pdjc, 0, &jc,
  199. DIJC_GUIDINSTANCE |
  200. DIJC_REGHWCONFIGTYPE |
  201. //DIJC_GAIN |
  202. 0);//DIJC_CALLOUT);
  203. tsz;
  204. #if 0 // HACKHACK NT
  205. wsprintf(tsz, "GUID=%08x, Flags=%08x, buttons=%d gain=%d type=%ls\r\n",
  206. jc.guidInstance.Data1,
  207. jc.hwc.hws.dwFlags, jc.hwc.hws.dwNumButtons, jc.dwGain,
  208. jc.wszType);
  209. OutputDebugString(tsz);
  210. #endif
  211. pcpl->pdjc->lpVtbl->Acquire(pcpl->pdjc);
  212. // MultiByteToWideChar(CP_ACP, 0, "#3", -1, jc.wszType, MAX_JOYSTRING);
  213. jc.dwGain = 5000;
  214. // pcpl->pdjc->lpVtbl->SetConfig(pcpl->pdjc, 0, &jc, DIJC_GAIN);
  215. pcpl->pdjc->lpVtbl->Unacquire(pcpl->pdjc);
  216. #endif
  217. */
  218. ////////////////////////////////////////////////////////////////////////////////
  219. /*****************************************************************************
  220. *
  221. * Cpl_OnAddNewHardware
  222. *
  223. *****************************************************************************/
  224. BOOL INTERNAL
  225. Cpl_OnAddNewHardware(HWND hdlg)
  226. {
  227. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  228. HWND hwnd = GetDlgItem(hdlg, IDC_CPL_CLASSES);
  229. int item;
  230. int icmap;
  231. if ((item = (int)ComboBox_GetCurSel(hwnd)) >= 0 &&
  232. (icmap = (int)ComboBox_GetItemData(hwnd, item)) >= 0) {
  233. HRESULT hres;
  234. hres = pcpl->pdjc->lpVtbl->AddNewHardware(
  235. pcpl->pdjc, hdlg, c_rgcmap[icmap].rguid);
  236. if (SUCCEEDED(hres)) {
  237. } else if (hres == DIERR_CANCELLED) {
  238. } else {
  239. MessageBoxV(hdlg, IDS_ERR_ADDNEWHARDWARE, hres);
  240. }
  241. }
  242. return TRUE;
  243. }
  244. /*****************************************************************************
  245. *
  246. * Cpl_OnTypeDblClk
  247. *
  248. * An item in the types list box was double-clicked. Display details.
  249. *
  250. *****************************************************************************/
  251. BOOL INTERNAL
  252. Cpl_OnTypeDblClk(HWND hdlg)
  253. {
  254. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  255. int iItem;
  256. iItem = ListBox_GetCurSel(pcpl->hwndTypes);
  257. if (iItem >= 0) {
  258. int itype = (int)ListBox_GetItemData(pcpl->hwndTypes, iItem);
  259. if (itype >= 0) {
  260. PTYPENAME ptype = Dary_GetPtr(&pcpl->daryTypes, itype, TYPENAME);
  261. Type_Create(hdlg, pcpl->pdjc, ptype->wsz);
  262. }
  263. /*
  264. * That dialog screws up the vwi state.
  265. */
  266. SetActiveWindow(hdlg);
  267. }
  268. return 1;
  269. }
  270. /*****************************************************************************
  271. *
  272. * Cpl_GetFirstFreeID
  273. *
  274. *****************************************************************************/
  275. int INTERNAL
  276. Cpl_GetFirstFreeID(HWND hdlg)
  277. {
  278. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  279. int ijoy;
  280. DIJOYCONFIG jc;
  281. HRESULT hres;
  282. jc.dwSize = cbX(jc);
  283. for (ijoy = 0; ijoy < 15; ijoy++ ){
  284. hres = pcpl->pdjc->lpVtbl->GetConfig(pcpl->pdjc,
  285. ijoy, &jc,
  286. DIJC_GUIDINSTANCE |
  287. DIJC_REGHWCONFIGTYPE
  288. );
  289. if (hres != DI_OK) {
  290. break;
  291. }
  292. }
  293. return ijoy;
  294. }
  295. /*****************************************************************************
  296. *
  297. * Cpl_AddSelectedItem
  298. *
  299. *****************************************************************************/
  300. GUID GUID_GAMEENUM_BUS_ENUMERATOR2 = {0xcae56030, 0x684a, 0x11d0, 0xd6, 0xf6, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda};
  301. BOOL INTERNAL
  302. Cpl_AddSelectedItem( HWND hdlg, DIJOYTYPEINFO *pjti, DWORD dwType, PTYPENAME ptype )
  303. {
  304. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  305. DIJOYTYPEINFO jti;
  306. DIJOYCONFIG jc;
  307. int ijoy;
  308. TCHAR tsz[MAX_JOYSTRING];
  309. HRESULT hres;
  310. BOOL bRet = FALSE;
  311. ijoy = Cpl_GetFirstFreeID(hdlg);
  312. if ( ijoy >= 15 ) {
  313. #ifdef _DEBUG
  314. OutputDebugString(TEXT("No available ID to SetConfig.\n"));
  315. #endif
  316. return FALSE;
  317. }
  318. memset( &jc, 0, cbX(jc) );
  319. jc.dwSize = cbX(DIJOYCONFIG);
  320. jc.hwc.hws = pjti->hws;
  321. jc.hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER;
  322. jc.hwc.dwUsageSettings |= JOY_US_PRESENT;
  323. jc.hwc.dwType = dwType;
  324. lstrcpyW(jc.wszCallout, pjti->wszCallout);
  325. lstrcpyW(jc.wszType, ptype->wsz);
  326. jc.guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR2;
  327. if ( SUCCEEDED(pcpl->pdjc->lpVtbl->Acquire(pcpl->pdjc)) ) {
  328. hres = pcpl->pdjc->lpVtbl->SetConfig(pcpl->pdjc, ijoy, &jc, DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_WDMGAMEPORT);
  329. if ( SUCCEEDED(hres) ) {
  330. bRet = TRUE;
  331. } else {
  332. #ifdef DEBUG
  333. OutputDebugString(TEXT("SetConfig failed.\n"));
  334. #endif
  335. goto _done;
  336. }
  337. ZeroX(jc);
  338. ZeroX(jti);
  339. jc.dwSize = cbX(jc);
  340. jti.dwSize = cbX(jti);
  341. hres = pcpl->pdjc->lpVtbl->GetConfig(pcpl->pdjc,
  342. ijoy, &jc,
  343. DIJC_GUIDINSTANCE |
  344. DIJC_REGHWCONFIGTYPE
  345. );
  346. if (hres == DI_OK) {
  347. hres = pcpl->pdjc->lpVtbl->GetTypeInfo(pcpl->pdjc,
  348. jc.wszType, &jti,
  349. DITC_DISPLAYNAME);
  350. if (SUCCEEDED(hres)) {
  351. int item;
  352. wsprintf(tsz, TEXT("%d (%ls)"), ijoy+1, jti.wszDisplayName);
  353. item = ListBox_AddString(pcpl->hwndConfigs, tsz);
  354. if (item >= 0) {
  355. ListBox_SetItemData(pcpl->hwndConfigs, item, ijoy);
  356. }
  357. }
  358. }
  359. pcpl->pdjc->lpVtbl->Unacquire(pcpl->pdjc);
  360. pcpl->pdjc->lpVtbl->SendNotify(pcpl->pdjc);
  361. }
  362. _done:
  363. return bRet;
  364. }
  365. /*****************************************************************************
  366. *
  367. * Cpl_AddJoystick
  368. *
  369. * The joystick selected in the types list box is added.
  370. *
  371. *****************************************************************************/
  372. BOOL INTERNAL
  373. Cpl_AddJoystick(HWND hdlg)
  374. {
  375. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  376. int iItem;
  377. BOOL bRet = FALSE;
  378. iItem = ListBox_GetCurSel(pcpl->hwndTypes);
  379. if (iItem >= 0) {
  380. int itype = (int)ListBox_GetItemData(pcpl->hwndTypes, iItem);
  381. if (itype >= 0) {
  382. PTYPENAME ptype = Dary_GetPtr(&pcpl->daryTypes, itype, TYPENAME);
  383. DIJOYTYPEINFO jti;
  384. HRESULT hres;
  385. jti.dwSize = cbX(jti);
  386. hres = pcpl->pdjc->lpVtbl->GetTypeInfo(pcpl->pdjc, ptype->wsz, &jti,
  387. DITC_REGHWSETTINGS |
  388. DITC_DISPLAYNAME);
  389. if (SUCCEEDED(hres)) {
  390. bRet = Cpl_AddSelectedItem( hdlg, &jti, iItem, ptype );
  391. }
  392. }
  393. SetActiveWindow(hdlg);
  394. }
  395. return bRet;
  396. }
  397. /*****************************************************************************
  398. *
  399. * Cpl_DeleteSelectedItem
  400. *
  401. *****************************************************************************/
  402. BOOL INTERNAL
  403. Cpl_DeleteSelectedItem( HWND hdlg, int iItem, int iJoy )
  404. {
  405. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  406. HRESULT hres;
  407. BOOL bRet = FALSE;
  408. hres = pcpl->pdjc->lpVtbl->Acquire(pcpl->pdjc);
  409. if(SUCCEEDED(hres))
  410. {
  411. hres = pcpl->pdjc->lpVtbl->DeleteConfig(pcpl->pdjc, iJoy);
  412. if(SUCCEEDED(hres))
  413. {
  414. pcpl->pdjc->lpVtbl->SendNotify(pcpl->pdjc);
  415. ListBox_DeleteString(pcpl->hwndConfigs, iItem);
  416. pcpl->pdjc->lpVtbl->Unacquire(pcpl->pdjc);
  417. bRet = TRUE;
  418. }
  419. }
  420. return bRet;
  421. }
  422. /*****************************************************************************
  423. *
  424. * Cpl_DeleteJoystick
  425. *
  426. * The joystick selected in the types list box is added.
  427. *
  428. *****************************************************************************/
  429. BOOL INTERNAL
  430. Cpl_DeleteJoystick(HWND hdlg)
  431. {
  432. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  433. int iItem;
  434. BOOL bRet = FALSE;
  435. iItem = ListBox_GetCurSel(pcpl->hwndConfigs);
  436. if (iItem >= 0) {
  437. int iJoy = (int)ListBox_GetItemData(pcpl->hwndConfigs, iItem);
  438. if (iJoy >= 0) {
  439. bRet = Cpl_DeleteSelectedItem( hdlg, iItem, iJoy );
  440. }
  441. SetActiveWindow(hdlg);
  442. }
  443. return bRet;
  444. }
  445. /*****************************************************************************
  446. *
  447. * Cpl_OnUserValues
  448. *
  449. * Open the User Values dialog.
  450. *
  451. *****************************************************************************/
  452. BOOL INTERNAL
  453. Cpl_OnUserValues(HWND hdlg)
  454. {
  455. PCPLDLGINFO pcpl = GetDialogPtr(hdlg);
  456. Uv_Create(hdlg, pcpl->pdjc);
  457. return 1;
  458. }
  459. /*****************************************************************************
  460. *
  461. * Cpl_OnCommand
  462. *
  463. *****************************************************************************/
  464. BOOL INTERNAL
  465. Cpl_OnCommand(HWND hdlg, int id, UINT cmd)
  466. {
  467. switch (id) {
  468. case IDC_CPL_ADD:
  469. return Cpl_OnAddNewHardware(hdlg);
  470. case IDC_CPL_TYPES:
  471. if (cmd == LBN_DBLCLK) {
  472. return Cpl_OnTypeDblClk(hdlg);
  473. }
  474. break;
  475. case IDC_CPL_ADDJOYSTICK:
  476. if (cmd == BN_CLICKED) {
  477. return Cpl_AddJoystick(hdlg);
  478. }
  479. break;
  480. case IDC_CPL_DELJOYSTICK:
  481. if (cmd == BN_CLICKED) {
  482. return Cpl_DeleteJoystick(hdlg);
  483. }
  484. break;
  485. case IDC_CPL_USERVALUES:
  486. if (cmd == BN_CLICKED) {
  487. return Cpl_OnUserValues(hdlg);
  488. }
  489. break;
  490. }
  491. return 0;
  492. }
  493. /*****************************************************************************
  494. *
  495. * Cpl_DlgProc
  496. *
  497. *****************************************************************************/
  498. INT_PTR INTERNAL
  499. Cpl_DlgProc(HWND hdlg, UINT wm, WPARAM wp, LPARAM lp)
  500. {
  501. switch (wm) {
  502. case WM_INITDIALOG:
  503. return Cpl_OnInitDialog(hdlg, lp);
  504. case WM_DESTROY:
  505. /*
  506. * Cpl_ThreadStart will do the cleanup for us.
  507. */
  508. break;
  509. case WM_COMMAND:
  510. return Cpl_OnCommand(hdlg,
  511. (int)GET_WM_COMMAND_ID(wp, lp),
  512. (UINT)GET_WM_COMMAND_CMD(wp, lp));
  513. case WM_CLOSE:
  514. DestroyWindow(hdlg);
  515. return TRUE;
  516. }
  517. return 0;
  518. }
  519. /*****************************************************************************
  520. *
  521. * Cpl_DoCpl
  522. *
  523. *****************************************************************************/
  524. void INLINE
  525. Cpl_DoCpl(PCPLDLGINFO pcpl)
  526. {
  527. SendNotifyMessage(pcpl->hdlgOwner, WM_THREADSTARTED, 0, 0);
  528. /*
  529. * This function also sends the WM_CHILDEXIT.
  530. */
  531. SemimodalDialogBoxParam(IDD_CPL, pcpl->hdlgOwner, Cpl_DlgProc,
  532. (LPARAM)pcpl);
  533. }
  534. /*****************************************************************************
  535. *
  536. * Cpl_ThreadStart
  537. *
  538. * Runs on the new thread. Creates the object and spins the dialog
  539. * box to control it.
  540. *
  541. *****************************************************************************/
  542. DWORD WINAPI
  543. Cpl_ThreadStart(PCPLDLGINFO pcpl)
  544. {
  545. HRESULT hres;
  546. LPDIRECTINPUTA pdia;
  547. hres = CoInitialize(0);
  548. if (SUCCEEDED(hres)) {
  549. hres = CreateDI(pcpl->fOle, pcpl->flCreate, (PPV)&pdia);
  550. if (SUCCEEDED(hres)) {
  551. hres = IDirectInput_QueryInterface(pdia,
  552. &IID_IDirectInputJoyConfig8,
  553. (PV)&pcpl->pdjc);
  554. if (SUCCEEDED(hres)) {
  555. Cpl_DoCpl(pcpl);
  556. if( pcpl->pdjc )
  557. IDirectInputJoyConfig_Release(pcpl->pdjc);
  558. } else {
  559. ThreadFailHres(pcpl->hdlgOwner, IDS_ERR_QICONFIG, hres);
  560. }
  561. pdia->lpVtbl->Release(pdia);
  562. } else {
  563. ThreadFailHres(pcpl->hdlgOwner, IDS_ERR_CREATEOBJ, hres);
  564. }
  565. CoUninitialize();
  566. } else {
  567. ThreadFailHres(pcpl->hdlgOwner, IDS_ERR_COINIT, hres);
  568. }
  569. Dary_Term(&pcpl->daryTypes);
  570. LocalFree(pcpl);
  571. return 0;
  572. }
  573. /*****************************************************************************
  574. *
  575. * Cpl_Create
  576. *
  577. * Spin a thread to create a DirectInput device interface.
  578. *
  579. *****************************************************************************/
  580. INT_PTR EXTERNAL
  581. Cpl_Create(HWND hdlg, BOOL fOle, UINT flCreate)
  582. {
  583. PCPLDLGINFO pcpl = LocalAlloc(LPTR, cbX(CPLDLGINFO));
  584. if (pcpl) {
  585. DWORD id;
  586. HANDLE h;
  587. pcpl->hdlgOwner = hdlg ;
  588. pcpl->fOle = fOle ;
  589. pcpl->flCreate = flCreate ;
  590. h = CreateThread(0, 0, Cpl_ThreadStart, pcpl, 0, &id);
  591. if (h) {
  592. ;
  593. } else {
  594. LocalFree(pcpl);
  595. pcpl = 0;
  596. }
  597. }
  598. return (INT_PTR)pcpl;
  599. }