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.

1042 lines
28 KiB

  1. /*****************************************************************************
  2. *
  3. * DIUtil.c
  4. *
  5. * Copyright (c) 1996 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. #ifdef IDirectInputDevice2Vtbl
  24. /*****************************************************************************
  25. *
  26. * @doc INTERNAL
  27. *
  28. * @func LPCTSTR | _ParseHex |
  29. *
  30. * Parse a hex string encoding cb bytes (at most 4), then expect
  31. * the tchDelim to appear afterwards. If tchDelim is 0, then no
  32. * delimiter is expected.
  33. *
  34. * Store the result into the indicated LPBYTE (using only the
  35. * size requested), updating it, and return a pointer to the
  36. * next unparsed character, or 0 on error.
  37. *
  38. * If the incoming pointer is also 0, then return 0 immediately.
  39. *
  40. * @parm IN LPCTSTR | ptsz |
  41. *
  42. * The string to parse.
  43. *
  44. * @parm IN OUT LPBYTE * | ppb |
  45. *
  46. * Pointer to the address of the destination buffer.
  47. *
  48. * @parm IN int | cb |
  49. *
  50. * The size in bytes of the buffer.
  51. *
  52. * @parm IN TCHAR | tchDelim |
  53. *
  54. * The delimiter charater to end the sequence or zero if none is
  55. * expected.
  56. *
  57. * @returns
  58. *
  59. * Returns a pointer to the next unparsed character, or 0 on error.
  60. *
  61. * @comm
  62. * Stolen from TweakUI.
  63. *
  64. * Prefix takes a strong dislike to this function, reporting that
  65. * all callers could use uninitialized memory when the function
  66. * succeeds.
  67. * The problem appears to be that Prefix is unable to determine that
  68. * if the source string can successfully be read, the destination is
  69. * always completely filled (the whole passed destination size) with
  70. * the binary value of the source string. Since all callers always
  71. * pass the size of the variable to which the destination buffer
  72. * pointer points, the memory is always completely initialized but
  73. * it seems reasonable that Prefix would raise a warning.
  74. *
  75. *****************************************************************************/
  76. LPCTSTR INTERNAL
  77. _ParseHex(LPCTSTR ptsz, LPBYTE *ppb, int cb, TCHAR tchDelim)
  78. {
  79. if(ptsz)
  80. {
  81. int i = cb * 2;
  82. DWORD dwParse = 0;
  83. do
  84. {
  85. DWORD uch;
  86. uch = (TBYTE)*ptsz - TEXT('0');
  87. if(uch < 10)
  88. { /* a decimal digit */
  89. } else
  90. {
  91. uch = (*ptsz | 0x20) - TEXT('a');
  92. if(uch < 6)
  93. { /* a hex digit */
  94. uch += 10;
  95. } else
  96. {
  97. return 0; /* Parse error */
  98. }
  99. }
  100. dwParse = (dwParse << 4) + uch;
  101. ptsz++;
  102. } while(--i);
  103. if(tchDelim && *ptsz++ != tchDelim) return 0; /* Parse error */
  104. for(i = 0; i < cb; i++)
  105. {
  106. (*ppb)[i] = ((LPBYTE)&dwParse)[i];
  107. }
  108. *ppb += cb;
  109. }
  110. return ptsz;
  111. }
  112. /*****************************************************************************
  113. *
  114. * @doc INTERNAL
  115. *
  116. * @func BOOL | ParseGUID |
  117. *
  118. * Take a string and convert it into a GUID, return success/failure.
  119. *
  120. * @parm OUT LPGUID | lpGUID |
  121. *
  122. * Receives the parsed GUID on success.
  123. *
  124. * @parm IN LPCTSTR | ptsz |
  125. *
  126. * The string to parse. The format is
  127. *
  128. * { <lt>dword<gt> - <lt>word<gt> - <lt>word<gt>
  129. * - <lt>byte<gt> <lt>byte<gt>
  130. * - <lt>byte<gt> <lt>byte<gt> <lt>byte<gt>
  131. * <lt>byte<gt> <lt>byte<gt> <lt>byte<gt> }
  132. *
  133. * @returns
  134. *
  135. * Returns zero if <p ptszGUID> is not a valid GUID.
  136. *
  137. *
  138. * @comm
  139. *
  140. * Stolen from TweakUI.
  141. *
  142. *****************************************************************************/
  143. BOOL EXTERNAL
  144. ParseGUID(LPGUID pguid, LPCTSTR ptsz)
  145. {
  146. if(lstrlen(ptsz) == ctchGuid - 1 && *ptsz == TEXT('{'))
  147. {
  148. ptsz++;
  149. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 4, TEXT('-'));
  150. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  151. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  152. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
  153. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('-'));
  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, 0 );
  159. ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('}'));
  160. return (BOOL)(UINT_PTR)ptsz;
  161. } else
  162. {
  163. return 0;
  164. }
  165. }
  166. /*****************************************************************************
  167. *
  168. * @doc INTERNAL
  169. *
  170. * @func BOOL | ParseVIDPID |
  171. *
  172. * Take a string formatted as VID_%04&PID_%04.
  173. *
  174. * @parm OUT PUSHORT | puVID |
  175. *
  176. * Receives the parsed VID.
  177. *
  178. * @parm OUT PUSHORT | puPID |
  179. *
  180. * Receives the parsed PID.
  181. *
  182. * @parm IN LPCTSTR | ptsz |
  183. *
  184. *
  185. * @returns
  186. *
  187. * Returns zero on failure.
  188. *
  189. *
  190. * @comm
  191. *
  192. * Stolen from TweakUI.
  193. *
  194. *****************************************************************************/
  195. // VID _ XXXX & PID _ YYYY
  196. #define ctchVIDPID ( 3 + 1 + 4 + 1 + 3 + 1 + 4 )
  197. #define VID_ TEXT("VID_")
  198. #define VID_offset (3+1)
  199. #define PID_ TEXT("&PID_")
  200. #define PID_offset (3+1+4+1+3+1)
  201. BOOL EXTERNAL
  202. ParseVIDPID(PUSHORT puVID, PUSHORT puPID , LPCWSTR pwsz)
  203. {
  204. LPCTSTR ptsz;
  205. #ifndef UNICODE
  206. TCHAR tsz[MAX_JOYSTRING];
  207. UToT( tsz, cA(tsz), pwsz );
  208. ptsz = tsz;
  209. #else
  210. ptsz = pwsz;
  211. #endif
  212. if( _ParseHex(ptsz+VID_offset, (LPBYTE *)&puVID, 2, TEXT('&')) &&
  213. _ParseHex(ptsz+PID_offset, (LPBYTE *)&puPID, 2, 0) )
  214. {
  215. return TRUE;
  216. }
  217. return FALSE;
  218. }
  219. #endif
  220. #if DIRECTINPUT_VERSION > 0x0300
  221. /*****************************************************************************
  222. *
  223. * @doc INTERNAL
  224. *
  225. * @func void | NameFromGUID |
  226. *
  227. * Convert a GUID into an ASCII string that will be used
  228. * to name it in the global namespace.
  229. *
  230. * We use the name "DirectInput.{guid}".
  231. *
  232. * Names are used in the following places:
  233. *
  234. * <c g_hmtxGlobal> names a mutex based on
  235. * <c IID_IDirectInputW> to gate access to the
  236. * shared memory block used to manage exclusive access.
  237. *
  238. * <c g_psop> names a shared memory block based on
  239. * <c IID_IDirectInputDeviceW> to record information
  240. * about exclusive access.
  241. *
  242. * <c g_hmtxJoy> names a mutex based on
  243. * <c IID_IDirectInputDevice2A> to gate access to the
  244. * shared memory block used to track joystick effects.
  245. *
  246. * @parm LPTSTR | ptszBuf |
  247. *
  248. * Output buffer to receive the converted name. It must
  249. * be <c ctchNameGuid> characters in size.
  250. *
  251. * @parm PCGUID | pguid |
  252. *
  253. * The GUID to convert.
  254. *
  255. *
  256. *****************************************************************************/
  257. #pragma BEGIN_CONST_DATA
  258. /* Note: If you change this string, you need to change ctchNameGuid to match */
  259. TCHAR c_tszNameFormat[] =
  260. TEXT("DirectInput.{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}");
  261. #pragma END_CONST_DATA
  262. void EXTERNAL
  263. NameFromGUID(LPTSTR ptszBuf, PCGUID pguid)
  264. {
  265. int ctch;
  266. ctch = wsprintf(ptszBuf, c_tszNameFormat,
  267. pguid->Data1, pguid->Data2, pguid->Data3,
  268. pguid->Data4[0], pguid->Data4[1],
  269. pguid->Data4[2], pguid->Data4[3],
  270. pguid->Data4[4], pguid->Data4[5],
  271. pguid->Data4[6], pguid->Data4[7]);
  272. AssertF(ctch == ctchNameGuid - 1);
  273. }
  274. #endif
  275. /*****************************************************************************
  276. *
  277. * @doc INTERNAL
  278. *
  279. * @func PV | pvFindResource |
  280. *
  281. * Handy wrapper that finds and loads a resource.
  282. *
  283. * @parm IN HINSTANCE | hinst |
  284. *
  285. * Module instance handle.
  286. *
  287. * @parm DWORD | id |
  288. *
  289. * Resource identifier.
  290. *
  291. * @parm LPCTSTR | rt |
  292. *
  293. * Resource type.
  294. *
  295. * @returns
  296. *
  297. * Pointer to resource, or 0.
  298. *
  299. *****************************************************************************/
  300. PV EXTERNAL
  301. pvFindResource(HINSTANCE hinst, DWORD id, LPCTSTR rt)
  302. {
  303. HANDLE hrsrc;
  304. PV pv;
  305. hrsrc = FindResource(hinst, (LPTSTR)(LONG_PTR)id, rt);
  306. if(hrsrc)
  307. {
  308. pv = LoadResource(hinst, hrsrc);
  309. } else
  310. {
  311. pv = 0;
  312. }
  313. return pv;
  314. }
  315. #ifndef UNICODE
  316. /*****************************************************************************
  317. *
  318. * @doc INTERNAL
  319. *
  320. * @func UINT | LoadStringW |
  321. *
  322. * Implementation of LoadStringW for platforms on which Unicode is
  323. * not supported. Does exactly what LoadStringW would've done
  324. * if it existed.
  325. *
  326. * @parm IN HINSTANCE | hinst |
  327. *
  328. * Module instance handle.
  329. *
  330. * @parm UINT | ids |
  331. *
  332. * String id number.
  333. *
  334. * @parm LPWSTR | pwsz |
  335. *
  336. * UNICODE output buffer.
  337. *
  338. * @parm UINT | cwch |
  339. *
  340. * Size of UNICODE output buffer.
  341. *
  342. * @returns
  343. *
  344. * Number of characters copied, not including terminating null.
  345. *
  346. * @comm
  347. *
  348. * Since the string is stored in the resource as UNICODE,
  349. * we just pull it out ourselves. If we go through
  350. * <f LoadStringA>, we may end up losing characters due
  351. * to character set translation.
  352. *
  353. *****************************************************************************/
  354. int EXTERNAL
  355. LoadStringW(HINSTANCE hinst, UINT ids, LPWSTR pwsz, int cwch)
  356. {
  357. PWCHAR pwch;
  358. AssertF(cwch);
  359. ScrambleBuf(pwsz, cbCwch(cwch));
  360. /*
  361. * String tables are broken up into "bundles" of 16 strings each.
  362. */
  363. pwch = pvFindResource(hinst, 1 + ids / 16, RT_STRING);
  364. if(pwch)
  365. {
  366. /*
  367. * Now skip over the strings in the resource until we
  368. * hit the one we want. Each entry is a counted string,
  369. * just like Pascal.
  370. */
  371. for(ids %= 16; ids; ids--)
  372. {
  373. pwch += *pwch + 1;
  374. }
  375. cwch = min(*pwch, cwch - 1);
  376. memcpy(pwsz, pwch+1, cbCwch(cwch)); /* Copy the goo */
  377. } else
  378. {
  379. cwch = 0;
  380. }
  381. pwsz[cwch] = TEXT('\0'); /* Terminate the string */
  382. return cwch;
  383. }
  384. #endif
  385. /*****************************************************************************
  386. *
  387. * @doc INTERNAL
  388. *
  389. * @func void | GetNthString |
  390. *
  391. * Generate a generic numbered object name.
  392. *
  393. * @parm LPWSTR | pwsz |
  394. *
  395. * Output buffer of <c MAX_PATH> characters.
  396. *
  397. * @parm UINT | ids |
  398. *
  399. * String containing number template.
  400. *
  401. * @parm UINT | ui |
  402. *
  403. * Button number.
  404. *
  405. *****************************************************************************/
  406. void EXTERNAL
  407. GetNthString(LPWSTR pwsz, UINT ids, UINT ui)
  408. {
  409. TCHAR tsz[256];
  410. #ifndef UNICODE
  411. TCHAR tszOut[MAX_PATH];
  412. #endif
  413. LoadString(g_hinst, ids, tsz, cA(tsz));
  414. #ifdef UNICODE
  415. wsprintfW(pwsz, tsz, ui);
  416. #else
  417. wsprintf(tszOut, tsz, ui);
  418. TToU(pwsz, MAX_PATH, tszOut);
  419. #endif
  420. }
  421. /*****************************************************************************
  422. *
  423. * @doc INTERNAL
  424. *
  425. * @func HRESULT | hresRunControlPanel |
  426. *
  427. * Run the control panel with the specified applet.
  428. *
  429. * @parm LPCTSTR | ptszApplet |
  430. *
  431. * Applet name.
  432. *
  433. * @returns
  434. *
  435. * <c S_OK> if we started the applet.
  436. *
  437. *****************************************************************************/
  438. #pragma BEGIN_CONST_DATA
  439. TCHAR c_tszControlExeS[] = TEXT("control.exe %s");
  440. #pragma END_CONST_DATA
  441. HRESULT EXTERNAL
  442. hresRunControlPanel(LPCTSTR ptszCpl)
  443. {
  444. HRESULT hres;
  445. STARTUPINFO si;
  446. PROCESS_INFORMATION pi;
  447. TCHAR tsz[MAX_PATH];
  448. EnterProc(hresRunControlPanel, (_ "s", ptszCpl));
  449. ZeroX(si);
  450. si.cb = cbX(si);
  451. wsprintf(tsz, c_tszControlExeS, ptszCpl);
  452. if(CreateProcess(0, tsz, 0, 0, 0, 0, 0, 0, &si, &pi))
  453. {
  454. CloseHandle(pi.hProcess);
  455. CloseHandle(pi.hThread);
  456. hres = S_OK;
  457. } else
  458. {
  459. hres = hresLe(GetLastError());
  460. }
  461. ExitOleProc();
  462. return hres;
  463. }
  464. /*****************************************************************************
  465. *
  466. * @doc INTERNAL
  467. *
  468. * @func void | DeviceInfoWToA |
  469. *
  470. ;begin_dx3
  471. * Convert a <t DIDEVICEINSTANCEW> to a <t DIDEVICEINSTANCEA>.
  472. ;end_dx3
  473. ;begin_dx5
  474. * Convert a <t DIDEVICEINSTANCEW> to a <t DIDEVICEINSTANCE_DX3A>
  475. * or a <t DIDEVICEINSTANCE_DX5A>.
  476. ;end_dx5
  477. *
  478. * @parm LPDIDIDEVICEINSTANCEA | pdiA |
  479. *
  480. * Destination.
  481. *
  482. * @parm LPCDIDIDEVICEINSTANCEW | pdiW |
  483. *
  484. * Source.
  485. *
  486. *****************************************************************************/
  487. void EXTERNAL
  488. DeviceInfoWToA(LPDIDEVICEINSTANCEA pdiA, LPCDIDEVICEINSTANCEW pdiW)
  489. {
  490. EnterProc(DeviceInfoWToA, (_ "pp", pdiA, pdiW));
  491. AssertF(pdiW->dwSize == sizeof(DIDEVICEINSTANCEW));
  492. #if DIRECTINPUT_VERSION <= 0x0400
  493. pdiA->dwSize = sizeof(*pdiA);
  494. #else
  495. AssertF(IsValidSizeDIDEVICEINSTANCEA(pdiA->dwSize));
  496. #endif
  497. pdiA->guidInstance = pdiW->guidInstance;
  498. pdiA->guidProduct = pdiW->guidProduct;
  499. pdiA->dwDevType = pdiW->dwDevType;
  500. UToA(pdiA->tszInstanceName, cA(pdiA->tszInstanceName), pdiW->tszInstanceName);
  501. UToA(pdiA->tszProductName, cA(pdiA->tszProductName), pdiW->tszProductName);
  502. #if DIRECTINPUT_VERSION > 0x0400
  503. if(pdiA->dwSize >= cbX(DIDEVICEINSTANCE_DX5A))
  504. {
  505. pdiA->guidFFDriver = pdiW->guidFFDriver;
  506. pdiA->wUsage = pdiW->wUsage;
  507. pdiA->wUsagePage = pdiW->wUsagePage;
  508. }
  509. #endif
  510. ExitProc();
  511. }
  512. /*****************************************************************************
  513. *
  514. * @doc INTERNAL
  515. *
  516. * @func void | ObjectInfoWToA |
  517. *
  518. #ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
  519. * Convert a <t DIDEVICEOBJECTINSTANCEW>
  520. * to a <t DIDEVICEOBJECTINSTANCE_DX3A>
  521. * or a <t DIDEVICEOBJECTINSTANCE_DX5A>.
  522. #else
  523. * Convert a <t DIDEVICEOBJECTINSTANCEW>
  524. * to a <t DIDEVICEOBJECTINSTANCEA>.
  525. #endif
  526. *
  527. * @parm LPDIDIDEVICEOBJECTINSTANCEA | pdoiA |
  528. *
  529. * Destination.
  530. *
  531. * @parm LPCDIDIDEVICEOBJECTINSTANCEW | pdoiW |
  532. *
  533. * Source.
  534. *
  535. *****************************************************************************/
  536. void EXTERNAL
  537. ObjectInfoWToA(LPDIDEVICEOBJECTINSTANCEA pdoiA,
  538. LPCDIDEVICEOBJECTINSTANCEW pdoiW)
  539. {
  540. EnterProc(ObjectInfoWToA, (_ "pp", pdoiA, pdoiW));
  541. AssertF(pdoiW->dwSize == sizeof(DIDEVICEOBJECTINSTANCEW));
  542. #ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
  543. AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEA(pdoiA->dwSize));
  544. #else
  545. pdoiA->dwSize = sizeof(*pdoiA);
  546. #endif
  547. pdoiA->guidType = pdoiW->guidType;
  548. pdoiA->dwOfs = pdoiW->dwOfs;
  549. pdoiA->dwType = pdoiW->dwType;
  550. pdoiA->dwFlags = pdoiW->dwFlags;
  551. UToA(pdoiA->tszName, cA(pdoiA->tszName), pdoiW->tszName);
  552. #ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
  553. if(pdoiA->dwSize >= cbX(DIDEVICEOBJECTINSTANCE_DX5A))
  554. {
  555. pdoiA->dwFFMaxForce = pdoiW->dwFFMaxForce;
  556. pdoiA->dwFFForceResolution = pdoiW->dwFFForceResolution;
  557. pdoiA->wCollectionNumber = pdoiW->wCollectionNumber;
  558. pdoiA->wDesignatorIndex = pdoiW->wDesignatorIndex;
  559. pdoiA->wUsagePage = pdoiW->wUsagePage;
  560. pdoiA->wUsage = pdoiW->wUsage;
  561. pdoiA->dwDimension = pdoiW->dwDimension;
  562. pdoiA->wExponent = pdoiW->wExponent;
  563. pdoiA->wReportId = pdoiW->wReportId;
  564. }
  565. #endif
  566. ExitProc();
  567. }
  568. #ifdef IDirectInputDevice2Vtbl
  569. /*****************************************************************************
  570. *
  571. * @doc INTERNAL
  572. *
  573. * @func void | EffectInfoWToA |
  574. *
  575. * Convert a <t DIEFFECTINFOW> to a <t DIEFFECTINFOA>
  576. *
  577. * @parm LPDIEFFECTINFOA | pdeiA |
  578. *
  579. * Destination.
  580. *
  581. * @parm LPCDIEFFECTINFOW | pdeiW |
  582. *
  583. * Source.
  584. *
  585. *****************************************************************************/
  586. void EXTERNAL
  587. EffectInfoWToA(LPDIEFFECTINFOA pdeiA, LPCDIEFFECTINFOW pdeiW)
  588. {
  589. EnterProc(EffectInfoWToA, (_ "pp", pdeiA, pdeiW));
  590. AssertF(pdeiW->dwSize == sizeof(DIEFFECTINFOW));
  591. AssertF(pdeiA->dwSize == cbX(*pdeiA));
  592. pdeiA->guid = pdeiW->guid;
  593. pdeiA->dwEffType = pdeiW->dwEffType;
  594. pdeiA->dwStaticParams = pdeiW->dwStaticParams;
  595. pdeiA->dwDynamicParams = pdeiW->dwDynamicParams;
  596. UToA(pdeiA->tszName, cA(pdeiA->tszName), pdeiW->tszName);
  597. ExitProc();
  598. }
  599. #endif
  600. /*****************************************************************************
  601. *
  602. * @doc INTERNAL
  603. *
  604. * @func HRESULT | hresValidInstanceVer |
  605. *
  606. * Check the <t HINSTANCE> and version number received from
  607. * an application.
  608. *
  609. * @parm HINSTANCE | hinst |
  610. *
  611. * Purported module instance handle.
  612. *
  613. * @parm DWORD | dwVersion |
  614. *
  615. * Version the application is asking for.
  616. *
  617. *****************************************************************************/
  618. HRESULT EXTERNAL
  619. hresValidInstanceVer_(HINSTANCE hinst, DWORD dwVersion, LPCSTR s_szProc)
  620. {
  621. HRESULT hres;
  622. TCHAR tszScratch[4];
  623. EnterProcS(hresValidInstanceVer, (_ "xxs", hinst, dwVersion, s_szProc));
  624. /*
  625. * You would think that passing a zero-sized buffer to
  626. * GetModuleFileName would return the necessary buffer size.
  627. *
  628. * You would be right. Except that the Win95 validation layer
  629. * doesn't realize that this was a valid scenario, so the call
  630. * fails in the validation layer and never reached Kernel.
  631. *
  632. * So we read it into a small scratch buffer. The scratch buffer
  633. * must be at least 2 characters; if we passed only 1, then
  634. * GetModuleFileName won't be able to write any characters and
  635. * will return 0.
  636. *
  637. * Now it turns out that there's a bug in NT where, if you
  638. * pass a buffer size of 4, but the actual name is longer than
  639. * 4, it writes 4 characters, PLUS A NULL TERMINATOR, thereby
  640. * smashing your stack and making you fault randomly.
  641. *
  642. * I spent two hours trying to figure that out.
  643. *
  644. * Therefore, you must pass one *less* than the buffer size
  645. * to GetModuleFileName, because it will overwrite your buffer
  646. * by one.
  647. */
  648. /*
  649. * For compatibility reasons, DirectInput 3.0 clients must be
  650. * allowed to pass hinst == 0. (It was a loophole in the original
  651. * DX3 implementation.)
  652. */
  653. if(hinst == 0 ?
  654. dwVersion == 0x0300 :
  655. GetModuleFileName(hinst, tszScratch, cA(tszScratch) - 1))
  656. {
  657. /*
  658. * We need to permit the following DirectX versions:
  659. *
  660. * 0x0300 - DX3 golden
  661. * 0x0500 - DX5 golden
  662. * 0x050A - DX5a Win98 golden
  663. * 0x05B2 - NT 5 beta 2 (also the CPL and WinMM)
  664. * 0x0602 - Win98 OSR1 internal first version
  665. * 0x061A - DX6.1a Win98 OSR1
  666. * 0x0700 - DX7 Win2000 golden
  667. */
  668. if(dwVersion == 0x0300 ||
  669. dwVersion == 0x0500 ||
  670. dwVersion == 0x050A ||
  671. dwVersion == 0x05B2 ||
  672. dwVersion == 0x0602 ||
  673. dwVersion == 0x061A ||
  674. dwVersion == 0x0700
  675. )
  676. {
  677. hres = S_OK;
  678. } else if ( dwVersion == 0 ) {
  679. RPF("%s: DinputInput object has not been initialized, or the version is given as 0.",
  680. s_szProc);
  681. hres = DIERR_NOTINITIALIZED;
  682. } else if(dwVersion < DIRECTINPUT_VERSION)
  683. {
  684. RPF("%s: Incorrect dwVersion(0x%x); program was written with beta SDK. This version 0x%x",
  685. s_szProc, dwVersion, DIRECTINPUT_VERSION);
  686. hres = DIERR_BETADIRECTINPUTVERSION;
  687. } else
  688. {
  689. RPF("%s: Incorrect dwVersion(0x%x); program needs newer version of dinput. This version 0x%x",
  690. s_szProc, dwVersion, DIRECTINPUT_VERSION);
  691. hres = DIERR_OLDDIRECTINPUTVERSION;
  692. }
  693. } else
  694. {
  695. RPF("%s: Invalid HINSTANCE", s_szProc);
  696. hres = E_INVALIDARG;
  697. }
  698. ExitOleProc();
  699. return hres;
  700. }
  701. /*****************************************************************************
  702. *
  703. * @doc INTERNAL
  704. *
  705. * @func HRESULT | DupEventHandle |
  706. *
  707. * Duplicate an event handle intra-process-ly. If the incoming
  708. * handle is NULL, then so is the output handle (and the call
  709. * succeeds).
  710. *
  711. * @parm HANDLE | h |
  712. *
  713. * Source handle.
  714. *
  715. * @parm LPHANDLE | phOut |
  716. *
  717. * Receives output handle.
  718. *
  719. *****************************************************************************/
  720. HRESULT EXTERNAL
  721. DupEventHandle(HANDLE h, LPHANDLE phOut)
  722. {
  723. HRESULT hres;
  724. EnterProc(DupEventHandle, (_ "p", h));
  725. if(h)
  726. {
  727. HANDLE hProcessMe = GetCurrentProcess();
  728. if(DuplicateHandle(hProcessMe, h, hProcessMe, phOut,
  729. EVENT_MODIFY_STATE, 0, 0))
  730. {
  731. hres = S_OK;
  732. } else
  733. {
  734. hres = hresLe(GetLastError());
  735. }
  736. } else
  737. {
  738. *phOut = h;
  739. hres = S_OK;
  740. }
  741. ExitOleProc();
  742. return hres;
  743. }
  744. /*****************************************************************************
  745. *
  746. * @doc INTERNAL
  747. *
  748. * @func DWORD | GetWindowPid |
  749. *
  750. * Simple wrapper that returns the PID of a window.
  751. *
  752. * Here is also where we do goofy hacks for DOS boxes
  753. * on Win95.
  754. *
  755. * @parm HWND | hwnd |
  756. *
  757. * Window handle.
  758. *
  759. * @returns
  760. *
  761. * PID or 0.
  762. *
  763. *****************************************************************************/
  764. DWORD EXTERNAL
  765. GetWindowPid(HWND hwnd)
  766. {
  767. DWORD pid;
  768. if(IsWindow(hwnd) &&
  769. GetWindowThreadProcessId(hwnd, &pid) )
  770. {
  771. if( !fWinnt )
  772. /*
  773. * The Winoldap console window belongs to another
  774. * process but Win95 lies and says that it belongs
  775. * to you but it doesn't.
  776. */
  777. if ( GetProp(hwnd, TEXT("flWinOldAp")) != 0 )
  778. pid = 0;
  779. } else
  780. {
  781. pid = 0;
  782. }
  783. return pid;
  784. }
  785. /*****************************************************************************
  786. *
  787. * @doc INTERNAL
  788. *
  789. * @func HRESULT | hresDupPtszPptsz |
  790. *
  791. * OLEish version of strdup.
  792. *
  793. * @parm LPCTSTR | ptszSrc |
  794. *
  795. * Source string being duplicated.
  796. *
  797. * @parm LPTSTR * | pptszDst |
  798. *
  799. * Receives the duplicated string.
  800. *
  801. * @returns
  802. *
  803. * <c S_OK> or an error code.
  804. *
  805. *****************************************************************************/
  806. HRESULT EXTERNAL
  807. hresDupPtszPptsz(LPCTSTR ptszSrc, LPTSTR *pptszDst)
  808. {
  809. HRESULT hres;
  810. hres = AllocCbPpv(cbCtch(lstrlen(ptszSrc) + 1), pptszDst);
  811. if(SUCCEEDED(hres))
  812. {
  813. lstrcpy(*pptszDst, ptszSrc);
  814. hres = S_OK;
  815. }
  816. return hres;
  817. }
  818. /*****************************************************************************
  819. *
  820. * @doc INTERNAL
  821. *
  822. * @func BOOL | fInitializeCriticalSection |
  823. *
  824. * Initialize the give critical section, returning 0 if an exception
  825. * is thrown, else 0.
  826. *
  827. * @parm LPCRITICAL_SECTION | pCritSec |
  828. *
  829. * Pointer to an uninitialized critical section.
  830. *
  831. *****************************************************************************/
  832. BOOL EXTERNAL
  833. fInitializeCriticalSection(LPCRITICAL_SECTION pCritSec)
  834. {
  835. BOOL fres = 1;
  836. EnterProc(fInitializeCriticalSection, (_ "" ));
  837. AssertF( pCritSec );
  838. __try
  839. {
  840. InitializeCriticalSection( pCritSec );
  841. }
  842. __except( EXCEPTION_EXECUTE_HANDLER )
  843. {
  844. fres = 0;
  845. }
  846. ExitProcF( fres );
  847. return fres;
  848. }
  849. /*****************************************************************************
  850. *
  851. * @doc INTERNAL
  852. *
  853. * @func void | DiCharUpperW |
  854. *
  855. * This function converts a wide-character string or a single wide-character
  856. * to uppercase. Since Win9x doesn't implement CharUpperW, we have to implement
  857. * ourselves.
  858. *
  859. * @parm LPWSTR | pwsz |
  860. *
  861. * The string to be converted
  862. *
  863. * @returns
  864. *
  865. * void
  866. *
  867. *****************************************************************************/
  868. void EXTERNAL
  869. DiCharUpperW(LPWSTR pwsz)
  870. {
  871. int idx;
  872. int iLen = lstrlenW(pwsz);
  873. #define DIFF (L'a' - L'A')
  874. for( idx=0; idx<iLen; idx++ )
  875. {
  876. if( (pwsz[idx] >= L'a') && (pwsz[idx] <= L'z') ){
  877. pwsz[idx] -= DIFF;
  878. }
  879. }
  880. #undef DIFF
  881. }
  882. /*****************************************************************************
  883. *
  884. * @doc INTERNAL
  885. *
  886. * @func DWORD | DIGetOSVersion |
  887. *
  888. * Return the OS version on which DInput8.dll is running.
  889. *
  890. * @returns
  891. *
  892. * WIN95_OS, WIN98_OS, WINME_OS, WINNT_OS, WINWH_OS, or WIN_UNKNOWN_OS.
  893. *
  894. *****************************************************************************/
  895. DWORD DIGetOSVersion()
  896. {
  897. OSVERSIONINFO osVerInfo;
  898. DWORD dwVer;
  899. if( GetVersion() < 0x80000000 ) {
  900. dwVer = WINNT_OS;
  901. } else {
  902. dwVer = WIN95_OS; //assume Windows 95 for safe
  903. }
  904. osVerInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  905. // If GetVersionEx is supported, then get more details.
  906. if( GetVersionEx( &osVerInfo ) )
  907. {
  908. // Win2K
  909. if( osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
  910. {
  911. // Whistler: Major = 5 & Build # > 2195
  912. if( osVerInfo.dwMajorVersion == 5 && osVerInfo.dwBuildNumber > 2195 )
  913. {
  914. dwVer = WINWH_OS;
  915. } else {
  916. dwVer = WINNT_OS;
  917. }
  918. }
  919. // Win9X
  920. else
  921. {
  922. if( (HIBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 4) )
  923. {
  924. // WinMe: Major = 4, Minor = 90
  925. if( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 90) )
  926. {
  927. dwVer = WINME_OS;
  928. } else if ( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) > 0) ) {
  929. dwVer = WIN98_OS;
  930. } else {
  931. dwVer = WIN95_OS;
  932. }
  933. }
  934. }
  935. }
  936. return dwVer;
  937. }