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.

1094 lines
23 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. version.c
  5. Abstract:
  6. This file implements a set of enumeration routines to access
  7. version info in a Win32 binary.
  8. Author:
  9. Jim Schmidt (jimschm) 03-Dec-1997
  10. Revision History:
  11. <alias> <date> <comments>
  12. --*/
  13. #include "pch.h"
  14. #include "migutilp.h"
  15. #define DBG_ACTION "Action"
  16. //
  17. // Globals
  18. //
  19. PCSTR g_DefaultTranslationsA[] = {
  20. "04090000",
  21. "040904E4",
  22. "040904B0",
  23. NULL
  24. };
  25. PCWSTR g_DefaultTranslationsW[] = {
  26. L"04090000",
  27. L"040904E4",
  28. L"040904B0",
  29. NULL
  30. };
  31. //
  32. // Prototypes
  33. //
  34. PCSTR
  35. pEnumVersionValueCommonA (
  36. IN OUT PVERSION_STRUCTA VersionStruct
  37. );
  38. PCWSTR
  39. pEnumVersionValueCommonW (
  40. IN OUT PVERSION_STRUCTW VersionStruct
  41. );
  42. //
  43. // Implementation
  44. //
  45. BOOL
  46. CreateVersionStructA (
  47. OUT PVERSION_STRUCTA VersionStruct,
  48. IN PCSTR FileSpec
  49. )
  50. /*++
  51. Routine Description:
  52. CreateVersionStruct is called to load a version structure from a file
  53. and to obtain the fixed version stamp info that is language-independent.
  54. The caller must call DestroyVersionStruct after the VersionStruct is no
  55. longer needed.
  56. Arguments:
  57. VersionStruct - Receives the version stamp info to be used by other
  58. functions in this module
  59. FileSpec - Specifies the file to obtain version info from
  60. Return Value:
  61. TRUE if the routine was able to get version info, or FALSE if an
  62. error occurred.
  63. --*/
  64. {
  65. //
  66. // Init the struct
  67. //
  68. ZeroMemory (VersionStruct, sizeof (VERSION_STRUCTA));
  69. VersionStruct->FileSpec = FileSpec;
  70. //
  71. // Allocate enough memory for the version stamp
  72. //
  73. VersionStruct->Size = GetFileVersionInfoSizeA (
  74. (PSTR) FileSpec,
  75. &VersionStruct->Handle
  76. );
  77. if (!VersionStruct->Size) {
  78. DEBUGMSG ((DBG_WARNING, "File %s does not have version info", FileSpec));
  79. return FALSE;
  80. }
  81. //
  82. // fix for version info bug:
  83. // allocate both buffers at once; this way the first buffer will not point to invalid
  84. // memory when a reallocation occurs because of the second grow
  85. //
  86. VersionStruct->VersionBuffer = GrowBuffer (&VersionStruct->GrowBuf, VersionStruct->Size * 2);
  87. if (!VersionStruct->VersionBuffer) {
  88. return FALSE;
  89. }
  90. VersionStruct->StringBuffer = VersionStruct->GrowBuf.Buf + VersionStruct->Size;
  91. //
  92. // Now get the version info from the file
  93. //
  94. if (!GetFileVersionInfoA (
  95. (PSTR) FileSpec,
  96. VersionStruct->Handle,
  97. VersionStruct->Size,
  98. VersionStruct->VersionBuffer
  99. )) {
  100. DestroyVersionStructA (VersionStruct);
  101. return FALSE;
  102. }
  103. //
  104. // Extract the fixed info
  105. //
  106. VerQueryValueA (
  107. VersionStruct->VersionBuffer,
  108. "\\",
  109. &VersionStruct->FixedInfo,
  110. &VersionStruct->FixedInfoSize
  111. );
  112. return TRUE;
  113. }
  114. ULONGLONG
  115. VerGetFileVer (
  116. IN PVERSION_STRUCTA VersionStruct
  117. )
  118. {
  119. ULONGLONG result = 0;
  120. if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
  121. *((PDWORD) (&result)) = VersionStruct->FixedInfo->dwFileVersionLS;
  122. *(((PDWORD) (&result)) + 1) = VersionStruct->FixedInfo->dwFileVersionMS;
  123. }
  124. return result;
  125. }
  126. ULONGLONG
  127. VerGetProductVer (
  128. IN PVERSION_STRUCTA VersionStruct
  129. )
  130. {
  131. ULONGLONG result = 0;
  132. if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
  133. *((PDWORD) (&result)) = VersionStruct->FixedInfo->dwProductVersionLS;
  134. *(((PDWORD) (&result)) + 1) = VersionStruct->FixedInfo->dwProductVersionMS;
  135. }
  136. return result;
  137. }
  138. DWORD
  139. VerGetFileDateLo (
  140. IN PVERSION_STRUCTA VersionStruct
  141. )
  142. {
  143. if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
  144. return VersionStruct->FixedInfo->dwFileDateLS;
  145. }
  146. return 0;
  147. }
  148. DWORD
  149. VerGetFileDateHi (
  150. IN PVERSION_STRUCTA VersionStruct
  151. )
  152. {
  153. if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
  154. return VersionStruct->FixedInfo->dwFileDateMS;
  155. }
  156. return 0;
  157. }
  158. DWORD
  159. VerGetFileVerOs (
  160. IN PVERSION_STRUCTA VersionStruct
  161. )
  162. {
  163. if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
  164. return VersionStruct->FixedInfo->dwFileOS;
  165. }
  166. return 0;
  167. }
  168. DWORD
  169. VerGetFileVerType (
  170. IN PVERSION_STRUCTA VersionStruct
  171. )
  172. {
  173. if (VersionStruct->FixedInfoSize >= sizeof (VS_FIXEDFILEINFO)) {
  174. return VersionStruct->FixedInfo->dwFileType;
  175. }
  176. return 0;
  177. }
  178. VOID
  179. DestroyVersionStructA (
  180. IN PVERSION_STRUCTA VersionStruct
  181. )
  182. /*++
  183. Routine Description:
  184. DestroyVersionStruct cleans up all memory allocated by the routines
  185. in this module.
  186. Arguments:
  187. VersionStruct - Specifies the structure to clean up
  188. Return Value:
  189. none
  190. --*/
  191. {
  192. //
  193. // Clean up all allocations made by any routine using
  194. // the VersionStruct
  195. //
  196. if (VersionStruct->GrowBuf.Buf) {
  197. FreeGrowBuffer (&VersionStruct->GrowBuf);
  198. }
  199. ZeroMemory (VersionStruct, sizeof (VERSION_STRUCTA));
  200. }
  201. PCSTR
  202. EnumFirstVersionTranslationA (
  203. IN OUT PVERSION_STRUCTA VersionStruct
  204. )
  205. /*++
  206. Routine Description:
  207. EnumFirstVersionTranslation returins the translation string needed
  208. to access the string table of a version stamp.
  209. Arguments:
  210. VersionStruct - Specifies the structure that has been initialized
  211. by InitializeVersionStruct.
  212. Return Value:
  213. A pointer to a string specifying the first translation, or
  214. NULL if no translations exist.
  215. --*/
  216. {
  217. UINT ArraySize;
  218. //
  219. // Query version block for array of code pages/languages
  220. //
  221. if (!VerQueryValueA (
  222. VersionStruct->VersionBuffer,
  223. "\\VarFileInfo\\Translation",
  224. &VersionStruct->Translations,
  225. &ArraySize
  226. )) {
  227. //
  228. // No translations are available
  229. //
  230. ArraySize = 0;
  231. }
  232. //
  233. // Return a pointer to the first translation
  234. //
  235. VersionStruct->CurrentDefaultTranslation = 0;
  236. VersionStruct->MaxTranslations = ArraySize / sizeof (TRANSLATION);
  237. VersionStruct->CurrentTranslation = 0;
  238. DEBUGMSG_IF ((
  239. VersionStruct->MaxTranslations == 0,
  240. DBG_WARNING,
  241. "File %s has no translations",
  242. VersionStruct->FileSpec
  243. ));
  244. return EnumNextVersionTranslationA (VersionStruct);
  245. }
  246. BOOL
  247. pIsDefaultTranslationA (
  248. IN PCSTR TranslationStr
  249. )
  250. /*++
  251. Routine Description:
  252. pIsDefaultTranslationA returns TRUE if the specified translation
  253. string is enumerated by default. This routine stops multiple
  254. enumeration of the same translation string.
  255. Arguments:
  256. TranslationStr - Specifies the translation string to test
  257. Return Value:
  258. TRUE if the translation string is the same as a default translation
  259. string, or FALSE if it is not.
  260. --*/
  261. {
  262. INT i;
  263. for (i = 0 ; g_DefaultTranslationsA[i] ; i++) {
  264. if (StringIMatchA (TranslationStr, g_DefaultTranslationsA[i])) {
  265. return TRUE;
  266. }
  267. }
  268. return FALSE;
  269. }
  270. PCSTR
  271. EnumNextVersionTranslationA (
  272. IN OUT PVERSION_STRUCTA VersionStruct
  273. )
  274. /*++
  275. Routine Description:
  276. EnumNextVersionTranslation continues the enumeration of translation
  277. strings, needed to access the string table in a version stamp.
  278. Arguments:
  279. VersionStruct - Specifies the same structure passed to
  280. EnumFirstVersionTranslation.
  281. Return Value:
  282. A pointer to a string specifying the next translation, or
  283. NULL if no additional translations exist.
  284. --*/
  285. {
  286. PTRANSLATION Translation;
  287. if (g_DefaultTranslationsA[VersionStruct->CurrentDefaultTranslation]) {
  288. //
  289. // Return default translations first
  290. //
  291. StringCbCopyA (
  292. VersionStruct->TranslationStr,
  293. sizeof(VersionStruct->TranslationStr),
  294. g_DefaultTranslationsA[VersionStruct->CurrentDefaultTranslation]
  295. );
  296. VersionStruct->CurrentDefaultTranslation++;
  297. } else {
  298. do {
  299. //
  300. // Return NULL if all translations have been enumerated
  301. //
  302. if (VersionStruct->CurrentTranslation == VersionStruct->MaxTranslations) {
  303. return NULL;
  304. }
  305. //
  306. // Otherwise build translation string and return pointer to it
  307. //
  308. Translation = &VersionStruct->Translations[VersionStruct->CurrentTranslation];
  309. StringCbPrintfA(
  310. VersionStruct->TranslationStr,
  311. sizeof(VersionStruct->TranslationStr),
  312. "%04x%04x",
  313. Translation->CodePage,
  314. Translation->Language
  315. );
  316. VersionStruct->CurrentTranslation++;
  317. } while (pIsDefaultTranslationA (VersionStruct->TranslationStr));
  318. }
  319. return VersionStruct->TranslationStr;
  320. }
  321. PCSTR
  322. EnumFirstVersionValueA (
  323. IN OUT PVERSION_STRUCTA VersionStruct,
  324. IN PCSTR VersionField
  325. )
  326. /*++
  327. Routine Description:
  328. EnumFirstVersionValue returns the first value stored in a version
  329. stamp for a specific field. If the field does not exist, the
  330. function returns NULL.
  331. An enumeration of EnumFirstVersionValue/EnumNextVersionValue
  332. is used to list all localized strings for a field.
  333. Arguments:
  334. VersionStruct - Specifies the structure that was initialized by
  335. InitializeVersionStruct.
  336. VersionField - Specifies the name of the version field to enumerate
  337. Return Value:
  338. A pointer to the first value of the field, or NULL if the field does
  339. not exist.
  340. --*/
  341. {
  342. PCSTR rc;
  343. if (!EnumFirstVersionTranslationA (VersionStruct)) {
  344. return NULL;
  345. }
  346. VersionStruct->VersionField = VersionField;
  347. rc = pEnumVersionValueCommonA (VersionStruct);
  348. if (!rc) {
  349. rc = EnumNextVersionValueA (VersionStruct);
  350. }
  351. return rc;
  352. }
  353. PCSTR
  354. EnumNextVersionValueA (
  355. IN OUT PVERSION_STRUCTA VersionStruct
  356. )
  357. /*++
  358. Routine Description:
  359. EnumNextVersionValue returns the next value stored in a version
  360. stamp for a specific field.
  361. Arguments:
  362. VersionStruct - Specifies the same structure passed to EnumFirstVersionField
  363. Return Value:
  364. A pointer to the next value of the field, or NULL if another field
  365. does not exist.
  366. --*/
  367. {
  368. PCSTR rc = NULL;
  369. do {
  370. if (!EnumNextVersionTranslationA (VersionStruct)) {
  371. break;
  372. }
  373. rc = pEnumVersionValueCommonA (VersionStruct);
  374. } while (!rc);
  375. return rc;
  376. }
  377. PCSTR
  378. pEnumVersionValueCommonA (
  379. IN OUT PVERSION_STRUCTA VersionStruct
  380. )
  381. /*++
  382. Routine Description:
  383. pEnumVersionValueCommon is a routine that obtains the value
  384. of a version field. It is used for both EnumFirstVersionValue
  385. and EnumNextVersionValue.
  386. Arguments:
  387. VersionStruct - Specifies the structure being processed
  388. Return Value:
  389. A pointer to the version value for the current translation, or
  390. NULL if the value does not exist for the current translation.
  391. --*/
  392. {
  393. PSTR Text;
  394. UINT StringLen;
  395. PBYTE String;
  396. PCSTR Result = NULL;
  397. //
  398. // Prepare sub block for VerQueryValue API
  399. //
  400. Text = AllocTextA (
  401. 16 +
  402. SizeOfStringA (VersionStruct->TranslationStr) +
  403. SizeOfStringA (VersionStruct->VersionField)
  404. );
  405. if (!Text) {
  406. return NULL;
  407. }
  408. wsprintfA (
  409. Text,
  410. "\\StringFileInfo\\%s\\%s",
  411. VersionStruct->TranslationStr,
  412. VersionStruct->VersionField
  413. );
  414. __try {
  415. //
  416. // Get the value from the version stamp
  417. //
  418. if (!VerQueryValueA (
  419. VersionStruct->VersionBuffer,
  420. Text,
  421. &String,
  422. &StringLen
  423. )) {
  424. //
  425. // No value is available
  426. //
  427. __leave;
  428. }
  429. //
  430. // Copy value into buffer
  431. //
  432. _mbsnzcpy (VersionStruct->StringBuffer, (PCSTR) String, StringLen);
  433. Result = VersionStruct->StringBuffer;
  434. }
  435. __finally {
  436. FreeTextA (Text);
  437. }
  438. return Result;
  439. }
  440. BOOL
  441. CreateVersionStructW (
  442. OUT PVERSION_STRUCTW VersionStruct,
  443. IN PCWSTR FileSpec
  444. )
  445. /*++
  446. Routine Description:
  447. CreateVersionStruct is called to load a version structure from a file
  448. and to obtain the fixed version stamp info that is language-independent.
  449. The caller must call DestroyVersionStruct after the VersionStruct is no
  450. longer needed.
  451. Arguments:
  452. VersionStruct - Receives the version stamp info to be used by other
  453. functions in this module
  454. FileSpec - Specifies the file to obtain version info from
  455. Return Value:
  456. TRUE if the routine was able to get version info, or FALSE if an
  457. error occurred.
  458. --*/
  459. {
  460. ZeroMemory (VersionStruct, sizeof (VERSION_STRUCTW));
  461. VersionStruct->FileSpec = FileSpec;
  462. //
  463. // Allocate enough memory for the version stamp
  464. //
  465. VersionStruct->Size = GetFileVersionInfoSizeW (
  466. (PWSTR) FileSpec,
  467. &VersionStruct->Handle
  468. );
  469. if (!VersionStruct->Size) {
  470. DEBUGMSG ((DBG_WARNING, "File %S does not have version info", FileSpec));
  471. return FALSE;
  472. }
  473. //
  474. // fix for version info bug:
  475. // allocate both buffers at once; this way the first buffer will not point to invalid
  476. // memory when a reallocation occurs because of the second grow
  477. //
  478. VersionStruct->VersionBuffer = GrowBuffer (&VersionStruct->GrowBuf, VersionStruct->Size * 2);
  479. if (!VersionStruct->VersionBuffer) {
  480. return FALSE;
  481. }
  482. VersionStruct->StringBuffer = VersionStruct->GrowBuf.Buf + VersionStruct->Size;
  483. //
  484. // Now get the version info from the file
  485. //
  486. if (!GetFileVersionInfoW (
  487. (PWSTR) FileSpec,
  488. VersionStruct->Handle,
  489. VersionStruct->Size,
  490. VersionStruct->VersionBuffer
  491. )) {
  492. DestroyVersionStructW (VersionStruct);
  493. return FALSE;
  494. }
  495. //
  496. // Extract the fixed info
  497. //
  498. VerQueryValueW (
  499. VersionStruct->VersionBuffer,
  500. L"\\",
  501. &VersionStruct->FixedInfo,
  502. &VersionStruct->FixedInfoSize
  503. );
  504. return TRUE;
  505. }
  506. VOID
  507. DestroyVersionStructW (
  508. IN PVERSION_STRUCTW VersionStruct
  509. )
  510. /*++
  511. Routine Description:
  512. DestroyVersionStruct cleans up all memory allocated by the routines
  513. in this module.
  514. Arguments:
  515. VersionStruct - Specifies the structure to clean up
  516. Return Value:
  517. none
  518. --*/
  519. {
  520. if (VersionStruct->GrowBuf.Buf) {
  521. FreeGrowBuffer (&VersionStruct->GrowBuf);
  522. }
  523. ZeroMemory (VersionStruct, sizeof (VERSION_STRUCTW));
  524. }
  525. PCWSTR
  526. EnumFirstVersionTranslationW (
  527. IN OUT PVERSION_STRUCTW VersionStruct
  528. )
  529. /*++
  530. Routine Description:
  531. EnumFirstVersionTranslation returins the translation string needed
  532. to access the string table of a version stamp.
  533. Arguments:
  534. VersionStruct - Specifies the structure that has been initialized
  535. by InitializeVersionStruct.
  536. Return Value:
  537. A pointer to a string specifying the first translation, or
  538. NULL if no translations exist.
  539. --*/
  540. {
  541. UINT ArraySize;
  542. if (!VerQueryValueW (
  543. VersionStruct->VersionBuffer,
  544. L"\\VarFileInfo\\Translation",
  545. &VersionStruct->Translations,
  546. &ArraySize
  547. )) {
  548. //
  549. // No translations are available
  550. //
  551. ArraySize = 0;
  552. }
  553. //
  554. // Return a pointer to the first translation
  555. //
  556. VersionStruct->CurrentDefaultTranslation = 0;
  557. VersionStruct->MaxTranslations = ArraySize / sizeof (TRANSLATION);
  558. VersionStruct->CurrentTranslation = 0;
  559. DEBUGMSG_IF ((
  560. VersionStruct->MaxTranslations == 0,
  561. DBG_WARNING,
  562. "File %S has no translations",
  563. VersionStruct->FileSpec
  564. ));
  565. return EnumNextVersionTranslationW (VersionStruct);
  566. }
  567. BOOL
  568. pIsDefaultTranslationW (
  569. IN PCWSTR TranslationStr
  570. )
  571. {
  572. INT i;
  573. for (i = 0 ; g_DefaultTranslationsW[i] ; i++) {
  574. if (StringIMatchW (TranslationStr, g_DefaultTranslationsW[i])) {
  575. return TRUE;
  576. }
  577. }
  578. return FALSE;
  579. }
  580. PCWSTR
  581. EnumNextVersionTranslationW (
  582. IN OUT PVERSION_STRUCTW VersionStruct
  583. )
  584. /*++
  585. Routine Description:
  586. EnumNextVersionTranslation continues the enumeration of translation
  587. strings, needed to access the string table in a version stamp.
  588. Arguments:
  589. VersionStruct - Specifies the same structure passed to
  590. EnumFirstVersionTranslation.
  591. Return Value:
  592. A pointer to a string specifying the next translation, or
  593. NULL if no additional translations exist.
  594. --*/
  595. {
  596. PTRANSLATION Translation;
  597. if (g_DefaultTranslationsW[VersionStruct->CurrentDefaultTranslation]) {
  598. StringCbCopyW (
  599. VersionStruct->TranslationStr,
  600. sizeof(VersionStruct->TranslationStr),
  601. g_DefaultTranslationsW[VersionStruct->CurrentDefaultTranslation]
  602. );
  603. VersionStruct->CurrentDefaultTranslation++;
  604. } else {
  605. do {
  606. if (VersionStruct->CurrentTranslation == VersionStruct->MaxTranslations) {
  607. return NULL;
  608. }
  609. Translation = &VersionStruct->Translations[VersionStruct->CurrentTranslation];
  610. StringCbPrintfW(
  611. VersionStruct->TranslationStr,
  612. sizeof(VersionStruct->TranslationStr),
  613. L"%04x%04x",
  614. Translation->CodePage,
  615. Translation->Language
  616. );
  617. VersionStruct->CurrentTranslation++;
  618. } while (pIsDefaultTranslationW (VersionStruct->TranslationStr));
  619. }
  620. return VersionStruct->TranslationStr;
  621. }
  622. PCWSTR
  623. EnumFirstVersionValueW (
  624. IN OUT PVERSION_STRUCTW VersionStruct,
  625. IN PCWSTR VersionField
  626. )
  627. /*++
  628. Routine Description:
  629. EnumFirstVersionValue returns the first value stored in a version
  630. stamp for a specific field. If the field does not exist, the
  631. function returns NULL.
  632. An enumeration of EnumFirstVersionValue/EnumNextVersionValue
  633. is used to list all localized strings for a field.
  634. Arguments:
  635. VersionStruct - Specifies the structure that was initialized by
  636. InitializeVersionStruct.
  637. VersionField - Specifies the name of the version field to enumerate
  638. Return Value:
  639. A pointer to the first value of the field, or NULL if the field does
  640. not exist.
  641. --*/
  642. {
  643. PCWSTR rc;
  644. if (!EnumFirstVersionTranslationW (VersionStruct)) {
  645. return NULL;
  646. }
  647. VersionStruct->VersionField = VersionField;
  648. rc = pEnumVersionValueCommonW (VersionStruct);
  649. if (!rc) {
  650. rc = EnumNextVersionValueW (VersionStruct);
  651. }
  652. return rc;
  653. }
  654. PCWSTR
  655. EnumNextVersionValueW (
  656. IN OUT PVERSION_STRUCTW VersionStruct
  657. )
  658. /*++
  659. Routine Description:
  660. EnumNextVersionValue returns the next value stored in a version
  661. stamp for a specific field.
  662. Arguments:
  663. VersionStruct - Specifies the same structure passed to EnumFirstVersionField
  664. Return Value:
  665. A pointer to the next value of the field, or NULL if another field
  666. does not exist.
  667. --*/
  668. {
  669. PCWSTR rc = NULL;
  670. do {
  671. if (!EnumNextVersionTranslationW (VersionStruct)) {
  672. break;
  673. }
  674. rc = pEnumVersionValueCommonW (VersionStruct);
  675. } while (!rc);
  676. return rc;
  677. }
  678. PCWSTR
  679. pEnumVersionValueCommonW (
  680. IN OUT PVERSION_STRUCTW VersionStruct
  681. )
  682. /*++
  683. Routine Description:
  684. pEnumVersionValueCommon is a routine that obtains the value
  685. of a version field. It is used for both EnumFirstVersionValue
  686. and EnumNextVersionValue.
  687. Arguments:
  688. VersionStruct - Specifies the structure being processed
  689. Return Value:
  690. A pointer to the version value for the current translation, or
  691. NULL if the value does not exist for the current translation.
  692. --*/
  693. {
  694. PWSTR Text;
  695. UINT StringLen;
  696. PBYTE String;
  697. PCWSTR Result = NULL;
  698. //
  699. // Prepare sub block for VerQueryValue API
  700. //
  701. Text = AllocTextW (
  702. 18 +
  703. LcharCountW (VersionStruct->TranslationStr) +
  704. LcharCountW (VersionStruct->VersionField)
  705. );
  706. if (!Text) {
  707. return NULL;
  708. }
  709. wsprintfW (
  710. Text,
  711. L"\\StringFileInfo\\%s\\%s",
  712. VersionStruct->TranslationStr,
  713. VersionStruct->VersionField
  714. );
  715. __try {
  716. //
  717. // Get the value from the version stamp
  718. //
  719. if (!VerQueryValueW (
  720. VersionStruct->VersionBuffer,
  721. Text,
  722. &String,
  723. &StringLen
  724. )) {
  725. //
  726. // No value is available
  727. //
  728. __leave;
  729. }
  730. CopyMemory (VersionStruct->StringBuffer, String, StringLen * sizeof (WCHAR));
  731. VersionStruct->StringBuffer [StringLen * sizeof (WCHAR)] = 0;
  732. Result = (PWSTR) VersionStruct->StringBuffer;
  733. }
  734. __finally {
  735. FreeTextW (Text);
  736. }
  737. return Result;
  738. }
  739. PSTR
  740. UnicodeToCcs (
  741. PCWSTR Source
  742. )
  743. /*++
  744. Routine Description:
  745. UnicodeToCcs will walk the unicode string and convert it to ANSII by encoding all DBCS characters
  746. to hex values.
  747. Arguments:
  748. Source - the Unicode string
  749. Return Value:
  750. An encoded ANSII string.
  751. --*/
  752. {
  753. CHAR result [MEMDB_MAX];
  754. UINT srcIndex = 0;
  755. UINT destIndex = 0;
  756. while (Source [srcIndex] && (destIndex < MEMDB_MAX)) {
  757. if ((Source [srcIndex] >=32) &&
  758. (Source [srcIndex] <=126)
  759. ) {
  760. result [destIndex] = (BYTE) Source [srcIndex];
  761. destIndex ++;
  762. }
  763. else {
  764. if ((destIndex == 0) ||
  765. (result [destIndex-1] != '*')
  766. ) {
  767. result [destIndex] = '*';
  768. destIndex ++;
  769. }
  770. }
  771. srcIndex ++;
  772. }
  773. result [destIndex] = 0;
  774. return DuplicatePathString (result, 0);
  775. }