Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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