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.

1665 lines
44 KiB

  1. /*****************************************************************************
  2. *
  3. * DIUtil.c
  4. *
  5. * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Misc helper functions.
  10. *
  11. * Contents:
  12. *
  13. *
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflUtil
  23. /*****************************************************************************
  24. *
  25. * @doc INTERNAL
  26. *
  27. * @func LPCTSTR | _ParseHex |
  28. *
  29. * Parse a hex string encoding cb bytes (at most 4), then expect
  30. * the tchDelim to appear afterwards. If tchDelim is 0, then no
  31. * delimiter is expected.
  32. *
  33. * Store the result into the indicated LPBYTE (using only the
  34. * size requested), updating it, and return a pointer to the
  35. * next unparsed character, or 0 on error.
  36. *
  37. * If the incoming pointer is also 0, then return 0 immediately.
  38. *
  39. * @parm IN LPCTSTR | ptsz |
  40. *
  41. * The string to parse.
  42. *
  43. * @parm IN OUT LPBYTE * | ppb |
  44. *
  45. * Pointer to the address of the destination buffer.
  46. *
  47. * @parm IN int | cb |
  48. *
  49. * The size in bytes of the buffer.
  50. *
  51. * @parm IN TCHAR | tchDelim |
  52. *
  53. * The delimiter charater to end the sequence or zero if none is
  54. * expected.
  55. *
  56. * @returns
  57. *
  58. * Returns a pointer to the next unparsed character, or 0 on error.
  59. *
  60. * @comm
  61. * Stolen from TweakUI.
  62. *
  63. * Prefix takes a strong dislike to this function, reporting that
  64. * all callers could use uninitialized memory when the function
  65. * succeeds.
  66. * The problem appears to be that Prefix is unable to determine that
  67. * if the source string can successfully be read, the destination is
  68. * always completely filled (the whole passed destination size) with
  69. * the binary value of the source string. Since all callers always
  70. * pass the size of the variable to which the destination buffer
  71. * pointer points, the memory is always completely initialized but
  72. * it seems reasonable that Prefix would raise a warning.
  73. *
  74. *****************************************************************************/
  75. LPCTSTR INTERNAL
  76. _ParseHex(LPCTSTR ptsz, LPBYTE *ppb, int cb, TCHAR tchDelim)
  77. {
  78. if(ptsz)
  79. {
  80. int i = cb * 2;
  81. DWORD dwParse = 0;
  82. do
  83. {
  84. DWORD uch;
  85. uch = (TBYTE)*ptsz - TEXT('0');
  86. if(uch < 10)
  87. { /* a decimal digit */
  88. } else
  89. {
  90. uch = (*ptsz | 0x20) - TEXT('a');
  91. if(uch < 6)
  92. { /* a hex digit */
  93. uch += 10;
  94. } else
  95. {
  96. return 0; /* Parse error */
  97. }
  98. }
  99. dwParse = (dwParse << 4) + uch;
  100. ptsz++;
  101. } while(--i);
  102. if(tchDelim && *ptsz++ != tchDelim) return 0; /* Parse error */
  103. for(i = 0; i < cb; i++)
  104. {
  105. (*ppb)[i] = ((LPBYTE)&dwParse)[i];
  106. }
  107. *ppb += cb;
  108. }
  109. return ptsz;
  110. }
  111. /*****************************************************************************
  112. *
  113. * @doc INTERNAL
  114. *
  115. * @func BOOL | ParseGUID |
  116. *
  117. * Take a string and convert it into a GUID, return success/failure.
  118. *
  119. * @parm OUT LPGUID | lpGUID |
  120. *
  121. * Receives the parsed GUID on success.
  122. *
  123. * @parm IN LPCTSTR | ptsz |
  124. *
  125. * The string to parse. The format is
  126. *
  127. * { <lt>dword<gt> - <lt>word<gt> - <lt>word<gt>
  128. * - <lt>byte<gt> <lt>byte<gt>
  129. * - <lt>byte<gt> <lt>byte<gt> <lt>byte<gt>
  130. * <lt>byte<gt> <lt>byte<gt> <lt>byte<gt> }
  131. *
  132. * @returns
  133. *
  134. * Returns zero if <p ptszGUID> is not a valid GUID.
  135. *
  136. *
  137. * @comm
  138. *
  139. * Stolen from TweakUI.
  140. *
  141. *****************************************************************************/
  142. BOOL EXTERNAL
  143. ParseGUID(LPGUID pguid, LPCTSTR ptsz)
  144. {
  145. if(lstrlen(ptsz) == ctchGuid - 1 && *ptsz == TEXT('{'))
  146. {
  147. ptsz++;
  148. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 4, TEXT('-'));
  149. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  150. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  151. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  152. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('-'));
  153. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  154. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  155. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  156. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  157. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  158. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('}'));
  159. return (BOOL)(UINT_PTR)ptsz;
  160. } else
  161. {
  162. return 0;
  163. }
  164. }
  165. /*****************************************************************************
  166. *
  167. * @doc INTERNAL
  168. *
  169. * @func BOOL | ParseVIDPID |
  170. *
  171. * Take a string formatted as VID_%04&PID_%04.
  172. *
  173. * @parm OUT PUSHORT | puVID |
  174. *
  175. * Receives the parsed VID.
  176. *
  177. * @parm OUT PUSHORT | puPID |
  178. *
  179. * Receives the parsed PID.
  180. *
  181. * @parm IN LPCTSTR | ptsz |
  182. *
  183. *
  184. * @returns
  185. *
  186. * Returns zero on failure.
  187. *
  188. *
  189. * @comm
  190. *
  191. * Stolen from TweakUI.
  192. *
  193. *****************************************************************************/
  194. // VID _ XXXX & PID _ YYYY
  195. #define ctchVIDPID ( 3 + 1 + 4 + 1 + 3 + 1 + 4 )
  196. #define VID_ TEXT("VID_")
  197. #define VID_offset (3+1)
  198. #define PID_ TEXT("&PID_")
  199. #define PID_offset (3+1+4+1+3+1)
  200. BOOL EXTERNAL
  201. ParseVIDPID(PUSHORT puVID, PUSHORT puPID , LPCWSTR pwsz)
  202. {
  203. LPCTSTR ptsz;
  204. #ifndef UNICODE
  205. TCHAR tsz[MAX_JOYSTRING];
  206. UToT( tsz, cA(tsz), pwsz );
  207. ptsz = tsz;
  208. #else
  209. ptsz = pwsz;
  210. #endif
  211. if( _ParseHex(ptsz+VID_offset, (LPBYTE *)&puVID, 2, TEXT('&')) &&
  212. _ParseHex(ptsz+PID_offset, (LPBYTE *)&puPID, 2, 0) )
  213. {
  214. return TRUE;
  215. }
  216. return FALSE;
  217. }
  218. /*****************************************************************************
  219. *
  220. * @doc INTERNAL
  221. *
  222. * @func void | NameFromGUID |
  223. *
  224. * Convert a GUID into an ASCII string that will be used
  225. * to name it in the global namespace.
  226. *
  227. * We use the name "DirectInput.{guid}".
  228. *
  229. * Names are used in the following places:
  230. *
  231. * <c g_hmtxGlobal> names a mutex based on
  232. * <c IID_IDirectInputW> to gate access to the
  233. * shared memory block used to manage exclusive access.
  234. *
  235. * <c g_psop> names a shared memory block based on
  236. * <c IID_IDirectInputDeviceW> to record information
  237. * about exclusive access.
  238. *
  239. * <c g_hmtxJoy> names a mutex based on
  240. * <c IID_IDirectInputDevice2A> to gate access to the
  241. * shared memory block used to track joystick effects.
  242. *
  243. * @parm LPTSTR | ptszBuf |
  244. *
  245. * Output buffer to receive the converted name. It must
  246. * be <c ctchNameGuid> characters in size.
  247. *
  248. * @parm PCGUID | pguid |
  249. *
  250. * The GUID to convert.
  251. *
  252. *
  253. *****************************************************************************/
  254. #pragma BEGIN_CONST_DATA
  255. /* Note: If you change this string, you need to change ctchNameGuid to match */
  256. TCHAR c_tszNameFormat[] =
  257. TEXT("DirectInput.{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}");
  258. #pragma END_CONST_DATA
  259. void EXTERNAL
  260. NameFromGUID(LPTSTR ptszBuf, PCGUID pguid)
  261. {
  262. int ctch;
  263. ctch = wsprintf(ptszBuf, c_tszNameFormat,
  264. pguid->Data1, pguid->Data2, pguid->Data3,
  265. pguid->Data4[0], pguid->Data4[1],
  266. pguid->Data4[2], pguid->Data4[3],
  267. pguid->Data4[4], pguid->Data4[5],
  268. pguid->Data4[6], pguid->Data4[7]);
  269. AssertF(ctch == ctchNameGuid - 1);
  270. }
  271. /*****************************************************************************
  272. *
  273. * @doc INTERNAL
  274. *
  275. * @func PV | pvFindResource |
  276. *
  277. * Handy wrapper that finds and loads a resource.
  278. *
  279. * @parm IN HINSTANCE | hinst |
  280. *
  281. * Module instance handle.
  282. *
  283. * @parm DWORD | id |
  284. *
  285. * Resource identifier.
  286. *
  287. * @parm LPCTSTR | rt |
  288. *
  289. * Resource type.
  290. *
  291. * @returns
  292. *
  293. * Pointer to resource, or 0.
  294. *
  295. *****************************************************************************/
  296. PV EXTERNAL
  297. pvFindResource(HINSTANCE hinst, DWORD id, LPCTSTR rt)
  298. {
  299. HANDLE hrsrc;
  300. PV pv;
  301. hrsrc = FindResource(hinst, (LPTSTR)(LONG_PTR)(id), rt);
  302. if(hrsrc)
  303. {
  304. pv = LoadResource(hinst, hrsrc);
  305. } else
  306. {
  307. pv = 0;
  308. }
  309. return pv;
  310. }
  311. #ifndef UNICODE
  312. /*****************************************************************************
  313. *
  314. * @doc INTERNAL
  315. *
  316. * @func UINT | LoadStringW |
  317. *
  318. * Implementation of LoadStringW for platforms on which Unicode is
  319. * not supported. Does exactly what LoadStringW would've done
  320. * if it existed.
  321. *
  322. * @parm IN HINSTANCE | hinst |
  323. *
  324. * Module instance handle.
  325. *
  326. * @parm UINT | ids |
  327. *
  328. * String id number.
  329. *
  330. * @parm LPWSTR | pwsz |
  331. *
  332. * UNICODE output buffer.
  333. *
  334. * @parm UINT | cwch |
  335. *
  336. * Size of UNICODE output buffer.
  337. *
  338. * @returns
  339. *
  340. * Number of characters copied, not including terminating null.
  341. *
  342. * @comm
  343. *
  344. * Since the string is stored in the resource as UNICODE,
  345. * we just take it out ourselves. If we go through
  346. * <f LoadStringA>, we may end up losing characters due
  347. * to character set translation.
  348. *
  349. *****************************************************************************/
  350. int EXTERNAL
  351. LoadStringW(HINSTANCE hinst, UINT ids, LPWSTR pwsz, int cwch)
  352. {
  353. PWCHAR pwch;
  354. AssertF(cwch);
  355. ScrambleBuf(pwsz, cbCwch(cwch));
  356. /*
  357. * String tables are broken up into "bundles" of 16 strings each.
  358. */
  359. pwch = pvFindResource(hinst, 1 + ids / 16, RT_STRING);
  360. if(pwch)
  361. {
  362. /*
  363. * Now skip over the strings in the resource until we
  364. * hit the one we want. Each entry is a counted string,
  365. * just like Pascal.
  366. */
  367. for(ids %= 16; ids; ids--)
  368. {
  369. pwch += *pwch + 1;
  370. }
  371. cwch = min(*pwch, cwch - 1);
  372. memcpy(pwsz, pwch+1, cbCwch(cwch)); /* Copy the goo */
  373. } else
  374. {
  375. cwch = 0;
  376. }
  377. pwsz[cwch] = TEXT('\0'); /* Terminate the string */
  378. return cwch;
  379. }
  380. #endif
  381. /*****************************************************************************
  382. *
  383. * @doc INTERNAL
  384. *
  385. * @func void | GetNthString |
  386. *
  387. * Generate a generic numbered object name.
  388. *
  389. * @parm LPWSTR | pwsz |
  390. *
  391. * Output buffer of <c MAX_PATH> characters.
  392. *
  393. * @parm UINT | ids |
  394. *
  395. * String containing number template.
  396. *
  397. * @parm UINT | ui |
  398. *
  399. * Button number.
  400. *
  401. *****************************************************************************/
  402. void EXTERNAL
  403. GetNthString(LPWSTR pwsz, UINT ids, UINT ui)
  404. {
  405. TCHAR tsz[256];
  406. #ifndef UNICODE
  407. TCHAR tszOut[MAX_PATH];
  408. #endif
  409. LoadString(g_hinst, ids, tsz, cA(tsz));
  410. #ifdef UNICODE
  411. wsprintfW(pwsz, tsz, ui);
  412. #else
  413. wsprintf(tszOut, tsz, ui);
  414. TToU(pwsz, MAX_PATH, tszOut);
  415. #endif
  416. }
  417. /*****************************************************************************
  418. *
  419. * @doc INTERNAL
  420. *
  421. * @func HRESULT | hresRunControlPanel |
  422. *
  423. * Run the control panel with the specified applet.
  424. *
  425. * @parm LPCTSTR | ptszApplet |
  426. *
  427. * Applet name.
  428. *
  429. * @returns
  430. *
  431. * <c S_OK> if we started the applet.
  432. *
  433. *****************************************************************************/
  434. #pragma BEGIN_CONST_DATA
  435. TCHAR c_tszControlExeS[] = TEXT("control.exe %s");
  436. #pragma END_CONST_DATA
  437. HRESULT EXTERNAL
  438. hresRunControlPanel(LPCTSTR ptszCpl)
  439. {
  440. HRESULT hres;
  441. STARTUPINFO si;
  442. PROCESS_INFORMATION pi;
  443. TCHAR tsz[MAX_PATH];
  444. EnterProc(hresRunControlPanel, (_ "s", ptszCpl));
  445. ZeroX(si);
  446. si.cb = cbX(si);
  447. wsprintf(tsz, c_tszControlExeS, ptszCpl);
  448. if(CreateProcess(0, tsz, 0, 0, 0, 0, 0, 0, &si, &pi))
  449. {
  450. CloseHandle(pi.hProcess);
  451. CloseHandle(pi.hThread);
  452. hres = S_OK;
  453. } else
  454. {
  455. hres = hresLe(GetLastError());
  456. }
  457. ExitOleProc();
  458. return hres;
  459. }
  460. /*****************************************************************************
  461. *
  462. * @doc INTERNAL
  463. *
  464. * @func void | ObjectInfoWToA |
  465. *
  466. * Convert a <t DIDEVICEOBJECTINSTANCEW>
  467. * to a <t DIDEVICEOBJECTINSTANCE_DX3A>
  468. * or a <t DIDEVICEOBJECTINSTANCE_DX5A>.
  469. *
  470. * @parm LPDIDIDEVICEOBJECTINSTANCEA | pdoiA |
  471. *
  472. * Destination.
  473. *
  474. * @parm LPCDIDIDEVICEOBJECTINSTANCEW | pdoiW |
  475. *
  476. * Source.
  477. *
  478. *****************************************************************************/
  479. void EXTERNAL
  480. ObjectInfoWToA(LPDIDEVICEOBJECTINSTANCEA pdoiA,
  481. LPCDIDEVICEOBJECTINSTANCEW pdoiW)
  482. {
  483. EnterProc(ObjectInfoWToA, (_ "pp", pdoiA, pdoiW));
  484. AssertF(pdoiW->dwSize == sizeof(DIDEVICEOBJECTINSTANCEW));
  485. AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEA(pdoiA->dwSize));
  486. pdoiA->guidType = pdoiW->guidType;
  487. pdoiA->dwOfs = pdoiW->dwOfs;
  488. pdoiA->dwType = pdoiW->dwType;
  489. pdoiA->dwFlags = pdoiW->dwFlags;
  490. UToA(pdoiA->tszName, cA(pdoiA->tszName), pdoiW->tszName);
  491. if(pdoiA->dwSize >= cbX(DIDEVICEOBJECTINSTANCE_DX5A))
  492. {
  493. pdoiA->dwFFMaxForce = pdoiW->dwFFMaxForce;
  494. pdoiA->dwFFForceResolution = pdoiW->dwFFForceResolution;
  495. pdoiA->wCollectionNumber = pdoiW->wCollectionNumber;
  496. pdoiA->wDesignatorIndex = pdoiW->wDesignatorIndex;
  497. pdoiA->wUsagePage = pdoiW->wUsagePage;
  498. pdoiA->wUsage = pdoiW->wUsage;
  499. pdoiA->dwDimension = pdoiW->dwDimension;
  500. pdoiA->wExponent = pdoiW->wExponent;
  501. pdoiA->wReportId = pdoiW->wReportId;
  502. }
  503. ExitProc();
  504. }
  505. /*****************************************************************************
  506. *
  507. * @doc INTERNAL
  508. *
  509. * @func void | EffectInfoWToA |
  510. *
  511. * Convert a <t DIEFFECTINFOW> to a <t DIEFFECTINFOA>
  512. *
  513. * @parm LPDIEFFECTINFOA | pdeiA |
  514. *
  515. * Destination.
  516. *
  517. * @parm LPCDIEFFECTINFOW | pdeiW |
  518. *
  519. * Source.
  520. *
  521. *****************************************************************************/
  522. void EXTERNAL
  523. EffectInfoWToA(LPDIEFFECTINFOA pdeiA, LPCDIEFFECTINFOW pdeiW)
  524. {
  525. EnterProc(EffectInfoWToA, (_ "pp", pdeiA, pdeiW));
  526. AssertF(pdeiW->dwSize == sizeof(DIEFFECTINFOW));
  527. AssertF(pdeiA->dwSize == cbX(*pdeiA));
  528. pdeiA->guid = pdeiW->guid;
  529. pdeiA->dwEffType = pdeiW->dwEffType;
  530. pdeiA->dwStaticParams = pdeiW->dwStaticParams;
  531. pdeiA->dwDynamicParams = pdeiW->dwDynamicParams;
  532. UToA(pdeiA->tszName, cA(pdeiA->tszName), pdeiW->tszName);
  533. ExitProc();
  534. }
  535. /*****************************************************************************
  536. *
  537. * @doc INTERNAL
  538. *
  539. * @func HRESULT | hresValidInstanceVer |
  540. *
  541. * Check the <t HINSTANCE> and version number received from
  542. * an application.
  543. *
  544. * @parm HINSTANCE | hinst |
  545. *
  546. * Purported module instance handle.
  547. *
  548. * @parm DWORD | dwVersion |
  549. *
  550. * Version the application is asking for.
  551. *
  552. *****************************************************************************/
  553. HRESULT EXTERNAL
  554. hresValidInstanceVer_(HINSTANCE hinst, DWORD dwVersion, LPCSTR s_szProc)
  555. {
  556. HRESULT hres;
  557. TCHAR tszScratch[4];
  558. EnterProcS(hresValidInstanceVer, (_ "xxs", hinst, dwVersion, s_szProc));
  559. /*
  560. * You would think that passing a zero-sized buffer to
  561. * GetModuleFileName would return the necessary buffer size.
  562. *
  563. * You would be right. Except that the Win95 validation layer
  564. * doesn't realize that this was a valid scenario, so the call
  565. * fails in the validation layer and never reached Kernel.
  566. *
  567. * So we read it into a small scratch buffer. The scratch buffer
  568. * must be at least 2 characters; if we passed only 1, then
  569. * GetModuleFileName won't be able to write any characters and
  570. * will return 0.
  571. *
  572. * Now it turns out that there's a bug in NT where, if you
  573. * pass a buffer size of 4, but the actual name is longer than
  574. * 4, it writes 4 characters, PLUS A NULL TERMINATOR, thereby
  575. * smashing your stack and making you fault randomly.
  576. *
  577. * I spent two hours trying to figure that out.
  578. *
  579. * Therefore, you must pass one *less* than the buffer size
  580. * to GetModuleFileName, because it will overwrite your buffer
  581. * by one.
  582. */
  583. if( ( hinst != 0 )
  584. && GetModuleFileName(hinst, tszScratch, cA(tszScratch) - 1) )
  585. {
  586. if(dwVersion == DIRECTINPUT_INTERNAL_VERSION)
  587. {
  588. hres = S_OK;
  589. } else if ( dwVersion == 0 ) {
  590. RPF("%s: DinputInput object has not been initialized, or the version is given as 0.",
  591. s_szProc);
  592. hres = DIERR_NOTINITIALIZED;
  593. } else if(dwVersion < DIRECTINPUT_VERSION)
  594. {
  595. RPF("%s: Incorrect dwVersion(0x%x); program was written with beta SDK. This version 0x%x",
  596. s_szProc, dwVersion, DIRECTINPUT_VERSION);
  597. hres = DIERR_BETADIRECTINPUTVERSION;
  598. } else
  599. {
  600. RPF("%s: Incorrect dwVersion(0x%x); program needs newer version of dinput. This version 0x%x",
  601. s_szProc, dwVersion, DIRECTINPUT_VERSION);
  602. hres = DIERR_OLDDIRECTINPUTVERSION;
  603. }
  604. } else
  605. {
  606. RPF("%s: Invalid HINSTANCE", s_szProc);
  607. hres = E_INVALIDARG;
  608. }
  609. ExitOleProc();
  610. return hres;
  611. }
  612. /*****************************************************************************
  613. *
  614. * @doc INTERNAL
  615. *
  616. * @func HRESULT | DupEventHandle |
  617. *
  618. * Duplicate an event handle intra-process-ly. If the incoming
  619. * handle is NULL, then so is the output handle (and the call
  620. * succeeds).
  621. *
  622. * @parm HANDLE | h |
  623. *
  624. * Source handle.
  625. *
  626. * @parm LPHANDLE | phOut |
  627. *
  628. * Receives output handle.
  629. *
  630. *****************************************************************************/
  631. HRESULT EXTERNAL
  632. DupEventHandle(HANDLE h, LPHANDLE phOut)
  633. {
  634. HRESULT hres;
  635. EnterProc(DupEventHandle, (_ "p", h));
  636. if(h)
  637. {
  638. HANDLE hProcessMe = GetCurrentProcess();
  639. if(DuplicateHandle(hProcessMe, h, hProcessMe, phOut,
  640. EVENT_MODIFY_STATE, 0, 0))
  641. {
  642. hres = S_OK;
  643. } else
  644. {
  645. hres = hresLe(GetLastError());
  646. }
  647. } else
  648. {
  649. *phOut = h;
  650. hres = S_OK;
  651. }
  652. ExitOleProc();
  653. return hres;
  654. }
  655. /*****************************************************************************
  656. *
  657. * @doc INTERNAL
  658. *
  659. * @func DWORD | GetWindowPid |
  660. *
  661. * Simple wrapper that returns the PID of a window.
  662. *
  663. * Here is also where we do goofy hacks for DOS boxes
  664. * on Win95.
  665. *
  666. * @parm HWND | hwnd |
  667. *
  668. * Window handle.
  669. *
  670. * @returns
  671. *
  672. * PID or 0.
  673. *
  674. *****************************************************************************/
  675. DWORD EXTERNAL
  676. GetWindowPid(HWND hwnd)
  677. {
  678. DWORD pid;
  679. if(IsWindow(hwnd) &&
  680. GetWindowThreadProcessId(hwnd, &pid) )
  681. {
  682. #ifndef WINNT
  683. /*
  684. * The Winoldap console window belongs to another
  685. * process but Win95 lies and says that it belongs
  686. * to you but it doesn't.
  687. */
  688. if ( GetProp(hwnd, TEXT("flWinOldAp")) != 0 )
  689. {
  690. pid = 0;
  691. }
  692. #endif
  693. } else
  694. {
  695. pid = 0;
  696. }
  697. return pid;
  698. }
  699. /*****************************************************************************
  700. *
  701. * @doc INTERNAL
  702. *
  703. * @func HRESULT | hresDupPtszPptsz |
  704. *
  705. * OLEish version of strdup.
  706. *
  707. * @parm LPCTSTR | ptszSrc |
  708. *
  709. * Source string being duplicated.
  710. *
  711. * @parm LPTSTR * | pptszDst |
  712. *
  713. * Receives the duplicated string.
  714. *
  715. * @returns
  716. *
  717. * <c S_OK> or an error code.
  718. *
  719. *****************************************************************************/
  720. HRESULT EXTERNAL
  721. hresDupPtszPptsz(LPCTSTR ptszSrc, LPTSTR *pptszDst)
  722. {
  723. HRESULT hres;
  724. hres = AllocCbPpv(cbCtch(lstrlen(ptszSrc) + 1), pptszDst);
  725. if(SUCCEEDED(hres))
  726. {
  727. lstrcpy(*pptszDst, ptszSrc);
  728. hres = S_OK;
  729. }
  730. return hres;
  731. }
  732. /*****************************************************************************
  733. *
  734. * @doc INTERNAL
  735. *
  736. * @func BOOL | fInitializeCriticalSection |
  737. *
  738. * Initialize the give critical section, returning 0 if an exception
  739. * is thrown, else 0.
  740. *
  741. * @parm LPCRITICAL_SECTION | pCritSec |
  742. *
  743. * Pointer to an uninitialized critical section.
  744. *
  745. *****************************************************************************/
  746. BOOL EXTERNAL
  747. fInitializeCriticalSection(LPCRITICAL_SECTION pCritSec)
  748. {
  749. BOOL fres = 1;
  750. EnterProc(fInitializeCriticalSection, (_ "" ));
  751. AssertF( pCritSec );
  752. __try
  753. {
  754. InitializeCriticalSection( pCritSec );
  755. }
  756. __except( EXCEPTION_EXECUTE_HANDLER )
  757. {
  758. fres = 0;
  759. }
  760. ExitProcF( fres );
  761. return fres;
  762. }
  763. /*****************************************************************************
  764. *
  765. * @doc INTERNAL
  766. *
  767. * @func void | DiCharUpperW |
  768. *
  769. * This function converts a wide-character string or a single wide-character
  770. * to uppercase. Since Win9x doesn't implement CharUpperW, we have to implement
  771. * ourselves.
  772. *
  773. * @parm LPWSTR | pwsz |
  774. *
  775. * The string to be converted
  776. *
  777. * @returns
  778. *
  779. * void
  780. *
  781. *****************************************************************************/
  782. void EXTERNAL
  783. DiCharUpperW(LPWSTR pwsz)
  784. {
  785. int idx;
  786. int iLen = lstrlenW(pwsz);
  787. #define DIFF (L'a' - L'A')
  788. for( idx=0; idx<iLen; idx++ )
  789. {
  790. if( (pwsz[idx] >= L'a') && (pwsz[idx] <= L'z') ){
  791. pwsz[idx] -= DIFF;
  792. }
  793. }
  794. #undef DIFF
  795. }
  796. /*****************************************************************************
  797. *
  798. * @doc INTERNAL
  799. *
  800. * @func void | ptrSwap |
  801. *
  802. * swaps the pointers pointed to by the two parameters
  803. *
  804. * @parm void ** | ppA |
  805. *
  806. * pointer to first pointer
  807. *
  808. * @parm void ** | ppB |
  809. *
  810. * pointer to second pointer
  811. *
  812. *****************************************************************************/
  813. void __inline ptrSwap( PPV ppA, PPV ppB )
  814. {
  815. PV pTemp = *ppB;
  816. *ppB = *ppA;
  817. *ppA = pTemp;
  818. }
  819. /*****************************************************************************
  820. *
  821. * @doc INTERNAL
  822. *
  823. * @func void | ptrPartialQSort |
  824. *
  825. * Partially sort the passed (sub)set of an array of pointers to
  826. * structures such that resultant array is contains sub arrays which
  827. * are sorted with respect to each other though locally unsorted.
  828. * Once partially sorted, a simple sort may be used to complete the
  829. * sort.
  830. *
  831. * @parm void ** | ppL |
  832. * Pointer to lowest element in the (sub)array to sort
  833. *
  834. * @parm void ** | ppR |
  835. * Pointer to highest element in the (sub)array to sort
  836. *
  837. * @parm COMP_FUNC | fpCompare |
  838. * Pointer to function returning analog of strcmp for strings, but
  839. * supplied by caller for comparing elements of the array.
  840. *
  841. *****************************************************************************/
  842. void ptrPartialQSort
  843. (
  844. PPV ppL,
  845. PPV ppR,
  846. COMP_FUNC fpCompare
  847. )
  848. {
  849. while( ( ppR - ppL ) > 8 )
  850. {
  851. /*
  852. * First pick a pivot by sorting the first last and middle
  853. * values in the sub array.
  854. */
  855. {
  856. PPV ppMid = ppL + ( ( ppR - ppL ) / 2 );
  857. if( fpCompare( *ppL, *ppMid ) > 0 )
  858. {
  859. ptrSwap( ppL, ppMid );
  860. }
  861. if( fpCompare( *ppL, *ppR ) > 0 )
  862. {
  863. ptrSwap( ppL, ppR );
  864. }
  865. if( fpCompare( *ppMid, *ppR ) > 0 )
  866. {
  867. ptrSwap( ppMid, ppR );
  868. }
  869. /*
  870. * Now we have a reasonable chance of a good pivot, move it
  871. * out of the way.
  872. */
  873. ptrSwap( ppMid, ppR-1 );
  874. }
  875. /*
  876. * Now sort the remainder into high and low parts
  877. */
  878. {
  879. PPV ppHi = ppR - 1;
  880. PV pPivot = *ppHi;
  881. PPV ppLo = ppL;
  882. for( ;; )
  883. {
  884. while( fpCompare( *(++ppLo), pPivot ) < 0 );
  885. while( fpCompare( *(--ppHi), pPivot ) > 0 );
  886. if( ppLo >= ppHi ) break;
  887. ptrSwap( ppLo, ppHi );
  888. }
  889. /*
  890. * Put the pivot back between the two parts as it must be in
  891. * order relative to all the items on each side of it.
  892. */
  893. ptrSwap( ppLo, ppR - 1 );
  894. /*
  895. * Recurse on the smaller part and continue with the larger
  896. */
  897. if( ppLo - ppL > ppR - ppLo )
  898. {
  899. /*
  900. * Left part is larger
  901. */
  902. ptrPartialQSort( ppLo + 1, ppR, fpCompare );
  903. ppR = ppLo - 1;
  904. }
  905. else
  906. {
  907. /*
  908. * Right part is larger
  909. */
  910. ptrPartialQSort( ppL, ppLo - 1, fpCompare );
  911. ppL = ppLo + 1;
  912. }
  913. }
  914. }
  915. }
  916. /*****************************************************************************
  917. *
  918. * @doc INTERNAL
  919. *
  920. * @func void | ptrInsertSort |
  921. *
  922. * Sort the passed (sub)set of an array of pointers to structures.
  923. * This sort is not suitable for large arrays.
  924. *
  925. * @parm void ** | ppBase |
  926. * Pointer to lowest element in the (sub)array to sort
  927. *
  928. * @parm void ** | ppLast |
  929. * Pointer to highest element in the (sub)array to sort
  930. *
  931. * @parm COMP_FUNC | fpCompare |
  932. * Pointer to function returning analog of strcmp for strings, but
  933. * supplied by caller for comparing elements of the array.
  934. *
  935. *****************************************************************************/
  936. void ptrInsertSort
  937. (
  938. PPV ppBase,
  939. PPV ppLast,
  940. COMP_FUNC fpCompare
  941. )
  942. {
  943. PPV ppOuter;
  944. for( ppOuter = ppBase + 1; ppOuter <= ppLast; ppOuter++ )
  945. {
  946. PV pTemp = *ppOuter;
  947. PPV ppInner;
  948. for( ppInner = ppOuter - 1; ppInner >= ppBase; ppInner-- )
  949. {
  950. if( fpCompare( pTemp, *ppInner ) > 0 )
  951. {
  952. *(ppInner+1) = *ppInner;
  953. }
  954. else
  955. {
  956. break;
  957. }
  958. }
  959. *(ppInner+1) = pTemp;
  960. }
  961. }
  962. /*****************************************************************************
  963. *
  964. * @doc INTERNAL
  965. *
  966. * @func void | swap |
  967. *
  968. * swaps the two array elements of size width
  969. *
  970. * @parm char * | a |
  971. *
  972. * pointer to first elements to swap
  973. *
  974. * @parm char * | b |
  975. *
  976. * pointer to second elements to swap
  977. *
  978. * @parm unsigned | width |
  979. *
  980. * width in bytes of each array element
  981. *
  982. * @returns
  983. *
  984. * void
  985. *
  986. *****************************************************************************/
  987. static void __cdecl swap (
  988. char *a,
  989. char *b,
  990. unsigned width
  991. )
  992. {
  993. char tmp;
  994. if ( a != b )
  995. {
  996. /* Do the swap one character at a time to avoid potential alignment
  997. problems. */
  998. while ( width-- ) {
  999. tmp = *a;
  1000. *a++ = *b;
  1001. *b++ = tmp;
  1002. }
  1003. }
  1004. }
  1005. /*****************************************************************************
  1006. *
  1007. * @doc INTERNAL
  1008. *
  1009. * @func void | shortsort |
  1010. *
  1011. * sorts the sub-array of elements between lo and hi (inclusive)
  1012. * side effects: sorts in place
  1013. * assumes that lo is less than hi
  1014. *
  1015. * @parm char * | lo |
  1016. * pointer to low element to sort
  1017. *
  1018. * @parm char * | hi |
  1019. * pointer to high element to sort
  1020. *
  1021. * @parm unsigned | width |
  1022. * width in bytes of each array element
  1023. *
  1024. * @parm int (*func)() | comp |
  1025. * pointer to function returning analog of strcmp for
  1026. * strings, but supplied by user for comparing the array elements.
  1027. * it accepts 2 pointers to elements and returns neg if 1 lt 2, 0 if
  1028. * 1 eq 2, pos if 1 gt 2.
  1029. *
  1030. * @returns
  1031. *
  1032. * void
  1033. *
  1034. *****************************************************************************/
  1035. void __cdecl shortsort (
  1036. char *lo,
  1037. char *hi,
  1038. unsigned width,
  1039. int (__cdecl *comp)(const void *, const void *)
  1040. )
  1041. {
  1042. char *p, *max;
  1043. /* Note: in assertions below, i and j are alway inside original bound of
  1044. array to sort. */
  1045. while (hi > lo) {
  1046. /* A[i] <= A[j] for i <= j, j > hi */
  1047. max = lo;
  1048. for (p = lo+width; p <= hi; p += width) {
  1049. /* A[i] <= A[max] for lo <= i < p */
  1050. if (comp(p, max) > 0) {
  1051. max = p;
  1052. }
  1053. /* A[i] <= A[max] for lo <= i <= p */
  1054. }
  1055. /* A[i] <= A[max] for lo <= i <= hi */
  1056. swap(max, hi, width);
  1057. /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
  1058. hi -= width;
  1059. /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
  1060. }
  1061. /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
  1062. so array is sorted */
  1063. }
  1064. /*****************************************************************************
  1065. *
  1066. * @doc INTERNAL
  1067. *
  1068. * @func HRESULT | GetWideUserName |
  1069. *
  1070. * Get a wide string for a user.
  1071. * If both of the IN parameters are NULL, memory is allocated for a
  1072. * MULTI_SZ string and set to the output pointer. The sting is
  1073. * filled with the current user name if available, else a localizable
  1074. * default sting.
  1075. * If a UNICODE name is supplied, it is validated and assigned to the
  1076. * output string pointer.
  1077. * If an ANSI name is supplied, it is validated and memory is
  1078. * allocated into which the translated SZ UNICODE name is written.
  1079. * Note it is the caller's responsibility to free the memory in
  1080. * either of the cases in which is is allocated.
  1081. * Also note that in the case of an error no memory needs to be
  1082. * freed.
  1083. *
  1084. * @parm LPCSTR | lpszUserName |
  1085. *
  1086. * A specific ANSI user name.
  1087. *
  1088. * @parm LPCWSTR | lpwszUserName |
  1089. *
  1090. * A specific UNICODE user name.
  1091. *
  1092. * @parm LPWSTR* | ppwszGoodUserName |
  1093. *
  1094. * A pointer to a pointer to the wide user name.
  1095. *
  1096. * @returns
  1097. *
  1098. * <c S_OK> if the output string is valid
  1099. * or an error code reflecting what went wrong.
  1100. *
  1101. *****************************************************************************/
  1102. STDMETHODIMP GetWideUserName
  1103. (
  1104. IN LPCSTR lpszUserName,
  1105. IN LPCWSTR lpwszUserName,
  1106. OUT LPWSTR *ppwszGoodUserName
  1107. )
  1108. {
  1109. HRESULT hres = S_OK;
  1110. EnterProcI(GetWideUserName, (_ "AW", lpszUserName, lpwszUserName ));
  1111. if( lpwszUserName )
  1112. {
  1113. /*
  1114. * Just validate and copy the pointer
  1115. */
  1116. if( SUCCEEDED( hres = hresFullValidReadStrW( lpwszUserName, UNLEN+1, 2 ) ) )
  1117. {
  1118. *ppwszGoodUserName = (LPWSTR)lpwszUserName;
  1119. }
  1120. }
  1121. else if( lpszUserName )
  1122. {
  1123. /*
  1124. * If an ANSI user name has been passed translate it
  1125. */
  1126. if( SUCCEEDED( hres = hresFullValidReadStrA( lpszUserName, UNLEN+1, 1 ) ) )
  1127. {
  1128. int UserNameLen = lstrlenA( lpszUserName ) + 1;
  1129. hres = AllocCbPpv( cbX(*lpwszUserName) * UserNameLen, ppwszGoodUserName );
  1130. if( SUCCEEDED( hres ) )
  1131. {
  1132. AToU( *ppwszGoodUserName, UserNameLen, lpszUserName );
  1133. }
  1134. }
  1135. }
  1136. else
  1137. {
  1138. DWORD dwUserNameLen = UNLEN + 1;
  1139. #ifdef WINNT
  1140. hres = AllocCbPpv( (dwUserNameLen+1) * 2, ppwszGoodUserName );
  1141. if( SUCCEEDED( hres ) )
  1142. {
  1143. if( GetUserNameW( *ppwszGoodUserName, &dwUserNameLen ) )
  1144. {
  1145. #else
  1146. hres = AllocCbPpv( (dwUserNameLen+1) * 3, ppwszGoodUserName );
  1147. if( SUCCEEDED( hres ) )
  1148. {
  1149. if( GetUserNameA( (PCHAR)(&((*ppwszGoodUserName)[UNLEN+2])), &dwUserNameLen ) )
  1150. {
  1151. AToU( *ppwszGoodUserName, dwUserNameLen, (PCHAR)(&((*ppwszGoodUserName)[UNLEN+2])) );
  1152. #endif
  1153. /*
  1154. * We allocated _and_zeroed_ an extra wchar for double
  1155. * termination. Assert nobody messed it up and then
  1156. * make sure we don't free the extra.
  1157. */
  1158. AssertF( (*ppwszGoodUserName)[dwUserNameLen] == L'\0' );
  1159. dwUserNameLen++;
  1160. }
  1161. else
  1162. {
  1163. /*
  1164. * If we felt the need, we could follow this recovery path
  1165. * only if ( GetLastError() == ERROR_NOT_LOGGED_ON ) and
  1166. * report some error or follow some alternate recovery
  1167. * otherwise but unless a problem is found with always using
  1168. * the default, this seems safer.
  1169. */
  1170. dwUserNameLen = LoadStringW( g_hinst, IDS_DEFAULTUSER, *ppwszGoodUserName, UNLEN+1 );
  1171. if( dwUserNameLen )
  1172. {
  1173. /*
  1174. * Double terminate the string for ConfigureDevices
  1175. */
  1176. dwUserNameLen += 2;
  1177. (*ppwszGoodUserName)[dwUserNameLen-1] = L'\0';
  1178. SquirtSqflPtszV(sqflUtil | sqflBenign,
  1179. TEXT("Failed to GetUserName, using default") );
  1180. }
  1181. else
  1182. {
  1183. SquirtSqflPtszV(sqflUtil | sqflError,
  1184. TEXT("Failed to GetUserName and default, le = %d"), GetLastError() );
  1185. hres = E_FAIL;
  1186. }
  1187. }
  1188. /*
  1189. * Chances are we have way more space than we need
  1190. * NOTE, in the failure case, this reallocs to zero thus
  1191. * freeing the memory.
  1192. * If we have a valid sting, failure to realloc just means
  1193. * using more memory that we need to for a little while.
  1194. * If we don't have a string, ReallocCbPpv cannot fail.
  1195. */
  1196. ReallocCbPpv( dwUserNameLen*2, ppwszGoodUserName );
  1197. #ifndef WINNT
  1198. }
  1199. }
  1200. #else /* Reduce bracket matching insanity even though these don't match */
  1201. }
  1202. }
  1203. #endif
  1204. #ifdef XDEBUG
  1205. if( SUCCEEDED( hres ) )
  1206. {
  1207. AssertF( SUCCEEDED( hresFullValidReadStrW( *ppwszGoodUserName, UNLEN+1, 2 ) ) );
  1208. }
  1209. else
  1210. {
  1211. /*
  1212. * If a passed string was invalid, we never allocated any memory so
  1213. * don't worry about this uninitialized output value for this error.
  1214. */
  1215. if( hres != E_INVALIDARG )
  1216. {
  1217. AssertF( *ppwszGoodUserName == NULL );
  1218. }
  1219. }
  1220. #endif
  1221. ExitOleProc();
  1222. return hres;
  1223. }
  1224. /*****************************************************************************
  1225. *
  1226. * @doc INTERNAL
  1227. *
  1228. * @func DWORD | GetValidDI8DevType |
  1229. *
  1230. * Return a valid type and subtype based on the ones passed, the
  1231. * number of buttons and axis/pov caps.
  1232. *
  1233. * @parm DWORD | dwDevType |
  1234. *
  1235. * Value to be checked, only the type and sub type bits are used.
  1236. *
  1237. * @parm DWORD | dwNumButtons |
  1238. *
  1239. * Number of buttons on device, only used when checking devices mja
  1240. *
  1241. * @parm DWORD | dwFlags |
  1242. *
  1243. * Flags determining any axis/pov requirements. mja
  1244. *
  1245. * @returns
  1246. *
  1247. * Zero if the type and subtype are not a valid combination for DX8.
  1248. *
  1249. *
  1250. *****************************************************************************/
  1251. #pragma BEGIN_CONST_DATA
  1252. #define MAKE_DI8TYPE_LIMITS( type ) { type##_MIN, type##_MAX, type##_MIN_BUTTONS, type##_MIN_CAPS },
  1253. struct
  1254. {
  1255. BYTE SubTypeMin;
  1256. BYTE SubTypeMax;
  1257. BYTE MinButtons;
  1258. BYTE HWCaps;
  1259. } c_rgSubTypeDetails[] = {
  1260. { 0, 1, 0, 0 }, /* DI8DEVTYPEDEVICE has no subtype or limits */
  1261. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEMOUSE )
  1262. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEKEYBOARD )
  1263. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEJOYSTICK )
  1264. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEGAMEPAD )
  1265. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEDRIVING )
  1266. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEFLIGHT )
  1267. MAKE_DI8TYPE_LIMITS( DI8DEVTYPE1STPERSON )
  1268. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEDEVICECTRL )
  1269. MAKE_DI8TYPE_LIMITS( DI8DEVTYPESCREENPTR )
  1270. MAKE_DI8TYPE_LIMITS( DI8DEVTYPEREMOTE )
  1271. MAKE_DI8TYPE_LIMITS( DI8DEVTYPESUPPLEMENTAL )
  1272. };
  1273. #undef MAKE_DI8TYPE_LIMITS
  1274. #pragma END_CONST_DATA
  1275. DWORD EXTERNAL GetValidDI8DevType
  1276. (
  1277. DWORD dwDevType,
  1278. DWORD dwNumButtons,
  1279. DWORD dwFlags
  1280. )
  1281. {
  1282. BYTE bDevTypeIdx = GET_DIDEVICE_TYPE( dwDevType ) - DI8DEVTYPE_MIN;
  1283. CAssertF( cA( c_rgSubTypeDetails ) == DI8DEVTYPE_MAX - DI8DEVTYPE_MIN );
  1284. if( ( (__int8)bDevTypeIdx >= 0 )
  1285. && ( bDevTypeIdx < DI8DEVTYPE_MAX - DI8DEVTYPE_MIN )
  1286. && ( GET_DIDEVICE_SUBTYPE( dwDevType ) >= c_rgSubTypeDetails[bDevTypeIdx].SubTypeMin )
  1287. && ( GET_DIDEVICE_SUBTYPE( dwDevType ) < c_rgSubTypeDetails[bDevTypeIdx].SubTypeMax ) )
  1288. {
  1289. /*
  1290. * MinButtons of zero means no minimum buttons OR caps
  1291. */
  1292. if( !c_rgSubTypeDetails[bDevTypeIdx].MinButtons
  1293. || ( ( dwNumButtons >= c_rgSubTypeDetails[bDevTypeIdx].MinButtons )
  1294. && ( ( dwFlags & c_rgSubTypeDetails[bDevTypeIdx].HWCaps )
  1295. == c_rgSubTypeDetails[bDevTypeIdx].HWCaps ) ) )
  1296. {
  1297. return dwDevType & ( DIDEVTYPE_TYPEMASK | DIDEVTYPE_SUBTYPEMASK );
  1298. }
  1299. else
  1300. {
  1301. return ( dwDevType & DIDEVTYPE_TYPEMASK ) | MAKE_DIDEVICE_TYPE( 0, DI8DEVTYPE_LIMITEDGAMESUBTYPE );
  1302. }
  1303. }
  1304. else
  1305. {
  1306. return 0;
  1307. }
  1308. }
  1309. /*****************************************************************************
  1310. *
  1311. * @doc INTERNAL
  1312. *
  1313. * @func BOOL | DIGetKeyNameTextHelper |
  1314. *
  1315. * return key name of a key.
  1316. *
  1317. * @parm IN UINT | uiScanCode |
  1318. *
  1319. * scan code of the key.
  1320. *
  1321. * @parm OUT LPWSTR | lpwszName |
  1322. *
  1323. * The buffer that will hold the returned key name.
  1324. *
  1325. * @parm int | nSize |
  1326. *
  1327. * The length of lpwszName.
  1328. *
  1329. * @returns
  1330. *
  1331. * TRUE - if successfully get a key name.
  1332. * FALSE - otherwise
  1333. *
  1334. *****************************************************************************/
  1335. BOOL DIGetKeyNameTextHelper( UINT uiScanCode, LPWSTR lpwszName, int nSize )
  1336. {
  1337. HKL hkl;
  1338. DWORD dwThread, dwProcessId;
  1339. UINT uiVk;
  1340. BYTE kbuf[256] = "";
  1341. int nResult;
  1342. // we only want to use this method to resolve alpha & punct keys.
  1343. if( uiScanCode > 0x53 ) {
  1344. return FALSE;
  1345. }
  1346. //Get the active window's thread
  1347. dwThread=GetWindowThreadProcessId(GetActiveWindow(), &dwProcessId);
  1348. //Get the active window's keyboard layout
  1349. hkl=GetKeyboardLayout(dwThread);
  1350. uiVk = MapVirtualKeyEx( uiScanCode, 3, hkl );
  1351. #ifdef WINNT
  1352. nResult = ToUnicodeEx(uiVk, uiScanCode, kbuf, lpwszName, nSize, 0, hkl);
  1353. #else
  1354. nResult = ToAsciiEx(uiVk, uiScanCode, kbuf, lpwszName, 0, hkl);
  1355. #endif
  1356. if( (nResult != 1) ||
  1357. (!iswalpha(lpwszName[0]) && !iswpunct(lpwszName[0])) )
  1358. {
  1359. return FALSE;
  1360. } else {
  1361. WCHAR wc;
  1362. wc = towupper( lpwszName[0] );
  1363. lpwszName[0] = wc;
  1364. }
  1365. return TRUE;
  1366. }
  1367. /*****************************************************************************
  1368. *
  1369. * @doc INTERNAL
  1370. *
  1371. * @func HRESULE | DIGetKeyNameText |
  1372. *
  1373. * return key name of a key.
  1374. *
  1375. * @parm IN UINT | index |
  1376. *
  1377. * the index of g_rgbKbdRMap[].
  1378. *
  1379. * @parm IN DWORD | dwDevType |
  1380. *
  1381. * the DevType of the key.
  1382. *
  1383. * @parm OUT LPWSTR | lpwszName |
  1384. *
  1385. * The buffer that will hold the returned key name.
  1386. *
  1387. * @parm int | nSize |
  1388. *
  1389. * The length of lpwszName.
  1390. *
  1391. * @returns
  1392. *
  1393. * S_OK - if successfully get a key name.
  1394. * DIERR_OBJECTNOTFOUND - otherwise
  1395. *
  1396. *****************************************************************************/
  1397. HRESULT DIGetKeyNameText( UINT index, DWORD dwDevType, LPWSTR lpwszName, int nSize )
  1398. {
  1399. HRESULT hres;
  1400. DWORD dwScancode;
  1401. LONG lp;
  1402. DWORD dw;
  1403. BOOL fSpecKey = FALSE;
  1404. DWORD dwSpecKeys[] = { 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, //number
  1405. 0x90, 0x99, 0xa0, 0xa1, 0xa2, 0xa4, 0xae, 0xb0, 0xb2,
  1406. 0xde, 0xdf, 0xe3, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
  1407. 0xeb, 0xec, 0xed };
  1408. dwScancode = (DWORD)g_rgbKbdRMap[index];
  1409. lp = ((dwScancode & 0x7F) << 16) | ((dwScancode & 0x80) << 17);
  1410. for( dw = 0; dw < cA(dwSpecKeys); dw++ ) {
  1411. if( dwSpecKeys[dw] == dwScancode ) {
  1412. fSpecKey = TRUE;
  1413. break;
  1414. }
  1415. }
  1416. if( !fSpecKey ) {
  1417. if( !DIGetKeyNameTextHelper(dwScancode, lpwszName, nSize) ) {
  1418. GetKeyNameTextW(lp, lpwszName, nSize);
  1419. #ifndef UNICODE
  1420. if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED )
  1421. {
  1422. CHAR szName[MAX_PATH];
  1423. GetKeyNameTextA( lp, szName, cA(szName) );
  1424. AToU( lpwszName, cA(szName), szName );
  1425. }
  1426. #endif
  1427. }
  1428. }
  1429. if( lpwszName[0] == TEXT('\0') &&
  1430. (dwScancode != 0x56 && dwScancode != 0x73 && dwScancode != 0x7E )
  1431. ) {
  1432. LoadStringW(g_hinst,
  1433. IDS_KEYBOARDOBJECT + DIDFT_GETINSTANCE(dwDevType),
  1434. lpwszName, nSize);
  1435. }
  1436. if( lpwszName[0] == L'\0' ) {
  1437. hres = DIERR_OBJECTNOTFOUND;
  1438. } else {
  1439. hres = S_OK;
  1440. }
  1441. return hres;
  1442. }
  1443. /*****************************************************************************
  1444. *
  1445. * @doc INTERNAL
  1446. *
  1447. * @func DWORD | DIGetOSVersion |
  1448. *
  1449. * Return the OS version on which DInput8.dll is running.
  1450. *
  1451. * @returns
  1452. *
  1453. * WIN95_OS, WIN98_OS, WINME_OS, WINNT_OS, WINWH_OS, or WIN_UNKNOWN_OS.
  1454. *
  1455. *****************************************************************************/
  1456. DWORD DIGetOSVersion()
  1457. {
  1458. OSVERSIONINFO osVerInfo;
  1459. DWORD dwVer;
  1460. if( GetVersion() < 0x80000000 ) {
  1461. dwVer = WINNT_OS;
  1462. } else {
  1463. dwVer = WIN95_OS; //assume Windows 95 for safe
  1464. }
  1465. osVerInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  1466. // If GetVersionEx is supported, then get more details.
  1467. if( GetVersionEx( &osVerInfo ) )
  1468. {
  1469. // Win2K
  1470. if( osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
  1471. {
  1472. // Whistler: Major = 5 & Build # > 2195
  1473. if( osVerInfo.dwMajorVersion == 5 && osVerInfo.dwBuildNumber > 2195 )
  1474. {
  1475. dwVer = WINWH_OS;
  1476. } else {
  1477. dwVer = WINNT_OS;
  1478. }
  1479. }
  1480. // Win9X
  1481. else
  1482. {
  1483. if( (HIBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 4) )
  1484. {
  1485. // WinMe: Major = 4, Minor = 90
  1486. if( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 90) )
  1487. {
  1488. dwVer = WINME_OS;
  1489. } else if ( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) > 0) ) {
  1490. dwVer = WIN98_OS;
  1491. } else {
  1492. dwVer = WIN95_OS;
  1493. }
  1494. }
  1495. }
  1496. }
  1497. return dwVer;
  1498. }