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.

1435 lines
44 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <windows.h>
  5. #include <assert.h>
  6. #include <io.h>
  7. #include <md5.h>
  8. #include <strsafe.h> // safe string
  9. #include "muibld.h"
  10. typedef struct
  11. {
  12. BOOL bContainResource;
  13. MD5_CTX ChecksumContext;
  14. pCommandLineInfo pInfo;
  15. } CHECKSUM_ENUM_DATA;
  16. void ExitFromOutOfMemory();
  17. void ExitFromSafeStringError();
  18. void DumpResourceDirectory
  19. (
  20. PIMAGE_RESOURCE_DIRECTORY resDir,
  21. DWORD resourceBase,
  22. DWORD level,
  23. DWORD resourceType
  24. );
  25. int g_bVerbose = FALSE; // Global flag to contorl verbose output.
  26. WORD wChecksumLangId;
  27. // The predefined resource types
  28. char *SzResourceTypes[] = {
  29. "???_0", "CURSOR", "BITMAP", "ICON", "MENU", "DIALOG", "STRING", "FONTDIR",
  30. "FONT", "ACCELERATORS", "RCDATA", "MESSAGETABLE", "GROUP_CURSOR",
  31. "???_13", "GROUP_ICON", "???_15", "VERSION"
  32. };
  33. void PrintError()
  34. {
  35. LPTSTR lpMsgBuf;
  36. if (FormatMessage(
  37. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  38. NULL,
  39. GetLastError(),
  40. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  41. (LPTSTR) &lpMsgBuf,
  42. 0,
  43. NULL
  44. ))
  45. {
  46. printf("GetLastError():\n %s", lpMsgBuf);
  47. LocalFree( lpMsgBuf );
  48. }
  49. return;
  50. }
  51. ////////////////////////////////////////////////////////////////////////////////////
  52. //
  53. // ChecksumEnumNamesFunc
  54. //
  55. // The callback funciton for enumerating the resource names in the specified module and
  56. // type.
  57. // The side effect is that MD5 checksum context (contained in CHECKSUM_ENUM_DATA
  58. // pointed by lParam) will be updated.
  59. //
  60. // Return:
  61. // Always return TRUE so that we can finish all resource enumeration.
  62. //
  63. ////////////////////////////////////////////////////////////////////////////////////
  64. BOOL CALLBACK ChecksumEnumNamesFunc(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG_PTR lParam){
  65. HRSRC hRsrc;
  66. HGLOBAL hRes;
  67. const unsigned char* pv;
  68. LONG ResSize=0L;
  69. WORD IdFlag=0xFFFF;
  70. DWORD dwHeaderSize=0L;
  71. CHECKSUM_ENUM_DATA* pChecksumEnumData = (CHECKSUM_ENUM_DATA*)lParam;
  72. if(!(hRsrc=FindResourceEx(hModule, lpType, lpName, wChecksumLangId ? wChecksumLangId : 0x409)))
  73. {
  74. //
  75. // If US English resource is not found for the specified type and name, we
  76. // will continue the resource enumeration.
  77. //
  78. return (TRUE);
  79. }
  80. pChecksumEnumData->bContainResource = TRUE;
  81. if (!(ResSize=SizeofResource(hModule, hRsrc)))
  82. {
  83. printf("WARNING: Can not get resource size when generating resource checksum.\n");
  84. return (TRUE);
  85. }
  86. if (!(hRes=LoadResource(hModule, hRsrc)))
  87. {
  88. printf("WARNING: Can not load resource when generating resource checksum.\n");
  89. return (TRUE);
  90. }
  91. pv=(unsigned char*)LockResource(hRes);
  92. //
  93. // Update MD5 context using the binary data of this particular resource.
  94. //
  95. MD5Update(&(pChecksumEnumData->ChecksumContext), pv, ResSize);
  96. return TRUE;
  97. }
  98. ////////////////////////////////////////////////////////////////////////////////////
  99. //
  100. // ChecksumEnumTypesFunc
  101. //
  102. // The callback function for enumerating the resource types in the specified module.
  103. // This function will call EnumResourceNames() to enumerate all resource names of
  104. // the specified resource type.
  105. //
  106. // Return:
  107. // TRUE if EnumResourceName() succeeds. Otherwise FALSE.
  108. //
  109. ////////////////////////////////////////////////////////////////////////////////////
  110. BOOL CALLBACK ChecksumEnumTypesFunc(HMODULE hModule, LPSTR lpType, LONG_PTR lParam)
  111. {
  112. CHECKSUM_ENUM_DATA* pChecksumEnumData = (CHECKSUM_ENUM_DATA*)lParam;
  113. //
  114. // Skip the version resource type, so that version is not included in the resource checksum.
  115. //
  116. if (lpType == RT_VERSION)
  117. {
  118. return (TRUE);
  119. }
  120. //
  121. // If muibld include -i arg. but the lpType is not in the -i arg. values, it does not
  122. // use lpType for checksum calculation.
  123. //
  124. if(pChecksumEnumData->pInfo->bIncludeFlag &&
  125. !bTypeIncluded((char *)lpType, pChecksumEnumData->pInfo->pszIncResType)) {
  126. return TRUE;
  127. }
  128. if(!EnumResourceNames(hModule, (LPCSTR)lpType, ChecksumEnumNamesFunc, (LONG_PTR)lParam))
  129. {
  130. return (FALSE);
  131. }
  132. return (TRUE);
  133. }
  134. ////////////////////////////////////////////////////////////////////////////////////
  135. //
  136. // GenerateResourceChecksum
  137. //
  138. // Generate the resource checksum for the US English resource in the specified file.
  139. //
  140. // Parameters:
  141. // pszSourceFileName The file used to generate resource checksum.
  142. // pResourceChecksum Pointer to a 16 bytes (128 bits) buffer for storing
  143. // the calcuated MD5 checksum.
  144. // pInfo pCommandLineInfo structure.the routine refer to
  145. // pszChecksumFile, pResourceChecksum, pszIncResType.
  146. // Return:
  147. // TURE if resource checksum is generated from the given file. Otherwise FALSE.
  148. //
  149. // The following situation may return FALSE:
  150. // * The specified file does not contain resource.
  151. // * If the specified file contains resource, but the resource is not US English.
  152. // * The specified file only contains US English version resource.
  153. //
  154. // Note.
  155. // muibld calculate the checksum only based of included resource types by -i arg.
  156. //
  157. ////////////////////////////////////////////////////////////////////////////////////
  158. BOOL GenerateResourceChecksum(pCommandLineInfo pInfo) // LPCSTR pszSourceFileName, unsigned char* pResourceChecksum)
  159. {
  160. ULONG i;
  161. HMODULE hModule = NULL;
  162. DWORD dwResultLen;
  163. BOOL bRet = FALSE;
  164. //
  165. // The stucture to be passed into the resource enumeration functions.
  166. //
  167. CHECKSUM_ENUM_DATA checksumEnumData;
  168. checksumEnumData.bContainResource = FALSE;
  169. checksumEnumData.pInfo = pInfo;
  170. //
  171. // Start MD5 checksum calculation by initializing MD5 context.
  172. //
  173. MD5Init(&(checksumEnumData.ChecksumContext));
  174. // Info.pszChecksumFile, Info.pResourceChecksum
  175. if (g_bVerbose)
  176. {
  177. printf("Generate resource checksum for [%s]\n", pInfo->pszChecksumFile);
  178. }
  179. if(!(hModule = LoadLibraryEx(pInfo->pszChecksumFile, NULL, DONT_RESOLVE_DLL_REFERENCES|LOAD_LIBRARY_AS_DATAFILE)))
  180. {
  181. if (g_bVerbose)
  182. {
  183. printf("\nERROR: Error in opening resource checksum module [%s]\n", pInfo->pszChecksumFile);
  184. }
  185. PrintError();
  186. goto GR_EXIT;
  187. }
  188. if (g_bVerbose)
  189. {
  190. printf("\nLoad checksum file: %s\n", pInfo->pszChecksumFile);
  191. }
  192. //
  193. // we check language id of Version resource if it has wChecksumLangId when wChecksumLangId has value
  194. //
  195. if (wChecksumLangId && wChecksumLangId != 0x409)
  196. {
  197. if(!FindResourceEx(hModule, MAKEINTRESOURCE(16), MAKEINTRESOURCE(1), wChecksumLangId))
  198. { //
  199. // It does not has specifed language id in version resource, we supposed that this binary does not
  200. // have any language id specified at all, so we set it as 0 in order to use English instead.
  201. //
  202. wChecksumLangId = 0;
  203. }
  204. }
  205. //
  206. // Enumerate all resources in the specified module.
  207. // During the enumeration, the MD5 context will be updated.
  208. //
  209. if (!EnumResourceTypes(hModule, ChecksumEnumTypesFunc, (LONG_PTR)&checksumEnumData))
  210. {
  211. if (g_bVerbose)
  212. {
  213. printf("\nWARNING: Unable to generate resource checksum from resource checksum module [%s]\n", pInfo->pszChecksumFile);
  214. }
  215. goto GR_EXIT;
  216. }
  217. if (checksumEnumData.bContainResource)
  218. {
  219. //
  220. // If the enumeration succeeds, and the specified file contains US English
  221. // resource, get the MD5 checksum from the accumulated MD5 context.
  222. //
  223. MD5Final(&checksumEnumData.ChecksumContext);
  224. memcpy(checksumEnumData.pInfo->pResourceChecksum, checksumEnumData.ChecksumContext.digest, 16);
  225. if (g_bVerbose)
  226. {
  227. printf("Generated checksum: [");
  228. for (i = 0; i < MD5_CHECKSUM_SIZE; i++)
  229. {
  230. printf("%02x ", pInfo->pResourceChecksum[i]);
  231. }
  232. printf("]\n");
  233. }
  234. bRet = TRUE;
  235. }
  236. GR_EXIT:
  237. if (hModule)
  238. {
  239. FreeLibrary(hModule);
  240. }
  241. return (bRet);
  242. }
  243. int __cdecl main(int argc, char *argv[]){
  244. struct CommandLineInfo Info;
  245. HMODULE hModule=0;
  246. char pszBuffer[400];
  247. DWORD dwError;
  248. DWORD dwOffset;
  249. BOOL bEnumTypesReturn;
  250. if(argc==1){
  251. Usage();
  252. return 0;
  253. }
  254. g_bVerbose=FALSE;
  255. wChecksumLangId=0;
  256. Info.pszIncResType=0;
  257. Info.wLanguage=0;
  258. Info.hFile=0;
  259. Info.pszSource=0;
  260. Info.pszTarget=0;
  261. Info.bContainsOnlyVersion=TRUE;
  262. Info.bContainsResources=FALSE;
  263. Info.bLanguageFound=FALSE;
  264. Info.bIncDependent=FALSE;
  265. Info.bIncludeFlag=FALSE;
  266. Info.pszChecksumFile=NULL;
  267. Info.bIsResChecksumGenerated = FALSE;
  268. if(ParseCommandLine(argc, argv, &Info)==FALSE){
  269. //...If help was the only command line argument, exit
  270. if(strcmp(argv[1], "-h")==0 && argc==2)
  271. return 0;
  272. dwError=ERROR_TOO_FEW_ARGUMENTS;
  273. dwOffset=0;
  274. goto Error_Exit;
  275. }
  276. //...Open resource module
  277. if(Info.pszSource){
  278. if(!(hModule = LoadLibraryEx (Info.pszSource, NULL, DONT_RESOLVE_DLL_REFERENCES|LOAD_LIBRARY_AS_DATAFILE)))
  279. {
  280. PrintError();
  281. if (g_bVerbose)
  282. {
  283. printf("\nERROR: Error in opening source module [%s]\n", Info.pszSource);
  284. }
  285. dwError=GetLastError();
  286. dwOffset=ERROR_OFFSET;
  287. goto Error_Exit;
  288. }
  289. }
  290. else {
  291. Usage();
  292. dwError=ERROR_NO_SOURCE;
  293. dwOffset=0;
  294. goto Error_Exit;
  295. }
  296. if (Info.pszChecksumFile)
  297. {
  298. if (GenerateResourceChecksum(&Info)) // c))
  299. {
  300. Info.bIsResChecksumGenerated = TRUE;
  301. }
  302. }
  303. //...Create target file
  304. if(Info.pszTarget){
  305. if((Info.hFile=CreateFile(Info.pszTarget, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
  306. {
  307. if (g_bVerbose)
  308. {
  309. printf("\nERROR: Error in creating target module [%s]\n", Info.pszSource);
  310. }
  311. dwError=GetLastError();
  312. dwOffset=ERROR_OFFSET;
  313. goto Error_Exit;
  314. }
  315. }
  316. else{
  317. if (g_bVerbose)
  318. {
  319. printf("\nERROR: There is no target file name.");
  320. }
  321. Usage();
  322. dwError=ERROR_NO_TARGET;
  323. dwOffset=0;
  324. goto Error_Exit;
  325. }
  326. if(Info.wLanguage==0){
  327. if (g_bVerbose)
  328. {
  329. printf("\nERROR: Can not find specified language name in the source module.");
  330. }
  331. Usage();
  332. dwError=ERROR_NO_LANGUAGE_SPECIFIED;
  333. dwOffset=0;
  334. goto Error_Exit;
  335. }
  336. bInsertHeader(Info.hFile);
  337. bEnumTypesReturn=EnumResourceTypes(hModule, EnumTypesFunc, (LONG_PTR)&Info);
  338. //...Check for muibld errors
  339. if(!Info.bContainsResources){
  340. if (g_bVerbose)
  341. {
  342. printf("\nERROR: There is no resource in the source module.");
  343. }
  344. dwError=ERROR_NO_RESOURCES;
  345. dwOffset=0;
  346. goto Error_Exit;
  347. }
  348. if(!Info.bLanguageFound){
  349. if (g_bVerbose)
  350. {
  351. printf("\nERROR: Resource in the specified language is not found in the source module.");
  352. }
  353. dwError=ERROR_LANGUAGE_NOT_IN_SOURCE;
  354. dwOffset=0;
  355. goto Error_Exit;
  356. }
  357. if(Info.bContainsOnlyVersion){
  358. if (g_bVerbose)
  359. {
  360. printf("\nERROR: The source module only contains version information.");
  361. }
  362. dwError=ERROR_ONLY_VERSION_STAMP;
  363. dwOffset=0;
  364. goto Error_Exit;
  365. }
  366. //...Check for system errors in EnumResourceTypes
  367. if(bEnumTypesReturn);
  368. else{
  369. dwError=GetLastError();
  370. dwOffset=ERROR_OFFSET;
  371. goto Error_Exit;
  372. }
  373. //...Check to see if extra resources were included
  374. if(Info.bIncDependent){
  375. CleanUp(&Info, hModule, FALSE);
  376. return DEPENDENT_RESOURCE_REMOVED;
  377. }
  378. CleanUp(&Info, hModule, FALSE);
  379. if (g_bVerbose)
  380. {
  381. printf("Resource file [%s] has been generated successfully.\n", Info.pszTarget);
  382. }
  383. return 0;
  384. Error_Exit:
  385. CleanUp(&Info, hModule, TRUE);
  386. if(dwOffset==ERROR_OFFSET){
  387. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPTSTR)pszBuffer, 399, NULL);
  388. fprintf(stderr, "\n%s\n", pszBuffer );
  389. }
  390. return dwError+dwOffset;
  391. }
  392. BOOL ParseCommandLine(int argc, char **argv, pCommandLineInfo pInfo){
  393. int iCount=1, chOpt=0, iLast=argc;
  394. int i;
  395. int iNumInc;
  396. BOOL bInc1=FALSE, bInc3=FALSE, bInc12=FALSE, bInc14=FALSE;
  397. HRESULT hr;
  398. HANDLE hFile;
  399. iLast=argc;
  400. //...Must have at least: muibld -l langid source
  401. if(argc>3){
  402. //...Determine the target and source files.
  403. hFile = CreateFile(argv[argc-2], 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  404. if(hFile !=INVALID_HANDLE_VALUE){
  405. CloseHandle(hFile);
  406. pInfo->pszSource=LocalAlloc(0, (strlen(argv[argc-2])+1) * sizeof(char));
  407. if (pInfo->pszSource == NULL)
  408. {
  409. ExitFromOutOfMemory();
  410. }
  411. // strcpy(pInfo->pszSource, argv[argc-2]);
  412. hr = StringCchCopyA(pInfo->pszSource, (strlen(argv[argc-2])+1) * sizeof(char),argv[argc-2]);
  413. if ( ! SUCCEEDED(hr)){
  414. ExitFromSafeStringError();
  415. }
  416. pInfo->pszTarget=LocalAlloc(0, (strlen(argv[argc-1])+1) * sizeof(char));
  417. if (pInfo->pszTarget == NULL)
  418. {
  419. ExitFromOutOfMemory();
  420. }
  421. // strcpy(pInfo->pszTarget, argv[argc-1]);
  422. hr = StringCchCopyA(pInfo->pszTarget, (strlen(argv[argc-1])+1) * sizeof(char), argv[argc-1]);
  423. if ( ! SUCCEEDED(hr)){
  424. ExitFromSafeStringError();
  425. }
  426. iLast=argc-2;
  427. }
  428. else {
  429. pInfo->pszSource=LocalAlloc(0, (strlen(argv[argc-1])+1) * sizeof(char));
  430. if (pInfo->pszSource == NULL)
  431. {
  432. ExitFromOutOfMemory();
  433. }
  434. //strcpy(pInfo->pszSource, argv[argc-1]);
  435. hr = StringCchCopyA(pInfo->pszSource, (strlen(argv[argc-1])+1) * sizeof(char), argv[argc-1]);
  436. if ( ! SUCCEEDED(hr)){
  437. ExitFromSafeStringError();
  438. }
  439. pInfo->pszTarget=LocalAlloc(0, (strlen(argv[argc-1]) + strlen(ADDED_EXT) + 1) * sizeof(char));
  440. if (pInfo->pszTarget == NULL)
  441. {
  442. ExitFromOutOfMemory();
  443. }
  444. //strcpy(pInfo->pszTarget, strcat(argv[argc-1], ADDED_EXT));
  445. hr = StringCchCatA(argv[argc-1], strlen(argv[argc-1]) + sizeof ADDED_EXT + 1, ADDED_EXT);
  446. hr = StringCchCopyA(pInfo->pszTarget, (strlen(argv[argc-1]) + strlen(ADDED_EXT) + 1) * sizeof(char),
  447. argv[argc-1]);
  448. if ( ! SUCCEEDED(hr)){
  449. ExitFromSafeStringError();
  450. }
  451. iLast=argc-1;
  452. }
  453. }
  454. //...Read in flags and arguments
  455. while ( (iCount < iLast) && (*argv[iCount] == '-' || *argv[iCount] == '/')){
  456. switch( ( chOpt = *CharLowerA( &argv[iCount][1]))) {
  457. case '?':
  458. case 'h':
  459. printf("\n\n");
  460. printf("MUIBLD [-h|?] [-v] [-c checksum_file] -l langid [-i resource_type] source_filename\n");
  461. printf(" [target_filename]\n\n");
  462. printf("-h(elp) or -?: Show help screen.\n\n");
  463. printf("-i(nclude) Use to include certain resource types,\n");
  464. printf("resource_type: e.g. -i 2 to include bitmaps.\n");
  465. printf(" Multiple inclusion is possible. If this\n");
  466. printf(" flag is not used, all types are included\n");
  467. printf(" Standard resource types must be specified\n");
  468. printf(" by number. See below for list.\n");
  469. printf(" Types 1 and 12 are always included in pairs,\n");
  470. printf(" even if only one is specified. Types 3 and 14\n");
  471. printf(" are always included in pairs, too.\n\n");
  472. printf("-v(erbose): Display source filename and target filename.\n\n");
  473. printf("-l(anguage) langid: Extract only resource in this language.\n");
  474. printf(" The language resource must be specified. The value is in decimal.\n\n");
  475. printf("source_filename: The localized source file (no wildcard support)\n\n");
  476. printf("target_filename: Optional. If no target_filename is specified,\n");
  477. printf(" a second extension.RES is added to the\n");
  478. printf(" source_filename.\n\n");
  479. printf("Standard Resource Types: CURSOR(1) BITMAP(2) ICON(3) MENU(4) DIALOG(5)\n");
  480. printf("STRING(6) FONTDIR(7) FONT(8) ACCELERATORS(9) RCDATA(10) MESSAGETABLE(11)\n");
  481. printf("GROUP_CURSOR(12) GROUP_ICON(14) VERSION(16)\n");
  482. iCount++;
  483. break;
  484. case 'v':
  485. g_bVerbose=TRUE;
  486. iCount++;
  487. break;
  488. case 'c':
  489. iCount++;
  490. pInfo->pszChecksumFile=LocalAlloc(0, (strlen(argv[iCount])+1) * sizeof(char));
  491. if (pInfo->pszChecksumFile == NULL)
  492. {
  493. ExitFromOutOfMemory();
  494. }
  495. //strcpy(pInfo->pszChecksumFile, argv[iCount]);
  496. hr = StringCchCopyA(pInfo->pszChecksumFile, (strlen(argv[iCount])+1) * sizeof(char),
  497. argv[iCount]);
  498. if ( ! SUCCEEDED(hr)){
  499. ExitFromSafeStringError();
  500. }
  501. iCount++;
  502. break;
  503. case 'b':
  504. iCount++;
  505. wChecksumLangId = (WORD)strtoul(argv[iCount], NULL, 0);
  506. iCount++;
  507. break;
  508. case 'i':
  509. if(argc<4)
  510. return FALSE;
  511. pInfo->bIncludeFlag=TRUE;
  512. iNumInc=++iCount;
  513. //...Allocate memory for and copy included types
  514. while (argv[iNumInc][0]!='-' && iNumInc<iLast){
  515. iNumInc++;
  516. }
  517. iNumInc-=iCount;
  518. //... Allocate enough memory for specified included resources
  519. // and unspecified resources dependent on them
  520. pInfo->pszIncResType=LocalAlloc(0 ,(iNumInc+3)*sizeof(char *));
  521. if (pInfo->pszIncResType == NULL)
  522. {
  523. ExitFromOutOfMemory();
  524. }
  525. i=0;
  526. while(i<iNumInc){
  527. pInfo->pszIncResType[i]=LocalAlloc(0, (strlen(argv[iCount])+1) * sizeof(char));
  528. if (pInfo->pszIncResType[i] == NULL)
  529. {
  530. ExitFromOutOfMemory();
  531. }
  532. //strcpy(pInfo->pszIncResType[i], argv[iCount]);
  533. hr = StringCchCopyA(pInfo->pszIncResType[i], (strlen(argv[iCount])+1) * sizeof(char),
  534. argv[iCount]);
  535. if ( ! SUCCEEDED(hr)){
  536. ExitFromSafeStringError();
  537. }
  538. switch(atoi(argv[iCount])){
  539. case 1:
  540. bInc1=TRUE;
  541. break;
  542. case 3:
  543. bInc3=TRUE;
  544. break;
  545. case 12:
  546. bInc12=TRUE;
  547. break;
  548. case 14:
  549. bInc14=TRUE;
  550. break;
  551. default:
  552. break;
  553. }
  554. i++;
  555. iCount++;
  556. }
  557. //...If 1 or 12 is included, make sure both are included
  558. if(bInc1 ^ bInc12){
  559. pInfo->bIncDependent=TRUE;
  560. if(bInc1){
  561. pInfo->pszIncResType[i]=LocalAlloc(0, 3 * sizeof(char));
  562. if (pInfo->pszIncResType[i] == NULL)
  563. {
  564. ExitFromOutOfMemory();
  565. }
  566. // strcpy(pInfo->pszIncResType[i], "12");
  567. hr = StringCchCopyA(pInfo->pszIncResType[i], 3 * sizeof(char),"12");
  568. if ( ! SUCCEEDED(hr)){
  569. ExitFromSafeStringError();
  570. }
  571. i++;
  572. }
  573. else{
  574. pInfo->pszIncResType[i]=LocalAlloc(0, 2 * sizeof(char));
  575. if (pInfo->pszIncResType[i] == NULL)
  576. {
  577. ExitFromOutOfMemory();
  578. }
  579. // strcpy(pInfo->pszIncResType[i], "1");
  580. hr = StringCchCopyA(pInfo->pszIncResType[i],2 * sizeof(char),"1");
  581. if ( ! SUCCEEDED(hr)){
  582. ExitFromSafeStringError();
  583. }
  584. i++;
  585. }
  586. }
  587. //..If 3 or 14 is included, make sure both are included
  588. if(bInc3 ^ bInc14){
  589. pInfo->bIncDependent=TRUE;
  590. if(bInc3){
  591. pInfo->pszIncResType[i]=LocalAlloc(0, 3 * sizeof(char));
  592. if (pInfo->pszIncResType[i] == NULL)
  593. {
  594. ExitFromOutOfMemory();
  595. }
  596. // strcpy(pInfo->pszIncResType[i], "14");
  597. hr = StringCchCopyA(pInfo->pszIncResType[i],3 * sizeof(char),"14");
  598. if ( ! SUCCEEDED(hr)){
  599. ExitFromSafeStringError();
  600. }
  601. i++;
  602. }
  603. else{
  604. pInfo->pszIncResType[i]=LocalAlloc(0, 2 * sizeof(char));
  605. if (pInfo->pszIncResType[i] == NULL)
  606. {
  607. ExitFromOutOfMemory();
  608. }
  609. // strcpy(pInfo->pszIncResType[i], "3");
  610. hr = StringCchCopyA(pInfo->pszIncResType[i],2 * sizeof(char),"3");
  611. if ( ! SUCCEEDED(hr)){
  612. ExitFromSafeStringError();
  613. }
  614. i++;
  615. }
  616. }
  617. while(i<iNumInc + 3){
  618. pInfo->pszIncResType[i++]=NULL;
  619. }
  620. break;
  621. case 'l':
  622. if(argc<4)
  623. return FALSE;
  624. iCount++;
  625. pInfo->wLanguage=(WORD)strtol(argv[iCount], NULL, 0);
  626. iCount++;
  627. break;
  628. }
  629. }
  630. if(argc<4)
  631. return FALSE;
  632. else
  633. return TRUE;
  634. }
  635. BOOL CALLBACK EnumTypesFunc(HMODULE hModule, LPTSTR lpType, LONG_PTR lParam){
  636. pCommandLineInfo pInfo;
  637. pInfo=(pCommandLineInfo)lParam;
  638. if(!pInfo->bIncludeFlag || bTypeIncluded((char *)lpType, pInfo->pszIncResType)) {
  639. pInfo->bContainsResources=TRUE;
  640. //...If the type is a string or a number other than 16...
  641. if( (PtrToUlong(lpType) & 0xFFFF0000) || ((WORD)PtrToUlong(lpType)!=16) ){
  642. pInfo->bContainsOnlyVersion=FALSE;
  643. }
  644. if(EnumResourceNames(hModule, (LPCTSTR)lpType, EnumNamesFunc, (LONG_PTR)pInfo));
  645. else {
  646. return FALSE;
  647. }
  648. }
  649. return TRUE;
  650. }
  651. // This is a Var struct within VarFileInfo for storing checksum for the source file.
  652. // The current size for this structure is 56 bytes.
  653. typedef struct VAR_SRC_CHECKSUM
  654. {
  655. WORD wLength;
  656. WORD wValueLength;
  657. WORD wType;
  658. WCHAR szResourceChecksum[17]; // For storing "ResourceChecksum" null-terminated string in Unicode.
  659. DWORD dwChecksum[4]; // 128 bit checksum = 16 bytes = 4 DWORD.
  660. } VarResourceChecksum;
  661. // This is a Var struct within VarFileInfo for stroing the resource types used in this file.
  662. struct VarResourceTypes
  663. {
  664. WORD wLength;
  665. WORD wValueLength;
  666. WORD wType;
  667. WCHAR szResourceType[13];
  668. //BYTE padding[0]; // WORD * 3 + UnicodeChar*13 = 32 bytes. So we need 0 bytes padding for DWORD alignment.
  669. DWORD* dwTypes; // 128 bit checksum = 16 bytes = 4 DWORD.
  670. };
  671. BOOL WriteResHeader(
  672. HANDLE hFile, LONG ResSize, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, DWORD* pdwBytesWritten, DWORD* pdwHeaderSize)
  673. {
  674. DWORD iPadding;
  675. WORD IdFlag=0xFFFF;
  676. unsigned i;
  677. LONG dwOffset;
  678. //...write the resource's size.
  679. PutDWord(hFile, ResSize, pdwBytesWritten, pdwHeaderSize);
  680. //...Put in bogus header size
  681. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize);
  682. //...Write Resource Type
  683. if(PtrToUlong(lpType) & 0xFFFF0000)
  684. {
  685. PutString(hFile, lpType, pdwBytesWritten, pdwHeaderSize);
  686. }
  687. else
  688. {
  689. PutWord(hFile, IdFlag, pdwBytesWritten, pdwHeaderSize);
  690. PutWord(hFile, (USHORT)lpType, pdwBytesWritten, pdwHeaderSize);
  691. }
  692. //...Write Resource Name
  693. if(PtrToUlong(lpName) & 0xFFFF0000){
  694. PutString(hFile, lpName, pdwBytesWritten, pdwHeaderSize);
  695. }
  696. else{
  697. PutWord(hFile, IdFlag, pdwBytesWritten, pdwHeaderSize);
  698. PutWord(hFile, (USHORT)lpName, pdwBytesWritten, pdwHeaderSize);
  699. }
  700. //...Make sure Type and Name are DWORD-aligned
  701. iPadding=(*pdwHeaderSize)%(sizeof(DWORD));
  702. if(iPadding){
  703. for(i=0; i<(sizeof(DWORD)-iPadding); i++){
  704. PutByte (hFile, 0, pdwBytesWritten, pdwHeaderSize);
  705. }
  706. }
  707. //...More Win32 header stuff
  708. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize);
  709. PutWord(hFile, 0x1030, pdwBytesWritten, pdwHeaderSize);
  710. //...Write Language
  711. PutWord(hFile, wLanguage, pdwBytesWritten, pdwHeaderSize);
  712. //...More Win32 header stuff
  713. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize); //... Version
  714. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize); //... Characteristics
  715. dwOffset=(*pdwHeaderSize)-4;
  716. //...Set file pointer to where the header size is
  717. if(SetFilePointer(hFile, -dwOffset, NULL, FILE_CURRENT));
  718. else{
  719. return FALSE;
  720. }
  721. PutDWord(hFile, (*pdwHeaderSize), pdwBytesWritten, NULL);
  722. //...Set file pointer back to the end of the header
  723. if(SetFilePointer(hFile, dwOffset-4, NULL, FILE_CURRENT));
  724. else {
  725. return FALSE;
  726. }
  727. return (TRUE);
  728. }
  729. BOOL WriteResource(HANDLE hFile, HMODULE hModule, WORD wLanguage, LPCSTR lpName, LPCSTR lpType, HRSRC hRsrc)
  730. {
  731. HGLOBAL hRes;
  732. PVOID pv;
  733. LONG ResSize=0L;
  734. DWORD iPadding;
  735. unsigned i;
  736. DWORD dwBytesWritten;
  737. DWORD dwHeaderSize=0L;
  738. // Handle other types other than VS_VERSION_INFO
  739. //...write the resource header
  740. if(!(ResSize=SizeofResource(hModule, hRsrc)))
  741. {
  742. return FALSE;
  743. }
  744. //
  745. // Generate an item in the RES format (*.res) file.
  746. //
  747. //
  748. // First, we generated header for this resource.
  749. //
  750. if (!WriteResHeader(hFile, ResSize, lpType, lpName, wLanguage, &dwBytesWritten, &dwHeaderSize))
  751. {
  752. return (FALSE);
  753. }
  754. //Second, we copy resource data to the .res file
  755. if (!(hRes=LoadResource(hModule, hRsrc)))
  756. {
  757. return FALSE;
  758. }
  759. if(!(pv=LockResource(hRes)))
  760. {
  761. return FALSE;
  762. }
  763. if (!WriteFile(hFile, pv, ResSize, &dwBytesWritten, NULL))
  764. {
  765. return FALSE;
  766. }
  767. //...Make sure resource is DWORD aligned
  768. iPadding=dwBytesWritten%(sizeof(DWORD));
  769. if(iPadding){
  770. for(i=0; i<(sizeof(DWORD)-iPadding); i++){
  771. PutByte (hFile, 0, &dwBytesWritten, NULL);
  772. }
  773. }
  774. return TRUE;
  775. }
  776. LPBYTE UpdateAddr(LPBYTE pAddr, WORD size, WORD* len)
  777. {
  778. *len += size;
  779. return (pAddr + size);
  780. }
  781. LPBYTE AddPadding(LPBYTE pAddr, WORD* padding, WORD* len)
  782. {
  783. if ((*padding = *len % 4) != 0)
  784. {
  785. *padding = (4 - *padding);
  786. *len += *padding;
  787. return (pAddr + *padding);
  788. }
  789. return (pAddr);
  790. }
  791. BOOL WriteVersionResource(
  792. HANDLE hFile, HMODULE hModule, WORD wLanguage, LPCSTR lpName, LPCSTR lpType, HRSRC hRsrc, unsigned char* pbChecksum)
  793. {
  794. LONG ResSize=0L, OldResSize=0L;
  795. DWORD dwBytesWritten;
  796. DWORD dwHeaderSize=0L;
  797. WORD IdFlag=0xFFFF;
  798. BYTE* newVersionData;
  799. BYTE* pAddr;
  800. VarResourceChecksum varResourceChecksum;
  801. PVOID pv = NULL;
  802. HGLOBAL hRes;
  803. WORD len = 0;
  804. WORD wLength;
  805. WORD wValueLength;
  806. WORD wType;
  807. LPWSTR szKey;
  808. WORD wPadding1Count;
  809. LPBYTE pValue;
  810. WORD wPadding2Count;
  811. int wTotalLen;
  812. BOOL isVS_VERSIONINFO = TRUE;
  813. BOOL isVarFileInfo = FALSE;
  814. BOOL isStringFileInfo = FALSE;
  815. BOOL bRet = FALSE;
  816. HRESULT hr;
  817. //
  818. // Copy resource data from the .res file
  819. //
  820. if (hRes=LoadResource(hModule, hRsrc))
  821. {
  822. pv=LockResource(hRes);
  823. }
  824. if (pv)
  825. {
  826. //
  827. // The first WORD is the size of the VERSIONINFO resource.
  828. //
  829. OldResSize = *((WORD*)pv);
  830. ResSize = OldResSize + sizeof(VarResourceChecksum);
  831. //
  832. // Generate an item in the RES format (*.res) file.
  833. //
  834. //
  835. // First, we generated header for this resource in the RES file.
  836. //
  837. if (WriteResHeader(hFile, ResSize, lpType, lpName, wLanguage, &dwBytesWritten, &dwHeaderSize) &&
  838. (newVersionData = (BYTE*)LocalAlloc(0, ResSize)))
  839. {
  840. bRet = TRUE;
  841. memcpy(newVersionData, pv, OldResSize);
  842. // Add the length of new VarResourceChecksum structure to VS_VERSIONINFO.wLength.
  843. pAddr = newVersionData;
  844. wTotalLen = *((WORD*)pAddr);
  845. while (wTotalLen > 0)
  846. {
  847. len = 0;
  848. wPadding1Count = 0;
  849. wPadding2Count = 0;
  850. // wLength
  851. wLength = *((WORD*)pAddr);
  852. pAddr = UpdateAddr(pAddr, sizeof(WORD), &len);
  853. // wValueLength
  854. wValueLength = *((WORD*)pAddr);
  855. pAddr = UpdateAddr(pAddr, sizeof(WORD), &len);
  856. // wType
  857. wType = *((WORD*)pAddr);
  858. pAddr = UpdateAddr(pAddr, sizeof(WORD), &len);
  859. // szKey
  860. szKey = (LPWSTR)pAddr;
  861. pAddr = UpdateAddr(pAddr, (WORD)((wcslen((WCHAR*)pAddr) + 1) * sizeof(WCHAR)), &len);
  862. // Padding 1
  863. pAddr = AddPadding(pAddr, &wPadding1Count, &len);
  864. // Value
  865. pValue = pAddr;
  866. if (wValueLength > 0)
  867. {
  868. if (wType==1)
  869. {
  870. // In the case of String, the wValueLength is in WORD (not in BYTE).
  871. pAddr = UpdateAddr(pAddr, (WORD)(wValueLength * sizeof(WCHAR)), &len);
  872. // Padding 2
  873. pAddr = AddPadding(pAddr, &wPadding2Count, &len);
  874. } else
  875. {
  876. pAddr = UpdateAddr(pAddr, wValueLength, &len);
  877. if (isStringFileInfo)
  878. {
  879. //
  880. // Generally, padding is not necessary in binary data.
  881. // However, in some rare cases, people use binary data in the StringFileInfo (
  882. // which is not really appropriate),
  883. // So we need to add proper padding here to get around this.
  884. //
  885. // Padding 2
  886. pAddr = AddPadding(pAddr, &wPadding2Count, &len);
  887. }
  888. }
  889. }
  890. if (isVS_VERSIONINFO)
  891. {
  892. //
  893. // This is VS_VERSION_INFO.
  894. //
  895. // VS_VERSIONINFO can have padding 2.
  896. isVS_VERSIONINFO = FALSE;
  897. // Padding 2
  898. pAddr = AddPadding(pAddr, &wPadding2Count, &len);
  899. //
  900. // Add the new VarResourceChecksum structure.
  901. //
  902. wLength += sizeof(VarResourceChecksum);
  903. }
  904. if (wcscmp(szKey, L"StringFileInfo") == 0)
  905. {
  906. isStringFileInfo = TRUE;
  907. }
  908. if (wcscmp(szKey, L"VarFileInfo") == 0)
  909. {
  910. isStringFileInfo = FALSE;
  911. isVarFileInfo = TRUE;
  912. wLength += sizeof(VarResourceChecksum);
  913. }
  914. PutWord(hFile, wLength, &dwBytesWritten, NULL);
  915. PutWord(hFile, wValueLength, &dwBytesWritten, NULL);
  916. PutWord(hFile, wType, &dwBytesWritten, NULL);
  917. PutStringW(hFile, szKey, &dwBytesWritten, NULL);
  918. PutPadding(hFile, wPadding1Count, &dwBytesWritten, NULL);
  919. WriteFile(hFile, pValue, wValueLength * (wType == 0 ? sizeof(BYTE) : sizeof(WCHAR)), &dwBytesWritten, NULL);
  920. PutPadding(hFile, wPadding2Count, &dwBytesWritten, NULL);
  921. if (isVarFileInfo && wcscmp(szKey, L"Translation") == 0)
  922. {
  923. isVarFileInfo = FALSE;
  924. varResourceChecksum.wLength = sizeof(VarResourceChecksum);
  925. varResourceChecksum.wValueLength = 16; // 128 bits checksum = 16 bytes
  926. varResourceChecksum.wType = 0;
  927. // wcscpy(varResourceChecksum.szResourceChecksum, RESOURCE_CHECK_SUM);
  928. hr = StringCchCopyW(varResourceChecksum.szResourceChecksum, sizeof (varResourceChecksum.szResourceChecksum)/ sizeof (WCHAR),
  929. RESOURCE_CHECK_SUM);
  930. if ( ! SUCCEEDED(hr)){
  931. ExitFromSafeStringError();
  932. }
  933. memcpy(varResourceChecksum.dwChecksum, pbChecksum, 16);
  934. if (!WriteFile(hFile, &varResourceChecksum, sizeof(VarResourceChecksum), &dwBytesWritten, NULL))
  935. {
  936. bRet = FALSE;
  937. break;
  938. }
  939. }
  940. wTotalLen -= len;
  941. }
  942. LocalFree(newVersionData);
  943. }
  944. }
  945. return (bRet);
  946. }
  947. BOOL CALLBACK EnumLangsFunc(
  948. HANDLE hModule, // module handle
  949. LPCTSTR lpType, // address of resource type
  950. LPCTSTR lpName, // address of resource name
  951. WORD wLang, // resource language
  952. LONG_PTR lParam) // extra parameter, could be
  953. // used for error checking
  954. {
  955. HANDLE hResInfo;
  956. char szBuffer[80];
  957. int cbString = 0;
  958. pCommandLineInfo pInfo;
  959. if (lParam == 0)
  960. {
  961. printf("EnumLangsFunc: lParam is invalid!\n");
  962. return FALSE;
  963. }
  964. pInfo = (pCommandLineInfo) lParam;
  965. //
  966. // only write out the resource if the language id matches, otherwise just skip it and return true
  967. // the call back will return whatever Write(Version)Resource function(s) return
  968. //
  969. //
  970. // Multi lingual binary has more than two language ID, in this case
  971. // we don't want to extract english version resource. (this is a fix of side effect; forcing english version
  972. // saved as localized one)
  973. //
  974. if ((WORD)PtrToUlong(lpType) == 16 && wLang == 0x409 && pInfo->wLanguage != 0x409)
  975. {
  976. hResInfo = FindResourceEx(hModule, lpType, lpName, pInfo->wLanguage);
  977. if (hResInfo)
  978. { // This is multi lingual DLL. we don't want to extract English Version resource.
  979. return TRUE;
  980. }
  981. }
  982. //
  983. // Some files does not localize VERSIOIN so we force VERSION should be added into MUI file as localized one.
  984. // if resource in the binary has more than two types, and type 16 is smallest resource number, then
  985. // it does not work in this routine.
  986. //
  987. if (pInfo->wLanguage == wLang || ( (WORD)PtrToUlong(lpType) == 16 && wLang == 0x409 && pInfo->bLanguageFound ) )
  988. {
  989. pInfo->bLanguageFound=TRUE; // set this to true now that we have found at least one resource
  990. hResInfo=FindResourceEx(hModule, lpType, lpName, pInfo->wLanguage);
  991. if (hResInfo)
  992. {
  993. if (lpType == MAKEINTRESOURCE(RT_VERSION) && pInfo->bIsResChecksumGenerated)
  994. {
  995. //
  996. // If this is a version resource and resource checksum is generated, call
  997. // the following function to embed the resource checksum into the version
  998. // resource.
  999. //
  1000. return (WriteVersionResource(pInfo->hFile, hModule, pInfo->wLanguage, lpName, lpType, hResInfo, pInfo->pResourceChecksum));
  1001. }
  1002. return (WriteResource(pInfo->hFile, hModule, pInfo->wLanguage, lpName, lpType, hResInfo));
  1003. }
  1004. }
  1005. return TRUE;
  1006. }
  1007. BOOL CALLBACK EnumNamesFunc(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG_PTR lParam)
  1008. {
  1009. HRSRC hRsrc;
  1010. pCommandLineInfo pInfo;
  1011. if(lParam == 0)
  1012. {
  1013. printf( "MUIBLD: EnumNamesFunc lParam value incorrect (%d)\n", lParam );
  1014. return FALSE;
  1015. }
  1016. return EnumResourceLanguages(hModule,
  1017. lpType,
  1018. lpName,
  1019. (ENUMRESLANGPROC)EnumLangsFunc,
  1020. lParam);
  1021. }
  1022. BOOL bTypeIncluded(LPCSTR lpType, char **pszIncResType){
  1023. char *pszBuf;
  1024. char **p;
  1025. HRESULT hr;
  1026. if (PtrToUlong(lpType) & 0xFFFF0000) {
  1027. pszBuf=LocalAlloc(0, strlen(lpType) +1);
  1028. if (pszBuf == NULL)
  1029. {
  1030. ExitFromOutOfMemory();
  1031. }
  1032. //sprintf(pszBuf, "%s", lpType);
  1033. hr = StringCbPrintfA(pszBuf, strlen(lpType) +1, "%s", lpType);
  1034. if ( ! SUCCEEDED(hr)){
  1035. ExitFromSafeStringError();
  1036. }
  1037. }
  1038. else {
  1039. WORD wType = (WORD) lpType;
  1040. pszBuf=LocalAlloc(0, sizeof(lpType) + 1);
  1041. if (pszBuf == NULL)
  1042. {
  1043. ExitFromOutOfMemory();
  1044. }
  1045. // sprintf(pszBuf, "%u", wType);
  1046. hr = StringCbPrintfA(pszBuf, sizeof(lpType) +1, "%u", wType);
  1047. if ( ! SUCCEEDED(hr)){
  1048. ExitFromSafeStringError();
  1049. }
  1050. }
  1051. p=pszIncResType;
  1052. while(p && *p){
  1053. if(strcmp(pszBuf, *p)==0)
  1054. return TRUE;
  1055. p++;
  1056. }
  1057. LocalFree(pszBuf);
  1058. return FALSE;
  1059. }
  1060. BOOL bInsertHeader(HANDLE hFile){
  1061. DWORD dwBytesWritten;
  1062. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1063. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1064. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1065. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1066. PutByte (hFile, 0x20, &dwBytesWritten, NULL);
  1067. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1068. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1069. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  1070. PutWord (hFile, 0xffff, &dwBytesWritten, NULL);
  1071. PutWord (hFile, 0x00, &dwBytesWritten, NULL);
  1072. PutWord (hFile, 0xffff, &dwBytesWritten, NULL);
  1073. PutWord (hFile, 0x00, &dwBytesWritten, NULL);
  1074. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  1075. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  1076. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  1077. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  1078. return TRUE;
  1079. }
  1080. void PutByte(HANDLE OutFile, TCHAR b, LONG *plSize1, LONG *plSize2){
  1081. BYTE temp=b;
  1082. if (plSize2){
  1083. (*plSize2)++;
  1084. }
  1085. WriteFile(OutFile, &b, 1, plSize1, NULL);
  1086. }
  1087. void PutWord(HANDLE OutFile, WORD w, LONG *plSize1, LONG *plSize2){
  1088. PutByte(OutFile, (BYTE) LOBYTE(w), plSize1, plSize2);
  1089. PutByte(OutFile, (BYTE) HIBYTE(w), plSize1, plSize2);
  1090. }
  1091. void PutDWord(HANDLE OutFile, DWORD l, LONG *plSize1, LONG *plSize2){
  1092. PutWord(OutFile, LOWORD(l), plSize1, plSize2);
  1093. PutWord(OutFile, HIWORD(l), plSize1, plSize2);
  1094. }
  1095. void PutString(HANDLE OutFile, LPCSTR szStr , LONG *plSize1, LONG *plSize2){
  1096. WORD i = 0;
  1097. do {
  1098. PutWord( OutFile , szStr[ i ], plSize1, plSize2);
  1099. }
  1100. while ( szStr[ i++ ] != TEXT('\0') );
  1101. }
  1102. void PutStringW(HANDLE OutFile, LPCWSTR szStr , LONG *plSize1, LONG *plSize2){
  1103. WORD i = 0;
  1104. do {
  1105. PutWord( OutFile , szStr[ i ], plSize1, plSize2);
  1106. }
  1107. while ( szStr[ i++ ] != L'\0' );
  1108. }
  1109. void PutPadding(HANDLE OutFile, int paddingCount, LONG *plSize1, LONG *plSize2)
  1110. {
  1111. int i;
  1112. for (i = 0; i < paddingCount; i++)
  1113. {
  1114. PutByte(OutFile, 0x00, plSize1, plSize2);
  1115. }
  1116. }
  1117. void Usage(){
  1118. printf("MUIBLD [-h|?] [-c checksum_filename] [-v] -l langid [-i resource_type] source_filename\n");
  1119. printf(" [target_filename]\n\n");
  1120. }
  1121. void CleanUp(pCommandLineInfo pInfo, HANDLE hModule, BOOL bDeleteFile){
  1122. if(hModule)
  1123. FreeLibrary(hModule);
  1124. if(pInfo->hFile)
  1125. CloseHandle(pInfo->hFile);
  1126. if(bDeleteFile && pInfo->pszTarget)
  1127. DeleteFile(pInfo->pszTarget);
  1128. }
  1129. void FreeAll(pCommandLineInfo pInfo){
  1130. char **p;
  1131. LocalFree(pInfo->pszSource);
  1132. LocalFree(pInfo->pszTarget);
  1133. if(pInfo->pszIncResType){
  1134. p=pInfo->pszIncResType;
  1135. while(p && *p){
  1136. LocalFree(*p);
  1137. p++;
  1138. }
  1139. LocalFree(pInfo->pszIncResType);
  1140. }
  1141. }
  1142. void ExitFromOutOfMemory()
  1143. {
  1144. printf("Out of memory. Can not continue. GetLastError() = 0x%x.", GetLastError());
  1145. exit(1);
  1146. }
  1147. void ExitFromSafeStringError()
  1148. {
  1149. printf("Safe string return error. Can not continue.\n");
  1150. exit(1);
  1151. }