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.

1599 lines
48 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. engine.c
  5. Abstract:
  6. Token Generator for Cross Language Migration Tool
  7. Author:
  8. Rerkboon Suwanasuk 01-May-2002 Created
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include <windows.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <setupapi.h>
  17. #include <shlwapi.h>
  18. #include "Common.h"
  19. //-----------------------------------------------------------------------------
  20. //
  21. // Function: GenerateTokenFile
  22. //
  23. // Synopsis: Entry function for our program.
  24. //
  25. // Returns: HRESULT
  26. //
  27. // History: 02/07/2002 Rerkboos Created
  28. //
  29. // Notes: none
  30. //
  31. //-----------------------------------------------------------------------------
  32. HRESULT GenerateTokenFile(VOID)
  33. {
  34. HRESULT hr;
  35. BOOL bRet;
  36. HINF hTemplateFile;
  37. HANDLE hFile;
  38. WCHAR wszFullTemplateFilePath[MAX_PATH];
  39. WCHAR wszFullOutputFilePath[MAX_PATH];
  40. WCHAR wszLCIDSectionName[32];
  41. LPWSTR lpOutputFileBuffer = NULL;
  42. LPWSTR lpFileName;
  43. size_t cbOutputFileBuffer;
  44. //
  45. // Set some private environment variables for use in our program
  46. //
  47. if (!SetPrivateEnvironmentVar())
  48. {
  49. wprintf(TEXT("Error! Cannot set private environment variables.\n"));
  50. return E_FAIL;
  51. }
  52. hTemplateFile = SetupOpenInfFile(g_wszTemplateFile,
  53. NULL,
  54. INF_STYLE_OLDNT,
  55. NULL);
  56. if (hTemplateFile != INVALID_HANDLE_VALUE)
  57. {
  58. //
  59. // Read the [SourcePath] section from template INF file
  60. //
  61. hr = ReadSourcePathData(hTemplateFile);
  62. if (SUCCEEDED(hr))
  63. {
  64. hr = InitOutputFile(g_wszOutputFile,
  65. wszLCIDSectionName,
  66. ARRAYSIZE(wszLCIDSectionName));
  67. if (SUCCEEDED(hr))
  68. {
  69. //
  70. // Resolve generic strings
  71. //
  72. hr = ResolveStringsSection(hTemplateFile, TEXT("Strings"));
  73. if (FAILED(hr))
  74. {
  75. goto EXIT;
  76. }
  77. //
  78. // Resolve lang-specific strings
  79. //
  80. hr = ResolveStringsSection(hTemplateFile, wszLCIDSectionName);
  81. if (FAILED(hr))
  82. {
  83. goto EXIT;
  84. }
  85. //
  86. // Remove unneeded sub string
  87. //
  88. hr = RemoveUnneededStrings(hTemplateFile);
  89. if (FAILED(hr))
  90. {
  91. goto EXIT;
  92. }
  93. //
  94. // Extract sub string
  95. //
  96. hr = ExtractStrings(hTemplateFile);
  97. if (FAILED(hr))
  98. {
  99. goto EXIT;
  100. }
  101. }
  102. }
  103. else
  104. {
  105. wprintf( TEXT("Error! Cannot read [SourcePath] section\n") );
  106. }
  107. SetupCloseInfFile(hTemplateFile);
  108. }
  109. else
  110. {
  111. wprintf(TEXT("Error! Cannot open template file: %s\n"), g_wszTemplateFile);
  112. hr = HRESULT_FROM_WIN32(GetLastError());
  113. }
  114. EXIT:
  115. return hr;
  116. }
  117. //-----------------------------------------------------------------------------
  118. //
  119. // Function: ReadSourcePathData
  120. //
  121. // Synopsis: Read [SourcePath] section from template INF file,
  122. // then store all the source paths into the structure.
  123. // This structure will be used to find the location of
  124. // resource files.
  125. //
  126. // Returns: HRESULT
  127. //
  128. // History: 02/07/2002 Rerkboos Created
  129. //
  130. // Notes: none
  131. //
  132. //-----------------------------------------------------------------------------
  133. HRESULT ReadSourcePathData(
  134. HINF hTemplateFile
  135. )
  136. {
  137. HRESULT hr = E_FAIL;
  138. BOOL bRet;
  139. size_t nLineIndex;
  140. WCHAR wszValue[MAX_PATH];
  141. WCHAR wszSrcPathSection[32];
  142. INFCONTEXT InfContext;
  143. if (hTemplateFile == INVALID_HANDLE_VALUE)
  144. {
  145. return E_INVALIDARG;
  146. }
  147. hr = StringCchPrintf(wszSrcPathSection,
  148. ARRAYSIZE(wszSrcPathSection),
  149. TEXT("SourcePath.%.4x"),
  150. g_lcidTarget);
  151. if (FAILED(hr))
  152. {
  153. return hr;
  154. }
  155. //
  156. // Extract the source paths from INF and save to global structure
  157. //
  158. g_dwSrcCount = SetupGetLineCount(hTemplateFile, wszSrcPathSection);
  159. for (nLineIndex = 0 ; nLineIndex < g_dwSrcCount ; nLineIndex++)
  160. {
  161. bRet = SetupGetLineByIndex(hTemplateFile,
  162. wszSrcPathSection,
  163. nLineIndex,
  164. &InfContext);
  165. if (bRet)
  166. {
  167. //
  168. // Get the name of each source path
  169. //
  170. bRet = SetupGetStringField(&InfContext,
  171. 0,
  172. wszValue,
  173. ARRAYSIZE(wszValue),
  174. NULL);
  175. if (bRet)
  176. {
  177. hr = StringCchCopy(g_SrcPath[nLineIndex].wszSrcName,
  178. ARRAYSIZE(g_SrcPath[nLineIndex].wszSrcName),
  179. wszValue);
  180. if (SUCCEEDED(hr))
  181. {
  182. //
  183. // Get the path associated to the source name
  184. //
  185. if (SetupGetStringField(&InfContext,
  186. 1,
  187. wszValue,
  188. ARRAYSIZE(wszValue),
  189. NULL))
  190. {
  191. hr = StringCchCopy(g_SrcPath[nLineIndex].wszPath,
  192. ARRAYSIZE(g_SrcPath[nLineIndex].wszPath),
  193. wszValue);
  194. }
  195. }
  196. }
  197. else
  198. {
  199. hr = HRESULT_FROM_WIN32(GetLastError());
  200. }
  201. }
  202. else
  203. {
  204. hr = HRESULT_FROM_WIN32(GetLastError());
  205. }
  206. if (FAILED(hr))
  207. {
  208. break;
  209. }
  210. }
  211. return hr;
  212. }
  213. //-----------------------------------------------------------------------------
  214. //
  215. // Function: ResolveStringsSection
  216. //
  217. // Synopsis: Resolve all strings under specified section name in template
  218. // file, then write the resolved strings to output file.
  219. //
  220. // Returns: HRESULT
  221. //
  222. // History: 03/27/2002 Rerkboos Created
  223. //
  224. // Notes:
  225. //
  226. //-----------------------------------------------------------------------------
  227. HRESULT ResolveStringsSection(
  228. HINF hTemplateFile, // Handle to template file
  229. LPCWSTR lpSectionName // Section name in template file to resolve
  230. )
  231. {
  232. HRESULT hr = E_FAIL;
  233. BOOL bRet;
  234. LONG lLineCount;
  235. if (hTemplateFile == INVALID_HANDLE_VALUE || lpSectionName == NULL)
  236. {
  237. return E_INVALIDARG;
  238. }
  239. wprintf(TEXT("Start resolving strings in section [%s]:\n"),
  240. lpSectionName);
  241. lLineCount = SetupGetLineCount(hTemplateFile, lpSectionName);
  242. if (lLineCount >= 0)
  243. {
  244. INFCONTEXT context;
  245. LONG lLineIndex;
  246. LPWSTR lpKey;
  247. LPWSTR lpValue;
  248. DWORD cchKey;
  249. DWORD cchValue;
  250. DWORD cbWritten;
  251. //
  252. // Resolve strings under string section
  253. //
  254. for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++)
  255. {
  256. bRet = SetupGetLineByIndex(hTemplateFile,
  257. lpSectionName,
  258. lLineIndex,
  259. &context);
  260. if (bRet)
  261. {
  262. hr = ResolveLine(&context, &lpKey, &cchKey, &lpValue, &cchValue);
  263. if (SUCCEEDED(hr))
  264. {
  265. hr = WriteToOutputFile(g_wszOutputFile, lpKey, lpValue);
  266. if (FAILED(hr))
  267. {
  268. wprintf(TEXT("[FAIL] - Cannot write to output file\n"));
  269. break;
  270. }
  271. MEMFREE(lpKey);
  272. MEMFREE(lpValue);
  273. }
  274. else
  275. {
  276. wprintf(TEXT("[FAIL] - Cannot process line %d in template file\n"),
  277. lLineIndex);
  278. hr = HRESULT_FROM_WIN32(GetLastError());
  279. break;
  280. }
  281. }
  282. else
  283. {
  284. hr = HRESULT_FROM_WIN32(GetLastError());
  285. break;
  286. }
  287. }
  288. }
  289. else
  290. {
  291. hr = HRESULT_FROM_WIN32(GetLastError());
  292. }
  293. wprintf(TEXT("Finish resolving strings in section [%s]: hr = 0x%X\n\n"),
  294. lpSectionName,
  295. hr);
  296. return hr;
  297. }
  298. //-----------------------------------------------------------------------------
  299. //
  300. // Function: ResolveLine
  301. //
  302. // Synopsis: Resolve a string value from input INF context.
  303. //
  304. // Returns: HRESULT
  305. //
  306. // History: 03/27/2002 Rerkboos Created
  307. //
  308. // Notes: This function will allocate memory for lplpKey and lplpValue,
  309. // Caller needs to free memory using HeapFree().
  310. //
  311. //-----------------------------------------------------------------------------
  312. HRESULT ResolveLine(
  313. PINFCONTEXT lpContext, // INF line context
  314. LPWSTR *lplpKey, // Pointer to newly allocated buffer for Key name
  315. LPDWORD lpcchKey, // Size of allocated buffer for Key name
  316. LPWSTR *lplpValue, // Pointer to newly allocated buffer for Value
  317. LPDWORD lpcchValue // Size of allocated buffer for Value
  318. )
  319. {
  320. HRESULT hr = E_FAIL;
  321. BOOL bRet;
  322. DWORD cchKey;
  323. DWORD cchRequired;
  324. if (lplpKey == NULL || lpcchKey == NULL ||
  325. lplpValue == NULL || lpcchValue == NULL)
  326. {
  327. return E_INVALIDARG;
  328. }
  329. bRet = SetupGetStringField(lpContext, 0, NULL, 0, &cchKey);
  330. if (bRet)
  331. {
  332. *lplpKey = MEMALLOC(cchKey * sizeof(WCHAR));
  333. if (*lplpKey)
  334. {
  335. *lpcchKey = cchKey;
  336. SetupGetStringField(lpContext, 0, *lplpKey, cchKey, &cchRequired);
  337. hr = ResolveValue(lpContext, lplpValue, lpcchValue);
  338. if (FAILED(hr))
  339. {
  340. wprintf(TEXT("[FAIL] Cannot resolve Key [%s], hr = 0x%X\n"),
  341. *lplpKey,
  342. hr);
  343. MEMFREE(*lplpKey);
  344. }
  345. }
  346. }
  347. else
  348. {
  349. hr = HRESULT_FROM_WIN32(GetLastError());
  350. }
  351. return hr;
  352. }
  353. //-----------------------------------------------------------------------------
  354. //
  355. // Function: InitOutputFile
  356. //
  357. // Synopsis: Initialize output file. Output file is always a Unicode text
  358. // file. This function will create a section name [Strings.XXXX]
  359. // where XXXX is locale ID that user put in command line
  360. //
  361. // Returns: S_OK if succeeded
  362. //
  363. // History: 03/27/2002 Rerkboos Created
  364. //
  365. // Notes:
  366. //
  367. //-----------------------------------------------------------------------------
  368. HRESULT InitOutputFile(
  369. LPCWSTR lpFileName, // Output file name to be created
  370. LPWSTR lpSectionName, // Buffer to store destination section name
  371. DWORD cchSectionName // Size of buffer in WCHAR
  372. )
  373. {
  374. HRESULT hr = S_OK;
  375. BOOL bRet;
  376. HANDLE hFile;
  377. if (lpSectionName == NULL)
  378. {
  379. return E_INVALIDARG;
  380. }
  381. hFile = CreateFile(lpFileName,
  382. GENERIC_WRITE,
  383. 0,
  384. NULL,
  385. CREATE_ALWAYS,
  386. FILE_ATTRIBUTE_NORMAL,
  387. NULL);
  388. if (hFile != INVALID_HANDLE_VALUE)
  389. {
  390. DWORD cbWritten;
  391. WCHAR wszSectionHeader[32];
  392. // Unicode BOM = 0xFEFF
  393. wszSectionHeader[0] = 0xFEFF;
  394. // Create a section name - [Strings.XXXX] where XXXX is locale ID in Hex
  395. hr = StringCchPrintf(wszSectionHeader + 1,
  396. ARRAYSIZE(wszSectionHeader) - 1,
  397. TEXT("[Strings.%.4x]\r\n"),
  398. g_lcidTarget);
  399. if (SUCCEEDED(hr))
  400. {
  401. // Write Unicode BOM and String section header to output file
  402. bRet = WriteFile(hFile,
  403. wszSectionHeader,
  404. lstrlen(wszSectionHeader) * sizeof(WCHAR),
  405. &cbWritten,
  406. NULL);
  407. if (!bRet)
  408. {
  409. hr = HRESULT_FROM_WIN32(GetLastError());
  410. }
  411. }
  412. CloseHandle(hFile);
  413. }
  414. else
  415. {
  416. hr = HRESULT_FROM_WIN32(GetLastError());
  417. }
  418. // If no error occurred, return target String section back to caller
  419. if (SUCCEEDED(hr))
  420. {
  421. hr = StringCchPrintf(lpSectionName,
  422. cchSectionName,
  423. TEXT("Strings.%.4x"),
  424. g_lcidTarget);
  425. }
  426. return hr;
  427. }
  428. //-----------------------------------------------------------------------------
  429. //
  430. // Function: WriteToOutputFile
  431. //
  432. // Synopsis: Write Key and Value to output file
  433. //
  434. // Returns: S_OK if succeeded
  435. //
  436. // History: 03/27/2002 Rerkboos Created
  437. //
  438. // Notes:
  439. //
  440. //-----------------------------------------------------------------------------
  441. HRESULT WriteToOutputFile(
  442. LPCWSTR lpFileName, // Output file name
  443. LPCWSTR lpKey, // Key name
  444. LPCWSTR lpValue // Value name
  445. )
  446. {
  447. HRESULT hr = S_OK;
  448. BOOL bRet;
  449. LPWSTR lpQuoted;
  450. DWORD cchQuoted;
  451. static WCHAR wszOutputLCIDSection[32];
  452. //
  453. // Create the target string section name in output file
  454. //
  455. if (wszOutputLCIDSection[0] == TEXT('\0'))
  456. {
  457. hr = StringCchPrintf(wszOutputLCIDSection,
  458. ARRAYSIZE(wszOutputLCIDSection),
  459. TEXT("Strings.%.4x"),
  460. g_lcidTarget);
  461. if (FAILED(hr))
  462. {
  463. return hr;
  464. }
  465. }
  466. //
  467. // Write the key and value to output file
  468. //
  469. cchQuoted = lstrlen(lpValue) + lstrlen(TEXT("\"\"")) + 1;
  470. lpQuoted = (LPWSTR) MEMALLOC(cchQuoted * sizeof(WCHAR));
  471. if (lpQuoted)
  472. {
  473. hr = StringCchPrintf(lpQuoted,
  474. cchQuoted,
  475. TEXT("\"%s\""),
  476. lpValue);
  477. if (SUCCEEDED(hr))
  478. {
  479. bRet = WritePrivateProfileString(wszOutputLCIDSection,
  480. lpKey,
  481. lpQuoted,
  482. lpFileName);
  483. if (!bRet)
  484. {
  485. hr = HRESULT_FROM_WIN32(GetLastError());
  486. }
  487. }
  488. MEMFREE(lpQuoted);
  489. }
  490. else
  491. {
  492. hr = E_OUTOFMEMORY;
  493. }
  494. return hr;
  495. }
  496. //-----------------------------------------------------------------------------
  497. //
  498. // Function: ResolveValue
  499. //
  500. // Synopsis: Resolve the string value from various resource.
  501. // Following is the format in template file
  502. //
  503. // Key = INF, [Src], [INF File], [Section], [Key Name]
  504. // Key = DLL, [Src], [DLL File], [Resource ID]
  505. // Key = MSG, [Src], [DLL File], [Message ID]
  506. // Key = STR, [String value]
  507. //
  508. // Returns: HRESULT
  509. //
  510. // History: 02/07/2002 Rerkboos Created
  511. //
  512. // Notes: Caller need to free the allocated buffer.
  513. //
  514. //-----------------------------------------------------------------------------
  515. HRESULT ResolveValue(
  516. PINFCONTEXT pInfContext, // INF line context of template file
  517. LPWSTR *lplpValue, // Address of pointer to newly allocated Value buffer
  518. LPDWORD lpcchValue // Address of pionter to size of Value buffer in WCHAR
  519. )
  520. {
  521. HRESULT hr = E_FAIL;
  522. BOOL bRet;
  523. LPWSTR lpToken[8];
  524. LONG lTokenCount;
  525. DWORD cchRequired;
  526. DWORD cchBuffer;
  527. LPWSTR lpBuffer;
  528. WCHAR wszSourceFile[MAX_PATH];
  529. if (lplpValue == NULL || lpcchValue == NULL)
  530. {
  531. return E_INVALIDARG;
  532. }
  533. // Query the required size of buffer to store the data
  534. bRet = SetupGetMultiSzField(pInfContext, 1, NULL, 0, &cchRequired);
  535. if (!bRet)
  536. {
  537. return HRESULT_FROM_WIN32(GetLastError());
  538. }
  539. // Allocate the buffer to store a line from INF
  540. cchBuffer = cchRequired;
  541. lpBuffer = (LPWSTR) MEMALLOC(cchBuffer * sizeof(WCHAR));
  542. if (lpBuffer)
  543. {
  544. // Get the data from field 1 to the end of line to allocated buffer
  545. bRet = SetupGetMultiSzField(pInfContext, 1, lpBuffer, cchBuffer, &cchRequired);
  546. if (bRet)
  547. {
  548. lTokenCount = TokenizeMultiSzString(lpBuffer, cchBuffer, lpToken, 8);
  549. if (lTokenCount >= 0)
  550. {
  551. if (CompareEngString(lpToken[0], TEXT_INF) == CSTR_EQUAL)
  552. {
  553. // INF, [Src], [INF File], [Section], [Key Name]
  554. // [0] [1] [2] [3] [4]
  555. if (lTokenCount == 5)
  556. {
  557. hr = ResolveSourceFile(lpToken[1],
  558. lpToken[2],
  559. wszSourceFile,
  560. ARRAYSIZE(wszSourceFile));
  561. if (SUCCEEDED(hr))
  562. {
  563. hr = GetStringFromINF(wszSourceFile, // Inf file name
  564. lpToken[3], // Section name in Inf
  565. lpToken[4], // Key name
  566. lplpValue,
  567. lpcchValue);
  568. }
  569. }
  570. else
  571. {
  572. // Data format is invalid
  573. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  574. }
  575. }
  576. else if (CompareEngString(lpToken[0], TEXT_DLL) == CSTR_EQUAL)
  577. {
  578. // DLL, [Src], [DLL File], [Resource ID]
  579. // [0] [1] [2] [3]
  580. if (lTokenCount == 4)
  581. {
  582. hr = ResolveSourceFile(lpToken[1],
  583. lpToken[2],
  584. wszSourceFile,
  585. ARRAYSIZE(wszSourceFile));
  586. if (SUCCEEDED(hr))
  587. {
  588. hr = GetStringFromDLL(wszSourceFile, // Dll file name
  589. _wtoi(lpToken[3]),
  590. lplpValue,
  591. lpcchValue);
  592. }
  593. }
  594. else
  595. {
  596. // Data format is invalid
  597. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  598. }
  599. }
  600. else if (CompareEngString(lpToken[0], TEXT_MSG) == CSTR_EQUAL)
  601. {
  602. // MSG, [Src], [DLL File], [Message ID]
  603. // [0] [1] [2] [3]
  604. if (lTokenCount == 4)
  605. {
  606. hr = ResolveSourceFile(lpToken[1],
  607. lpToken[2],
  608. wszSourceFile,
  609. ARRAYSIZE(wszSourceFile));
  610. if (SUCCEEDED(hr))
  611. {
  612. hr = GetStringFromMSG(wszSourceFile, // File name
  613. _wtoi(lpToken[3]), // Message ID
  614. g_lcidTarget,
  615. lplpValue,
  616. lpcchValue);
  617. }
  618. }
  619. else
  620. {
  621. // Data format is invalid
  622. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  623. }
  624. }
  625. else if (CompareEngString(lpToken[0], TEXT_STR) == CSTR_EQUAL)
  626. {
  627. // STR, [String]
  628. // [0] [1]
  629. if (lTokenCount == 2)
  630. {
  631. hr = GetStringFromSTR(lpToken[1], lplpValue, lpcchValue);
  632. }
  633. else
  634. {
  635. // Data format is invalid
  636. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  637. }
  638. }
  639. else
  640. {
  641. *lplpValue = NULL;
  642. *lpcchValue = 0;
  643. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  644. }
  645. }
  646. }
  647. MEMFREE(lpBuffer);
  648. }
  649. else
  650. {
  651. hr = E_OUTOFMEMORY;
  652. }
  653. return hr;
  654. }
  655. HRESULT ResolveSourceFile(
  656. LPCWSTR lpSrcPathName,
  657. LPCWSTR lpSrcFileName,
  658. LPWSTR lpFullOutputPath,
  659. DWORD cchFullOutputPath
  660. )
  661. {
  662. HRESULT hr;
  663. WCHAR wszCabPath[MAX_PATH];
  664. WCHAR wszCab[MAX_PATH];
  665. WCHAR wszFileInCab[MAX_PATH];
  666. WCHAR wszExpandedCabPath[MAX_PATH];
  667. DWORD dwErr;
  668. if (lpFullOutputPath == NULL)
  669. {
  670. return E_INVALIDARG;
  671. }
  672. //
  673. // Resolve source file name and directory
  674. //
  675. hr = GetPathFromSourcePathName(lpSrcPathName, wszCabPath, ARRAYSIZE(wszCabPath));
  676. if (SUCCEEDED(hr))
  677. {
  678. hr = GetCabFileName(lpSrcFileName,
  679. wszCab,
  680. ARRAYSIZE(wszCab),
  681. wszFileInCab,
  682. ARRAYSIZE(wszFileInCab));
  683. if (SUCCEEDED(hr))
  684. {
  685. dwErr = ExpandEnvironmentStrings(wszCabPath,
  686. wszExpandedCabPath,
  687. ARRAYSIZE(wszExpandedCabPath));
  688. if (dwErr > 0)
  689. {
  690. hr = CopyCompressedFile(wszCabPath,
  691. wszCab,
  692. wszFileInCab,
  693. lpFullOutputPath,
  694. cchFullOutputPath);
  695. }
  696. else
  697. {
  698. hr = HRESULT_FROM_WIN32(GetLastError());
  699. }
  700. }
  701. }
  702. return hr;
  703. }
  704. //-----------------------------------------------------------------------------
  705. //
  706. // Function: GetStringFromINF
  707. //
  708. // Synopsis: Extract the string value from INF file
  709. //
  710. // Returns: HRESULT
  711. //
  712. // History: 02/07/2002 Rerkboos Created
  713. //
  714. // Notes: Caller need to free the allocated buffer (HeapFree)
  715. //
  716. //-----------------------------------------------------------------------------
  717. HRESULT GetStringFromINF(
  718. LPCWSTR lpInfFile, // Full path name to Inf file
  719. LPCWSTR lpSection, // Section name
  720. LPCWSTR lpKey, // Key name
  721. LPWSTR *lplpValue, // Address of pointer to point to the allocated buffer
  722. LPDWORD lpcchValue //
  723. )
  724. {
  725. HRESULT hr = E_FAIL;
  726. BOOL bRet;
  727. WCHAR wszFullPath[MAX_PATH];
  728. HINF hInf;
  729. DWORD dwCharCount;
  730. if (lplpValue == NULL)
  731. {
  732. return E_INVALIDARG;
  733. }
  734. *lplpValue = NULL;
  735. *lpcchValue = 0;
  736. hInf = SetupOpenInfFile(lpInfFile,
  737. NULL,
  738. INF_STYLE_WIN4,
  739. NULL);
  740. if (hInf != INVALID_HANDLE_VALUE)
  741. {
  742. // Find out the size of buffer needed to store the string
  743. bRet = SetupGetLineText(NULL,
  744. hInf,
  745. lpSection,
  746. lpKey,
  747. NULL, // No returned buffer
  748. 0, // No returned buffer size
  749. lpcchValue); // Required size including null terminator
  750. if (bRet)
  751. {
  752. // Allocate memory to store the string
  753. *lplpValue = (LPWSTR) MEMALLOC(*lpcchValue * sizeof(WCHAR));
  754. if (*lplpValue != NULL)
  755. {
  756. //
  757. // Read the string from INF file
  758. //
  759. bRet = SetupGetLineText(NULL,
  760. hInf,
  761. lpSection,
  762. lpKey,
  763. *lplpValue,
  764. *lpcchValue,
  765. NULL);
  766. if (bRet)
  767. {
  768. hr = S_OK;
  769. }
  770. }
  771. else
  772. {
  773. SetLastError(ERROR_OUTOFMEMORY);
  774. }
  775. }
  776. SetupCloseInfFile(hInf);
  777. }
  778. // If something was wrong, clean up
  779. if (hr != S_OK)
  780. {
  781. hr = HRESULT_FROM_WIN32(GetLastError());
  782. *lpcchValue = 0;
  783. if (*lplpValue != NULL)
  784. {
  785. MEMFREE(*lplpValue);
  786. }
  787. }
  788. return hr;
  789. }
  790. //-----------------------------------------------------------------------------
  791. //
  792. // Function: GetStringFromDLL
  793. //
  794. // Synopsis: Extract the string value from String resource in DLL
  795. //
  796. // Returns: HRESULT
  797. //
  798. // History: 02/07/2002 Rerkboos Created
  799. //
  800. // Notes: Caller need to free the allocated buffer
  801. //
  802. //-----------------------------------------------------------------------------
  803. HRESULT GetStringFromDLL(
  804. LPCWSTR lpDLLFile, // Full path to Dll file
  805. UINT uStrID, // String ID
  806. LPWSTR *lplpValue, // Address of pointer to point to the allocated buffer
  807. LPDWORD lpcchValue //
  808. )
  809. {
  810. HRESULT hr = E_FAIL;
  811. BOOL bRet;
  812. HMODULE hDLL;
  813. int cchCopied;
  814. if (lplpValue == NULL || lpcchValue == NULL)
  815. {
  816. return E_INVALIDARG;
  817. }
  818. *lplpValue = NULL;
  819. *lpcchValue = 0;
  820. // Load resource DLL
  821. hDLL = LoadLibraryEx(lpDLLFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
  822. if (hDLL)
  823. {
  824. // Allocate memory to store the string
  825. // There is no function to calculate buffer size needed, maximum is 65535 (from MSDN)
  826. // Initially allocate 1024 WCHARs, Reallocate again if it's not big enough
  827. *lpcchValue = 1024;
  828. *lplpValue = (LPWSTR) MEMALLOC(*lpcchValue * sizeof(WCHAR));
  829. if (*lplpValue != NULL)
  830. {
  831. //
  832. // Load the string from DLL
  833. //
  834. cchCopied = LoadString(hDLL, uStrID, *lplpValue, (int) *lpcchValue);
  835. if (cchCopied > 0)
  836. {
  837. hr = S_OK;
  838. while (cchCopied == (int) (*lpcchValue - 1))
  839. {
  840. // Allocated buffer is too small, reallocate more
  841. LPWSTR lpOldBuffer;
  842. lpOldBuffer = *lplpValue;
  843. *lpcchValue += 1024;
  844. *lplpValue = MEMREALLOC(lpOldBuffer, *lpcchValue);
  845. if (*lplpValue == NULL)
  846. {
  847. // Error reallocating more memory
  848. *lplpValue = lpOldBuffer;
  849. SetLastError(ERROR_OUTOFMEMORY);
  850. hr = E_FAIL;
  851. break;
  852. }
  853. else
  854. {
  855. hr = S_OK;
  856. }
  857. cchCopied = LoadString(hDLL, uStrID, *lplpValue, (int) *lpcchValue);
  858. }
  859. }
  860. }
  861. else
  862. {
  863. SetLastError(ERROR_OUTOFMEMORY);
  864. }
  865. FreeLibrary(hDLL);
  866. }
  867. // If something was wrong, clean up
  868. if (hr != S_OK)
  869. {
  870. hr = HRESULT_FROM_WIN32(GetLastError());
  871. *lpcchValue = 0;
  872. if (*lplpValue != NULL)
  873. {
  874. MEMFREE(*lplpValue);
  875. }
  876. }
  877. return hr;
  878. }
  879. //-----------------------------------------------------------------------------
  880. //
  881. // Function: GetStringFromMSG
  882. //
  883. // Synopsis: Extract the string value from message table
  884. //
  885. // Returns: HRESULT
  886. //
  887. // History: 02/07/2002 Rerkboos Created
  888. //
  889. // Notes: Caller need to free the allocated buffer
  890. //
  891. //-----------------------------------------------------------------------------
  892. HRESULT GetStringFromMSG(
  893. LPCWSTR lpDLLFile, // Full path to resource DLL
  894. DWORD dwMsgID, // Message ID
  895. DWORD dwLangID, // Language ID
  896. LPWSTR *lplpValue, //
  897. LPDWORD lpcchValue //
  898. )
  899. {
  900. HRESULT hr = E_FAIL;
  901. BOOL bRet;
  902. WCHAR wszFullPath[MAX_PATH];
  903. HMODULE hDLL;
  904. LPWSTR lpTmpBuffer;
  905. int nRet;
  906. if (lplpValue == NULL || lpcchValue == NULL)
  907. {
  908. return E_INVALIDARG;
  909. }
  910. *lplpValue = NULL;
  911. *lpcchValue = 0;
  912. // Load the resource DLL
  913. hDLL = LoadLibraryEx(lpDLLFile, NULL, DONT_RESOLVE_DLL_REFERENCES);
  914. if (hDLL != NULL)
  915. {
  916. // Load the string from message table in DLL
  917. // FormatMessage will allocate buffer for the data using LocalAlloc()
  918. // need to free with LocalFree()
  919. bRet = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
  920. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  921. FORMAT_MESSAGE_IGNORE_INSERTS |
  922. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  923. hDLL,
  924. dwMsgID,
  925. dwLangID,
  926. (LPWSTR) &lpTmpBuffer,
  927. 0, // use 0 to query the required buffer size
  928. NULL);
  929. if (bRet)
  930. {
  931. // Trim all unnecessary leading and trailing spaces
  932. RTrim(lpTmpBuffer);
  933. // Allocate the buffer for returned data
  934. *lpcchValue = lstrlen(lpTmpBuffer) + 1;
  935. *lplpValue = (LPWSTR) MEMALLOC(*lpcchValue * sizeof(WCHAR));
  936. if (*lplpValue)
  937. {
  938. hr = StringCchCopy(*lplpValue, *lpcchValue, lpTmpBuffer);
  939. }
  940. else
  941. {
  942. SetLastError(ERROR_OUTOFMEMORY);
  943. }
  944. LocalFree(lpTmpBuffer);
  945. }
  946. FreeLibrary(hDLL);
  947. }
  948. // If something was wrong, clean up
  949. if (hr != S_OK)
  950. {
  951. hr = HRESULT_FROM_WIN32(GetLastError());
  952. *lpcchValue = 0;
  953. if (*lplpValue != NULL)
  954. {
  955. MEMFREE(*lplpValue);
  956. }
  957. }
  958. return hr;
  959. }
  960. //-----------------------------------------------------------------------------
  961. //
  962. // Function: GetStringFromSTR
  963. //
  964. // Synopsis: Copy the hardcoded string into the newly allocated buffer
  965. //
  966. // Returns: HRESULT
  967. //
  968. // History: 02/07/2002 Rerkboos Created
  969. //
  970. // Notes: Caller need to free the allocated buffer
  971. //
  972. //-----------------------------------------------------------------------------
  973. HRESULT GetStringFromSTR(
  974. LPCWSTR lpString,
  975. LPWSTR *lplpValue, //
  976. LPDWORD lpcchValue //
  977. )
  978. {
  979. HRESULT hr = E_FAIL;
  980. if (lplpValue == NULL || lpcchValue == NULL)
  981. {
  982. return E_INVALIDARG;
  983. }
  984. // Allocate buffer and copy string to buffer
  985. *lpcchValue = lstrlen(lpString) + 1;
  986. *lplpValue = (LPWSTR) MEMALLOC(*lpcchValue * sizeof(WCHAR));
  987. if (*lplpValue)
  988. {
  989. hr = StringCchCopy(*lplpValue, *lpcchValue, lpString);
  990. }
  991. // If something was wrong, clean up
  992. if (hr != S_OK)
  993. {
  994. hr = HRESULT_FROM_WIN32(GetLastError());
  995. *lpcchValue = 0;
  996. if (*lplpValue != NULL)
  997. {
  998. MEMFREE(*lplpValue);
  999. }
  1000. }
  1001. return hr;
  1002. }
  1003. //-----------------------------------------------------------------------------
  1004. //
  1005. // Function: SetPrivateEnvironmentVar
  1006. //
  1007. // Synopsis: Set private environment variables to use within our program
  1008. //
  1009. // Returns: TRUE if succeeded, FALSE otherwise
  1010. //
  1011. // History: 02/07/2002 Rerkboos Created
  1012. //
  1013. // Notes: none
  1014. //
  1015. //-----------------------------------------------------------------------------
  1016. BOOL SetPrivateEnvironmentVar()
  1017. {
  1018. HRESULT hr;
  1019. BOOL bRet;
  1020. WCHAR wszValue[MAX_PATH];
  1021. //
  1022. // Set LANGID_DEC to decimal value of the system default UI language
  1023. //
  1024. hr = StringCchPrintf(wszValue,
  1025. ARRAYSIZE(wszValue),
  1026. TEXT("%04d"),
  1027. g_lcidTarget);
  1028. if (SUCCEEDED(hr))
  1029. {
  1030. bRet = SetEnvironmentVariable(TEXT("LANGID_DEC"), wszValue);
  1031. }
  1032. //
  1033. // Set LANGID_HEX to hexadecimal value of the system default UI language
  1034. //
  1035. hr = StringCchPrintf(wszValue,
  1036. ARRAYSIZE(wszValue),
  1037. TEXT("%04x"),
  1038. g_lcidTarget);
  1039. if (SUCCEEDED(hr))
  1040. {
  1041. bRet = SetEnvironmentVariable(TEXT("LANGID_HEX"), wszValue);
  1042. }
  1043. return bRet;
  1044. }
  1045. //-----------------------------------------------------------------------------
  1046. //
  1047. // Function: RemoveUnneededStrings
  1048. //
  1049. // Synopsis: Remove all unneeded sub strings from the value of
  1050. // specified keys under [Remove] section
  1051. //
  1052. // Returns: HRESULT
  1053. //
  1054. // History: 02/07/2002 Rerkboos Created
  1055. //
  1056. // Notes: Caller need to free the allocated buffer
  1057. //
  1058. //-----------------------------------------------------------------------------
  1059. HRESULT RemoveUnneededStrings(
  1060. HINF hTemplateFile // Handle of template file
  1061. )
  1062. {
  1063. HRESULT hr = E_FAIL;
  1064. BOOL bRet;
  1065. LONG lLineCount;
  1066. LONG lLineIndex;
  1067. lLineCount = SetupGetLineCount(hTemplateFile, TEXT("Remove"));
  1068. for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++)
  1069. {
  1070. INFCONTEXT Context;
  1071. bRet = SetupGetLineByIndex(hTemplateFile,
  1072. TEXT("Remove"),
  1073. lLineIndex,
  1074. &Context);
  1075. if (bRet)
  1076. {
  1077. WCHAR wszKey[64];
  1078. WCHAR wszType[8];
  1079. WCHAR wszValue[MAX_PATH];
  1080. DWORD cchRequired;
  1081. // Get type of unneeded string
  1082. bRet = SetupGetStringField(&Context,
  1083. 0,
  1084. wszKey,
  1085. ARRAYSIZE(wszKey),
  1086. &cchRequired) &&
  1087. SetupGetStringField(&Context,
  1088. 1,
  1089. wszType,
  1090. ARRAYSIZE(wszType),
  1091. &cchRequired) &&
  1092. SetupGetStringField(&Context,
  1093. 2,
  1094. wszValue,
  1095. ARRAYSIZE(wszValue),
  1096. &cchRequired);
  1097. if (bRet)
  1098. {
  1099. if (CompareEngString(wszType, TEXT("STR")) == CSTR_EQUAL)
  1100. {
  1101. // STR type
  1102. hr = RemoveUnneededString(wszKey, wszValue);
  1103. }
  1104. else if (CompareEngString(wszType, TEXT("EXP")) == CSTR_EQUAL)
  1105. {
  1106. // EXP type
  1107. WCHAR wszUnneededString[MAX_PATH];
  1108. hr = GetExpString(wszUnneededString,
  1109. ARRAYSIZE(wszUnneededString),
  1110. wszValue);
  1111. if (SUCCEEDED(hr))
  1112. {
  1113. hr = RemoveUnneededString(wszKey, wszUnneededString);
  1114. }
  1115. }
  1116. else
  1117. {
  1118. SetLastError(ERROR_INVALID_DATA);
  1119. }
  1120. }
  1121. }
  1122. }
  1123. if (hr == E_FAIL)
  1124. {
  1125. hr = HRESULT_FROM_WIN32(GetLastError());
  1126. }
  1127. return hr;
  1128. }
  1129. //-----------------------------------------------------------------------------
  1130. //
  1131. // Function: RemoveUnneededString
  1132. //
  1133. // Synopsis: Remove an unneeded sub string from the value of specified key
  1134. //
  1135. // Returns: HRESULT
  1136. //
  1137. // History: 02/07/2002 Rerkboos Created
  1138. //
  1139. // Notes: Caller need to free the allocated buffer
  1140. //
  1141. //-----------------------------------------------------------------------------
  1142. HRESULT RemoveUnneededString(
  1143. LPCWSTR lpKey, // Key name
  1144. LPCWSTR lpUnneededString // Unneeded sub string
  1145. )
  1146. {
  1147. HRESULT hr = E_FAIL;
  1148. BOOL bRet;
  1149. WCHAR wszOldValue[MAX_PATH];
  1150. WCHAR wszNewValue[MAX_PATH];
  1151. DWORD cchCopied;
  1152. cchCopied = GetPrivateProfileString(g_wszTargetLCIDSection,
  1153. lpKey,
  1154. TEXT(""),
  1155. wszOldValue,
  1156. ARRAYSIZE(wszOldValue),
  1157. g_wszOutputFile);
  1158. if (cchCopied > 0)
  1159. {
  1160. if (StrStrI(wszOldValue, lpUnneededString))
  1161. {
  1162. // Unneeded string found
  1163. hr = StringSubstitute(wszNewValue,
  1164. ARRAYSIZE(wszNewValue),
  1165. wszOldValue,
  1166. lpUnneededString,
  1167. TEXT(""));
  1168. if (SUCCEEDED(hr))
  1169. {
  1170. WCHAR wszQuoted[MAX_PATH];
  1171. hr = StringCchPrintf(wszQuoted,
  1172. ARRAYSIZE(wszQuoted),
  1173. TEXT("\"%s\""),
  1174. wszNewValue);
  1175. if (SUCCEEDED(hr))
  1176. {
  1177. bRet = WritePrivateProfileString(g_wszTargetLCIDSection,
  1178. lpKey,
  1179. wszQuoted,
  1180. g_wszOutputFile);
  1181. if (bRet)
  1182. {
  1183. hr = S_OK;
  1184. }
  1185. else
  1186. {
  1187. hr = HRESULT_FROM_WIN32(GetLastError());
  1188. }
  1189. }
  1190. }
  1191. }
  1192. else
  1193. {
  1194. // Unneeded string not found
  1195. hr = S_FALSE;
  1196. }
  1197. }
  1198. else
  1199. {
  1200. hr = HRESULT_FROM_WIN32(GetLastError());
  1201. }
  1202. return hr;
  1203. }
  1204. //-----------------------------------------------------------------------------
  1205. //
  1206. // Function: ExtractStrings
  1207. //
  1208. // Synopsis: Extract sub strings from the value of
  1209. // specified keys under [Extract] section
  1210. //
  1211. // Returns: HRESULT
  1212. //
  1213. // History: 08/01/2002 Geoffguo Created
  1214. //
  1215. // Notes: Caller need to free the allocated buffer
  1216. //
  1217. //-----------------------------------------------------------------------------
  1218. HRESULT ExtractStrings(
  1219. HINF hTemplateFile // Handle of template file
  1220. )
  1221. {
  1222. HRESULT hr = E_FAIL;
  1223. BOOL bRet;
  1224. LONG lLineCount;
  1225. LONG lLineIndex;
  1226. WCHAR wszKey[64];
  1227. WCHAR wszValueName[64];
  1228. WCHAR wszMatch[64];
  1229. WCHAR wszLeftDelimitor[8];
  1230. WCHAR wszRightDelimitor[8];
  1231. DWORD cchRequired;
  1232. lLineCount = SetupGetLineCount(hTemplateFile, TEXT("Extract"));
  1233. for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++)
  1234. {
  1235. INFCONTEXT Context;
  1236. bRet = SetupGetLineByIndex(hTemplateFile,
  1237. TEXT("Extract"),
  1238. lLineIndex,
  1239. &Context);
  1240. if (bRet)
  1241. {
  1242. // Get type of unneeded string
  1243. bRet = SetupGetStringField(&Context,
  1244. 0,
  1245. wszValueName,
  1246. ARRAYSIZE(wszValueName),
  1247. &cchRequired) &&
  1248. SetupGetStringField(&Context,
  1249. 1,
  1250. wszKey,
  1251. ARRAYSIZE(wszKey),
  1252. &cchRequired) &&
  1253. SetupGetStringField(&Context,
  1254. 2,
  1255. wszMatch,
  1256. ARRAYSIZE(wszMatch),
  1257. &cchRequired) &&
  1258. SetupGetStringField(&Context,
  1259. 3,
  1260. wszLeftDelimitor,
  1261. ARRAYSIZE(wszLeftDelimitor),
  1262. &cchRequired) &&
  1263. SetupGetStringField(&Context,
  1264. 4,
  1265. wszRightDelimitor,
  1266. ARRAYSIZE(wszRightDelimitor),
  1267. &cchRequired);
  1268. hr = ExtractString(wszKey,
  1269. wszValueName,
  1270. wszMatch,
  1271. wszLeftDelimitor,
  1272. wszRightDelimitor);
  1273. }
  1274. }
  1275. bRet = WritePrivateProfileString(g_wszTargetLCIDSection,
  1276. wszKey,
  1277. NULL,
  1278. g_wszOutputFile);
  1279. if (bRet)
  1280. hr = S_OK;
  1281. if (hr == E_FAIL)
  1282. {
  1283. hr = HRESULT_FROM_WIN32(GetLastError());
  1284. }
  1285. return hr;
  1286. }
  1287. //-----------------------------------------------------------------------------
  1288. //
  1289. // Function: RemoveUnneededString
  1290. //
  1291. // Synopsis: Remove an unneeded sub string from the value of specified key
  1292. //
  1293. // Returns: HRESULT
  1294. //
  1295. // History: 02/07/2002 Rerkboos Created
  1296. //
  1297. // Notes: Caller need to free the allocated buffer
  1298. //
  1299. //-----------------------------------------------------------------------------
  1300. HRESULT ExtractString(
  1301. LPCWSTR lpKey, // Key name
  1302. LPCWSTR lpValueName,
  1303. LPCWSTR lpMatch,
  1304. LPCWSTR lpLeftDelimitor,
  1305. LPCWSTR lpRightDelimitor)
  1306. {
  1307. HRESULT hr = E_FAIL;
  1308. BOOL bRet;
  1309. LPWSTR lpMatchedStr;
  1310. WCHAR wszOldValue[MAX_PATH*20];
  1311. WCHAR wszNewValue[MAX_PATH];
  1312. DWORD cchCopied;
  1313. cchCopied = GetPrivateProfileString(g_wszTargetLCIDSection,
  1314. lpKey,
  1315. TEXT(""),
  1316. wszOldValue,
  1317. ARRAYSIZE(wszOldValue),
  1318. g_wszOutputFile);
  1319. if (cchCopied > 0)
  1320. {
  1321. if (lpMatchedStr = StrStrI(wszOldValue, lpMatch))
  1322. {
  1323. hr = ExtractSubString(wszNewValue,
  1324. ARRAYSIZE(wszNewValue),
  1325. lpMatchedStr,
  1326. lpLeftDelimitor,
  1327. lpRightDelimitor);
  1328. if (SUCCEEDED(hr))
  1329. {
  1330. WCHAR wszQuoted[MAX_PATH];
  1331. hr = StringCchPrintf(wszQuoted,
  1332. ARRAYSIZE(wszQuoted),
  1333. TEXT("\"%s\""),
  1334. wszNewValue);
  1335. if (SUCCEEDED(hr))
  1336. {
  1337. bRet = WritePrivateProfileString(g_wszTargetLCIDSection,
  1338. lpValueName,
  1339. wszQuoted,
  1340. g_wszOutputFile);
  1341. if (bRet)
  1342. {
  1343. hr = S_OK;
  1344. }
  1345. else
  1346. {
  1347. hr = HRESULT_FROM_WIN32(GetLastError());
  1348. }
  1349. }
  1350. }
  1351. }
  1352. else
  1353. {
  1354. // Unneeded string not found
  1355. hr = S_FALSE;
  1356. }
  1357. }
  1358. else
  1359. {
  1360. hr = HRESULT_FROM_WIN32(GetLastError());
  1361. }
  1362. return hr;
  1363. }
  1364. HRESULT GetExpString(
  1365. LPWSTR lpUnneededString, // Returned buffer
  1366. DWORD cchUnneededString, // Size of buffer in WCHAR
  1367. LPCWSTR lpString // String with %Key%
  1368. )
  1369. {
  1370. HRESULT hr = E_FAIL;
  1371. LPCWSTR lpBegin;
  1372. LPCWSTR lpEnd;
  1373. if (lpUnneededString == NULL || lpString == NULL)
  1374. {
  1375. return E_INVALIDARG;
  1376. }
  1377. //
  1378. // Find the key name from Source string
  1379. //
  1380. lpBegin = StrChr(lpString, TEXT('%'));
  1381. if (lpBegin)
  1382. {
  1383. // Begin of key name
  1384. lpBegin++;
  1385. // End of key name
  1386. lpEnd = StrChr(lpBegin, TEXT('%'));
  1387. if (lpEnd)
  1388. {
  1389. DWORD cchLen;
  1390. WCHAR wszKey[MAX_PATH];
  1391. cchLen = (DWORD) (lpEnd - lpBegin);
  1392. if (cchLen >= cchUnneededString)
  1393. {
  1394. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1395. }
  1396. else
  1397. {
  1398. // Got the key name, needs one more char for a '\0'
  1399. if (lstrcpyn(wszKey, lpBegin, cchLen + 1))
  1400. {
  1401. WCHAR wszOldSubStr[MAX_PATH];
  1402. WCHAR wszNewSubStr[MAX_PATH];
  1403. DWORD cchCopied;
  1404. // Get the value of key name from output file
  1405. cchCopied = GetPrivateProfileString(g_wszTargetLCIDSection,
  1406. wszKey,
  1407. TEXT(""),
  1408. wszNewSubStr,
  1409. ARRAYSIZE(wszNewSubStr),
  1410. g_wszOutputFile);
  1411. if (cchCopied > 0)
  1412. {
  1413. hr = StringCchPrintf(wszOldSubStr,
  1414. ARRAYSIZE(wszOldSubStr),
  1415. TEXT("%%%s%%"),
  1416. wszKey);
  1417. if (SUCCEEDED(hr))
  1418. {
  1419. // Substitute %Key% with the new value
  1420. hr = StringSubstitute(lpUnneededString,
  1421. cchUnneededString,
  1422. lpString,
  1423. wszOldSubStr,
  1424. wszNewSubStr);
  1425. }
  1426. }
  1427. }
  1428. }
  1429. }
  1430. }
  1431. if (hr == E_FAIL)
  1432. {
  1433. hr = HRESULT_FROM_WIN32(GetLastError());
  1434. }
  1435. return hr;
  1436. }