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.

1912 lines
61 KiB

  1. /*****************************************************************************
  2. Copyright (c) 2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. cmf.cpp
  5. Abstract:
  6. The implementation of CCompactMUIFile, CMUIFile
  7. Revision History:
  8. 2001-11-01 sunggch created.
  9. Revision.
  10. *******************************************************************************/
  11. #include "muirct.h"
  12. #include "res.h"
  13. #include "cmf.h"
  14. #define DWORD_ALIGNMENT(dwValue) ( (dwValue+3) & ~3 )
  15. #define TEMP_BUFFER 300
  16. #define MUI_COMPACT L"CMF"
  17. ///////////////////////////////////////////////////////////////////////////////////////////
  18. //
  19. // CCompactMUIFile Implementation
  20. //
  21. ///////////////////////////////////////////////////////////////////////////////////////////
  22. CCompactMUIFile::CCompactMUIFile()
  23. {
  24. m_upCMFHeader.dwSignature = 0x1a1b;
  25. m_upCMFHeader.dwHeaderSize = sizeof(UP_COMPACT_MUI_RESOURCE);
  26. m_upCMFHeader.dwNumberofMui = 0;
  27. m_pcmui = new CMUIFile;
  28. if(!m_pcmui)
  29. return;
  30. m_strFileName = new TCHAR[MAX_FILENAME_LENGTH];
  31. if(!m_strFileName)
  32. return;
  33. m_dwFileSize = m_upCMFHeader.dwHeaderSize;
  34. }
  35. CCompactMUIFile::CCompactMUIFile( CCompactMUIFile & ccmf)
  36. {
  37. m_hCMFFile = ccmf.m_hCMFFile;
  38. m_upCMFHeader = ccmf.m_upCMFHeader;
  39. m_pcmui = ccmf.m_pcmui;
  40. m_strFileName = ccmf.m_strFileName;
  41. }
  42. CCompactMUIFile::~CCompactMUIFile()
  43. {
  44. if (m_strFileName)
  45. delete []m_strFileName;
  46. if (m_pcmui)
  47. delete m_pcmui;
  48. }
  49. CCompactMUIFile & CCompactMUIFile::operator= (CCompactMUIFile & ccmf)
  50. {
  51. if(&ccmf == this)
  52. return *this;
  53. m_upCMFHeader = ccmf.m_upCMFHeader;
  54. m_pcmui = ccmf.m_pcmui;
  55. m_strFileName = ccmf.m_strFileName;
  56. return *this;
  57. }
  58. BOOL CCompactMUIFile::Create (LPCTSTR pszCMFFileName, PSTR * ppszMuiFiles, DWORD dwNumOfMUIFiles )
  59. /*++
  60. Abstract:
  61. this is main creation part of CMF Files, we simply call CMUIFile::Create with each indivisual
  62. mui file into specified CMF file.
  63. Arguments:
  64. pszCMFFileName - CMF file name
  65. ppszMuiFiles - MUI files name array
  66. dwNumOfMUIFiles - the number of MUI files, it is important to avoid adding "CMF" section into
  67. DLL several times when this function is called from Adding MUI file to existing CMF file.
  68. return:
  69. true/false
  70. --*/
  71. {
  72. //
  73. // Loading MUI files and fill the headers and create CMFFile with this information.
  74. // calling LoadAllMui [public]
  75. //
  76. if ( pszCMFFileName == NULL || ppszMuiFiles == NULL || * ppszMuiFiles == NULL)
  77. return FALSE;
  78. //
  79. // sec; CreateFile (ascii version) only handle MAX_PATH for file name.
  80. //
  81. m_hCMFFile = CreateFile(pszCMFFileName, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
  82. if ( INVALID_HANDLE_VALUE == m_hCMFFile)
  83. {
  84. CError ce;
  85. ce.ErrorPrint(_T("CCompactMUIFile::Create"),_T("Failure of CreateFile()"));
  86. return FALSE;
  87. }
  88. // just in case, user want to use path for cmf file name. this value will be
  89. // store in updated langNeu file.
  90. LPCSTR pszFileName = m_pcmui->GetFileNameFromPath(pszCMFFileName);
  91. if (strlen (pszFileName)+1 > MAX_FILENAME_LENGTH )
  92. return FALSE; // overflow.
  93. // strncpy(m_strFileName, pszFileName, strlen(pszFileName));
  94. PTSTR * ppszDestEnd = NULL;
  95. size_t * pbRem = NULL;
  96. HRESULT hr;
  97. hr = StringCchCopyEx(m_strFileName, MAX_FILENAME_LENGTH, pszFileName, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  98. if ( ! SUCCEEDED(hr)){
  99. _tprintf("Safe string copy Error\n");
  100. return FALSE;
  101. }
  102. return LoadAllMui(ppszMuiFiles, dwNumOfMUIFiles);
  103. }
  104. BOOL CCompactMUIFile::Create( LPCTSTR pszCMFFileName )
  105. /*++
  106. Abstract:
  107. simpley create CMFFile and set the handle member data.
  108. Arguments:
  109. pszCMFFileName - CMF file name
  110. return:
  111. true/false
  112. --*/
  113. {
  114. if (pszCMFFileName == NULL)
  115. return FALSE;
  116. m_hCMFFile = CreateFile(pszCMFFileName, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
  117. // Can't use file mapping. we don't know the file size be created after all operation.
  118. if ( INVALID_HANDLE_VALUE == m_hCMFFile)
  119. {
  120. CError ce;
  121. ce.ErrorPrint(_T("CCompactMUIFile::Create"),_T("Failure of CreateFile()") );
  122. return FALSE;
  123. }
  124. return TRUE;
  125. }
  126. typedef struct _tagCOMPACT_MUI {
  127. WORD wHeaderSize; // COMPACT_MUI size // [WORD]
  128. DWORD dwFileVersionMS; // [DWORD * 2 ] /major version, minor version.
  129. DWORD dwFileVersionLS;
  130. BYTE Checksum[16]; // [DWORD * 4 ] MD5 checksum
  131. WORD wReserved; // [DWORD ]
  132. ULONG_PTR ulpOffset; //Offset to mui resource of this from COMPACT_MUI_RESOURCE signature. [DWORD]
  133. DWORD dwFileSize;
  134. WORD wFileNameLenWPad; // file name lenght + padding;
  135. WCHAR wstrFieName[MAX_FILENAME_LENGTH]; // [WCHAR]
  136. // WORD wPadding[1]; // [WORD] // does not calcualte in the tools, but shall be
  137. // included specfication.
  138. }COMPACT_MUI, *PCOMPACT_MUI;
  139. BOOL CCompactMUIFile::OpenCMFWithMUI(LPCTSTR pszCMFFile)
  140. /*++
  141. Abstract:
  142. Loading MUI files and fill the headers and create CMFFile with this information.
  143. calling LoadAllMui [public]
  144. Arguments:
  145. pszCMFFile - CMF file name
  146. return:
  147. true/false
  148. --*/
  149. {
  150. BOOL bRet = FALSE;
  151. PSTR pszCMFBuffer = NULL;
  152. if (pszCMFFile == NULL)
  153. goto exit;
  154. m_hCMFFile = CreateFile(pszCMFFile, GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
  155. if ( INVALID_HANDLE_VALUE == m_hCMFFile)
  156. {
  157. CError ce;
  158. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of CreateFile()"));
  159. goto exit;
  160. }
  161. //
  162. // Loading CMF and MUI files inside, fill the header of CMF, MUI.
  163. //
  164. LPCSTR pszFileName = m_pcmui->GetFileNameFromPath(pszCMFFile);
  165. if (strlen (pszFileName)+1 > MAX_FILENAME_LENGTH )
  166. goto exit; // overflow.
  167. strncpy(m_strFileName, pszFileName, strlen(pszFileName)+1 );
  168. DWORD dwFileSize = GetFileSize(m_hCMFFile, NULL);
  169. if( dwFileSize == INVALID_FILE_SIZE)
  170. {
  171. CError ce;
  172. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of GetFileSize()"));
  173. goto exit;
  174. }
  175. pszCMFBuffer = new CHAR[dwFileSize]; // use char for possible byte operation of locating mui data.
  176. if(!pszCMFBuffer)
  177. goto exit;
  178. DWORD dwWritten;
  179. if(! ReadFile(m_hCMFFile, pszCMFBuffer, dwFileSize, &dwWritten, NULL))
  180. {
  181. CError ce;
  182. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of read file"));
  183. goto exit;
  184. }
  185. m_dwFileSize = GetFileSize(m_hCMFFile, NULL);
  186. if( m_dwFileSize == INVALID_FILE_SIZE)
  187. {
  188. CError ce;
  189. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of GetFileSize()"));
  190. goto exit;
  191. }
  192. m_upCMFHeader = *(UP_COMPACT_MUI_RESOURCE* ) pszCMFBuffer;
  193. //
  194. // Retrieve the each MUI header and files and fill the data to new CMUIFile.
  195. //
  196. DWORD dwUpCMFHeaderSize = sizeof UP_COMPACT_MUI_RESOURCE;
  197. for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i ++ )
  198. {
  199. CMUIFile *pcmui = new CMUIFile();
  200. // pc = (COMPACT_MUI*)((PBYTE)pszCMFBuffer + wUpCMFHeaderSize);
  201. PCOMPACT_MUI pcm = NULL;
  202. pcm = (PCOMPACT_MUI)((PBYTE)pszCMFBuffer + dwUpCMFHeaderSize);
  203. // Copy the MUI header
  204. memcpy((PVOID)(&pcmui->m_MUIHeader), (PVOID)pcm, pcm->wHeaderSize );
  205. dwUpCMFHeaderSize += pcmui->m_MUIHeader.wHeaderSize;
  206. // Copy the MUI image, because we are going to close file handle of ReadFile.
  207. pcmui->m_pbImageBase = new TBYTE[pcmui->m_MUIHeader.dwFileSize]; // will be delete in destructor.
  208. memcpy(pcmui->m_pbImageBase, (PBYTE)pszCMFBuffer + pcmui->m_MUIHeader.ulpOffset,
  209. pcmui->m_MUIHeader.dwFileSize);
  210. if(WideCharToMultiByte(CP_ACP, NULL, pcmui->m_MUIHeader.wstrFieName, wcslen(pcmui->m_MUIHeader.wstrFieName)+1,
  211. pcmui->m_strFileName, wcslen(pcmui->m_MUIHeader.wstrFieName)+1, NULL, NULL) == 0) // REVISIT; Does MUI header include its filename for updating case.
  212. {
  213. CError ce;
  214. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of WideCharToMultiByte()"));
  215. delete pcmui;
  216. goto exit;
  217. }
  218. pcmui->m_dwIndex = i;
  219. m_pcvector.Push_back(pcmui);
  220. }
  221. bRet = TRUE;
  222. exit:
  223. if (pszCMFBuffer)
  224. delete [] pszCMFBuffer;
  225. if (m_hCMFFile)
  226. CloseHandle(m_hCMFFile);
  227. m_hCMFFile = NULL; // It still has value although it's freed, so we need to set it NULL.
  228. return bRet;
  229. }
  230. BOOL CCompactMUIFile::LoadAllMui (PSTR *ppszMuiFiles, DWORD dwNumberofMuiFile)
  231. /*++
  232. Abstract:
  233. Load MUI files and create/initialze CMUIFile with these loaded MUI file information.
  234. Arguments:
  235. ppszMuiFiles - MUI files array.
  236. return:
  237. dwNumberofMuiFile - Number of MUI files in the array.
  238. --*/
  239. {
  240. //
  241. // 1. Use FileMapping 2.
  242. //
  243. if (ppszMuiFiles == NULL)
  244. return FALSE;
  245. for (UINT i = 0; i < dwNumberofMuiFile; i++)
  246. {
  247. PSTR pszMUIFile = ppszMuiFiles[i];
  248. if (pszMUIFile == NULL)
  249. return FALSE;
  250. CMUIFile *pcmui = new CMUIFile;
  251. if(!pcmui)
  252. return FALSE;
  253. if (! pcmui->Create(pszMUIFile))
  254. {
  255. CError ce;
  256. ce.ErrorPrint(_T("CCompactMUIFile::LoadAllMui"),_T("Failure of CMUIFile::Create") );
  257. delete pcmui;
  258. return FALSE;
  259. }
  260. //
  261. // Add to the list.
  262. //
  263. m_upCMFHeader.dwHeaderSize += pcmui->m_MUIHeader.wHeaderSize;
  264. m_upCMFHeader.dwNumberofMui++;
  265. m_dwFileSize += pcmui->m_MUIHeader.wHeaderSize + pcmui->m_MUIHeader.dwFileSize;
  266. // Add dwFileSize to the strucuture for sanity check inside Loader.
  267. m_upCMFHeader.dwFileSize = m_dwFileSize;
  268. pcmui->m_dwIndex = (WORD)i;
  269. m_pcvector.Push_back(pcmui);
  270. }
  271. return TRUE;
  272. // REVIST; adjust m_upCMFHeader.wHeaderSize as DWORD aligned.
  273. }
  274. // #define USE_WRITEFILE
  275. BOOL CCompactMUIFile::WriteCMFFile()
  276. /*++
  277. Abstract:
  278. Write a COMPACT_MUI_RESOURCE, COMPACT_MUI, MUI image files;
  279. we need to fill the offset data in COMPACT_MUI header for each files.
  280. Arguments:
  281. return:
  282. true/false
  283. --*/
  284. {
  285. //
  286. // Write the file to real file.
  287. //
  288. if (! m_hCMFFile)
  289. {
  290. m_hCMFFile = CreateFile(m_strFileName, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
  291. if ( INVALID_HANDLE_VALUE == m_hCMFFile)
  292. {
  293. CError ce;
  294. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile"),_T("Failure of CreateFile()"));
  295. return FALSE;
  296. }
  297. }
  298. #ifndef USE_WRITEFILE
  299. HANDLE hFileMapping = CreateFileMapping(m_hCMFFile, NULL, PAGE_READWRITE, NULL, m_dwFileSize, NULL);
  300. if (hFileMapping == NULL)
  301. {
  302. CError ce;
  303. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile"),_T("Failure of CreateFileMapping()"));
  304. _tprintf(_T("GetLastError : %d\n"), GetLastError());
  305. return FALSE;
  306. }
  307. PVOID pCMFImageBase = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, NULL, NULL, NULL);
  308. if (pCMFImageBase == NULL)
  309. {
  310. CError ce;
  311. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile"),_T("Failure of MapViewOfFile()"));
  312. _tprintf(_T("GetLastError : %d\n"), GetLastError());
  313. return FALSE;
  314. }
  315. DWORD dwTempImageBase = (DWORD)PtrToUlong(pCMFImageBase);
  316. CloseHandle(hFileMapping);
  317. //
  318. // write offset to each MUI header.
  319. //
  320. DWORD dwUpCMFHeaderSize = m_upCMFHeader.dwHeaderSize;
  321. DWORD_ALIGNMENT(dwUpCMFHeaderSize); // All MUI headers are already DWORD aligned.
  322. memcpy(pCMFImageBase, (PVOID)&m_upCMFHeader, sizeof(UP_COMPACT_MUI_RESOURCE));
  323. DWORD dwLowOffset = sizeof(UP_COMPACT_MUI_RESOURCE);
  324. for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i++)
  325. {
  326. CMUIFile *pcmui = (CMUIFile *)m_pcvector.GetValue(i);
  327. pcmui->m_MUIHeader.ulpOffset = dwUpCMFHeaderSize; // + header size. header size should be DWORD in Create()
  328. dwUpCMFHeaderSize += pcmui->m_MUIHeader.dwFileSize; // + File size is next file offset
  329. DWORD_ALIGNMENT(dwUpCMFHeaderSize); // need to adjust for DWORD.
  330. // writing MUI header
  331. memcpy((PBYTE)pCMFImageBase + dwLowOffset, (PVOID)&pcmui->m_MUIHeader, pcmui->m_MUIHeader.wHeaderSize);
  332. dwLowOffset += pcmui->m_MUIHeader.wHeaderSize; // do not DWORD align.
  333. // writing MUI image
  334. memcpy((PBYTE)pCMFImageBase + pcmui->m_MUIHeader.ulpOffset, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize);
  335. UnmapViewOfFile(pcmui->m_pbImageBase); // unmap MUI file at last.
  336. };
  337. if (! FlushViewOfFile(pCMFImageBase, NULL) )
  338. {
  339. CError ce;
  340. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of FlushViewOfFile()") );
  341. return FALSE;
  342. }
  343. UnmapViewOfFile(pCMFImageBase);
  344. #else
  345. //
  346. // Using WriteFile.
  347. // create two buffer. 1. header part 2. data part. we fill this buffer with data, then
  348. // write these buffer; we can save time by reducing I/O
  349. //
  350. PBYTE pCMFImageBase = (PBYTE)LocalAlloc(LMEM_ZEROINIT, m_dwFileSize);
  351. if (pCMFImageBase == NULL)
  352. {
  353. CError ce;
  354. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of LocalAlloc()") );
  355. return FALSE;
  356. }
  357. //
  358. // write offset to each MUI header.
  359. //
  360. DWORD dwUpCMFHeaderSize = m_upCMFHeader.dwHeaderSize;
  361. DWORD_ALIGNMENT(dwUpCMFHeaderSize); // All MUI headers are already DWORD aligned.
  362. memcpy(pCMFImageBase, (PVOID)&m_upCMFHeader, sizeof(UP_COMPACT_MUI_RESOURCE));
  363. DWORD dwLowOffset = sizeof(UP_COMPACT_MUI_RESOURCE);
  364. for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i++)
  365. {
  366. CMUIFile *pcmui = (CMUIFile *)m_pcvector.GetValue(i);
  367. pcmui->m_MUIHeader.ulpOffset = wUpCMFHeaderSize; // + header size. header size should be DWORD in Create()
  368. dwUpCMFHeaderSize += pcmui->m_MUIHeader.dwFileSize; // + File size is next file offset
  369. DWORD_ALIGNMENT(dwUpCMFHeaderSize); // need to adjust for DWORD.
  370. // writing MUI header
  371. memcpy((PBYTE)pCMFImageBase + dwLowOffset, (PVOID)&pcmui->m_MUIHeader, pcmui->m_MUIHeader.wHeaderSize);
  372. dwLowOffset += pcmui->m_MUIHeader.wHeaderSize; // do not DWORD align.
  373. // writing MUI image
  374. memcpy((PBYTE)pCMFImageBase + pcmui->m_MUIHeader.ulpOffset, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize);
  375. UnmapViewOfFile(pcmui->m_pbImageBase); // unmap MUI file at last.
  376. };
  377. DWORD dwWritten;
  378. if (!WriteFile(m_hCMFFile, pCMFImageBase, m_dwFileSize, &dwWritten, NULL))
  379. {
  380. CError ce;
  381. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of WriteFile()") );
  382. return FALSE;
  383. }
  384. #endif
  385. CloseHandle(m_hCMFFile);
  386. return TRUE;
  387. }
  388. #ifdef VARIALBE_MUI_STRUCTURE
  389. BOOL CCompactMUIFile::WriteCMFFile()
  390. /*++
  391. Abstract:
  392. Create mapped view of CMF file handle and write all information when MUI data structe is variable; MUI structure
  393. would be variable if we dicide replace array of MUI file name with null terminated pointer.
  394. currently, our structured can accomodate both of them. if we use null termated pointer, we can set file name size
  395. for robust reason from client use.
  396. Arguments:
  397. return:
  398. --*/
  399. {
  400. //
  401. // Write the file to real file.
  402. //
  403. HANDLE hFileMapping = CreateFileMapping(m_hCMFFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
  404. PVOID pCMFImageBase = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, NULL, NULL, NULL);
  405. CloseHandle(hFileMapping);
  406. //
  407. // write offset to each MUI header.
  408. //
  409. DWORD dwUpCMFHeaderSize = m_upCMFHeader.dwHeaderSize;
  410. // DWORD_ALIGNMENT(wUpCMFHeaderSize); All MUI headers are already DWORD aligned.
  411. memcpy(pCMFImageBase, (PVOID)&m_upCMFHeader, sizeof(UP_COMPACT_MUI_RESOURCE));
  412. DWORD dwLowOffset = sizeof(UP_COMPACT_MUI_RESOURCE);
  413. for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i++)
  414. {
  415. CMUIFile *pcmui = (CMUIFile *)m_pcvector->GetValue(i);
  416. pcmui->m_MUIHeader.ulpOffset = dwUpCMFHeaderSize; // + header size
  417. dwUpCMFHeaderSize += pcmui->m_MUIHeader.dwFileSize; // + File size is next file offset
  418. DWORD_ALIGNMENT(dwUpCMFHeaderSize); // need to adjust for DWORD.
  419. // writing MUI header
  420. memcpy((PBYTE)pCMFImageBase + dwLowOffset, (PVOID)&pcmui->m_MUIHeader, pcmui->m_MUIHeader.wHeaderSize);
  421. dwLowOffset += pcmui->m_MUIHeader.wHeaderSize; // do not DWORD align.
  422. // writing MUI image
  423. memcpy((PBYTE)pCMFImageBase + pcmui->m_MUIHeader.ulpOffset, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize);
  424. };
  425. if (! FlushViewOfFile(pCMFImageBase, NULL) )
  426. {
  427. CError ce;
  428. ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of FlushViewOfFile()") );
  429. return FALSE;
  430. }
  431. UnmapViewOfFile(pCMFImageBase);
  432. }
  433. #endif
  434. BOOL CCompactMUIFile::UpdateMuiFile( PSTR pszCMFFile, PSTR pszMuiFile)
  435. {
  436. // TBD
  437. if ( pszCMFFile == NULL || pszMuiFile == NULL)
  438. return FALSE;
  439. return TRUE;
  440. }
  441. //create CMUIFile and replace this data with same name inside //CMF file and fill new CMF file structure.
  442. BOOL CCompactMUIFile::DisplayHeaders(PSTR pszCMFFile, WORD wLevel /*= NULL*/)
  443. /*++
  444. Abstract:
  445. Dump CMF header information
  446. Arguments:
  447. pszCMFFile - CMF file
  448. wLevel - dump level. not implemented yet.
  449. return:
  450. true/false
  451. --*/
  452. {
  453. if (pszCMFFile == NULL)
  454. return FALSE;
  455. if (OpenCMFWithMUI(pszCMFFile))
  456. {
  457. _tprintf(_T("\nCMF Headers %s\n"), pszCMFFile );
  458. _tprintf(_T("------------------ ---------------- \n\n") );
  459. _tprintf(_T("dwSignature :%16x \n"),m_upCMFHeader.dwSignature );
  460. _tprintf(_T("dwHeaderSize :%16x \n"),m_upCMFHeader.dwHeaderSize );
  461. _tprintf(_T("dwNumberofMui :%16x \n"),m_upCMFHeader.dwNumberofMui );
  462. _tprintf(_T("dwFileSize :%16x \n\n\n"),m_upCMFHeader.dwFileSize );
  463. for ( UINT i = 0; i < m_pcvector.Size(); i++)
  464. {
  465. CMUIFile *pcmui = m_pcvector.GetValue(i);
  466. _tprintf(_T(" %d MUI Header \n"),i+1 );
  467. _tprintf(_T("------------------ ---------------- \n\n") );
  468. _tprintf(_T("wHeaderSize : %16x \n"),pcmui->m_MUIHeader.wHeaderSize );
  469. _tprintf(_T("dwFileVersionMS : %16x \n"),pcmui->m_MUIHeader.dwFileVersionMS );
  470. _tprintf(_T("dwFileVersionLS : %16x \n"),pcmui->m_MUIHeader.dwFileVersionLS );
  471. _tprintf(_T("Checksum : "));
  472. for (UINT j=0; j < 16; j++){
  473. _tprintf(_T("%x "),pcmui->m_MUIHeader.Checksum[j] );
  474. }
  475. _tprintf(_T("\n"));
  476. _tprintf(_T("wReserved : %16x \n"),pcmui->m_MUIHeader.wReserved );
  477. _tprintf(_T("ulpOffset : %16x \n"),pcmui->m_MUIHeader.ulpOffset );
  478. _tprintf(_T("dwFileSize : %16x \n"),pcmui->m_MUIHeader.dwFileSize );
  479. _tprintf(_T("wFileNameLenWPad : %16x \n"),pcmui->m_MUIHeader.wFileNameLenWPad );
  480. _tprintf(_T("wstrFieName : %16S \n\n\n"),pcmui->m_MUIHeader.wstrFieName );
  481. }
  482. }
  483. return TRUE;
  484. }
  485. BOOL CCompactMUIFile::AddFile (PSTR pszCMFFile, PSTR *pszAddedMuiFile, DWORD dwNumOfMUIFiles)
  486. /*++
  487. Abstract:
  488. Add a new mui file into existing cmf file, it does not create new file yet,
  489. it just add mui into cmf's mui tree.
  490. Arguments:
  491. pszAddedMuiFile : MUI fil be added.
  492. pszCMFFile : existing CMF file
  493. return:
  494. true/false
  495. --*/
  496. {
  497. if ( pszCMFFile == NULL || pszAddedMuiFile == NULL)
  498. return FALSE;
  499. //
  500. // Open CMF file with MUI files
  501. //
  502. if (! OpenCMFWithMUI(pszCMFFile))
  503. {
  504. CError ce;
  505. ce.ErrorPrint(_T("CCompactMUIFile::AddFile"),_T("Failure of OpenCMFWithMUI(pszCMFFile)"),pszCMFFile );
  506. return FALSE;
  507. }
  508. //
  509. // Create a new CMUIfile on the based on new added mui file
  510. //
  511. for (UINT i =0; i < dwNumOfMUIFiles; i++)
  512. {
  513. CMUIFile *pcmui = new CMUIFile();
  514. if (!pcmui )
  515. return FALSE;
  516. if (! pcmui->Create(pszAddedMuiFile[i]))
  517. {
  518. CError ce;
  519. ce.ErrorPrint(_T("CCompactMUIFile::AddFile"),_T("Failure of CMUIFile::Create"),pszAddedMuiFile[i] );
  520. delete pcmui;
  521. return FALSE;
  522. }
  523. //
  524. // Add to the list.
  525. //
  526. m_upCMFHeader.dwHeaderSize += pcmui->m_MUIHeader.wHeaderSize;
  527. m_upCMFHeader.dwNumberofMui++;
  528. m_dwFileSize += pcmui->m_MUIHeader.wHeaderSize + pcmui->m_MUIHeader.dwFileSize;
  529. // Add dwFileSize to the strucuture for sanity check inside Loader.
  530. m_upCMFHeader.dwFileSize = m_dwFileSize;
  531. pcmui->m_dwIndex = m_upCMFHeader.dwNumberofMui - 1;
  532. m_pcvector.Push_back(pcmui);
  533. }
  534. return TRUE;
  535. }
  536. BOOL CCompactMUIFile::SubtractFile ( PSTR pszSubtractedMuiFile , PSTR pszCMFFile /*= NULL*/ )//elete from the list,and create file for that.
  537. /*++
  538. Abstract:
  539. subtract mui file from the CMF file. NOT implemented yet.
  540. Arguments:
  541. pszSubtractedMuiFile - MUI file, which would be removed from CMF file
  542. pszCMFFile - CMF file
  543. return:
  544. true/false
  545. --*/
  546. {
  547. if (pszSubtractedMuiFile == NULL)
  548. return FALSE;
  549. return TRUE;
  550. }
  551. // add new CMUI file into existing CMF file
  552. BOOL CCompactMUIFile::UnCompactCMF (PSTR pszCMFFile)
  553. /*++
  554. Abstract:
  555. Create each MUI file from CMF file.
  556. Arguments:
  557. pszCMFFile - CMF file
  558. return:
  559. true/false
  560. --*/
  561. {
  562. if (pszCMFFile == NULL)
  563. return FALSE;
  564. if (OpenCMFWithMUI(pszCMFFile))
  565. {
  566. for (UINT i = 0; i < m_pcvector.Size(); i++)
  567. {
  568. CMUIFile *pcmui = m_pcvector.GetValue(i);
  569. if (! pcmui->WriteMUIFile(pcmui))
  570. {
  571. CError ce;
  572. ce.ErrorPrint(_T("CCompactMUIFile::UnCompactCMF"), _T("Failure of CMUIFile::writeMUIFile()") );
  573. return FALSE;
  574. }
  575. }
  576. return TRUE;
  577. // REVIST ; how about uddating a binary files.
  578. }
  579. return FALSE;
  580. }
  581. void CCompactMUIFile::SubtractFile(CMUIFile* pcmui)
  582. /*++
  583. Abstract:
  584. Arguments:
  585. return:
  586. --*/
  587. {
  588. // TBD
  589. }
  590. BOOL CCompactMUIFile::UpdateCodeFiles(PSTR pszCodeFilePath, DWORD dwNumbOfFiles)
  591. /*++
  592. Abstract:
  593. This rotine will be called when -m(create new cmf file) and -a(add mui file into
  594. existing cmf file). in the -a case, we don't have to (shouldn't) update code files
  595. because it alreay updated(include CMF name). The updated files are added at the end
  596. cmf files so we update files reversly.
  597. Arguments:
  598. pszCodeFilePath - DLL (parent of MUI file) path
  599. dwNumbOfFiles - number of added MUI files. this is called as a function of CompactMUI in main function.
  600. return:
  601. true/false
  602. --*/
  603. {
  604. PTSTR * ppszDestEnd = NULL;
  605. size_t * pbRem = NULL;
  606. HRESULT hr;
  607. if (pszCodeFilePath == NULL)
  608. return FALSE;
  609. // Update files from the last item until number of files end.
  610. UINT i =m_pcvector.Size()-1;
  611. for (UINT j = 0 ; j < dwNumbOfFiles ; i --, j++ )
  612. { // create temp codefilepath.
  613. CHAR szTempCodeFilePath[MAX_PATH]; // = {0};
  614. // szTempCodeFilePath[sizeof(szTempCodeFilePath)-1] = '\0';
  615. // strncpy(szTempCodeFilePath, pszCodeFilePath, strlen(pszCodeFilePath)+1);
  616. hr = StringCchCopyExA(szTempCodeFilePath, MAX_PATH ,pszCodeFilePath, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  617. if ( ! SUCCEEDED(hr)){
  618. _tprintf("Safe string copy Error\n");
  619. return FALSE;
  620. }
  621. // Get CMUIFile
  622. CMUIFile *pcmui = m_pcvector.GetValue(i);
  623. LPCTSTR pcstrMuiFile = pcmui->m_strFileName;
  624. if ( pcstrMuiFile == NULL)
  625. return FALSE;
  626. // Get the file name without ".mui"
  627. DWORD dwLen = strlen(pcstrMuiFile);
  628. TCHAR szCodeFileName[MAX_PATH]={0}; // new is used when initializing class.
  629. if (dwLen > MAX_PATH) {
  630. return FALSE;
  631. }
  632. while ( dwLen )
  633. {
  634. if ( *(pcstrMuiFile + ( --dwLen )) == '.')
  635. {
  636. _tcsncpy(szCodeFileName, pcstrMuiFile, dwLen);
  637. // pcstrMuiFile[dwLen] = _T('\0');
  638. // StringCchCopyEx(szCodeFileName, MAX_PATH ,pcstrMuiFile, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  639. // memcpy(szCodeFileName, pcstrMuiFile, dwLen);
  640. break;
  641. }
  642. }
  643. if (dwLen == 0)
  644. {
  645. CError ce;
  646. ce.ErrorPrint(_T("CCompactMUIFile::UpdateCodeFiles"), _T("MUI File name is not a file name format (*.*)") );
  647. return FALSE;
  648. }
  649. //
  650. // Check if target file exist in the directory.
  651. //
  652. WIN32_FIND_DATA w32fd;
  653. //_tcsncat(szTempCodeFilePath, "\\", 2);
  654. hr = StringCchCatEx(szTempCodeFilePath, MAX_PATH, _T("\\"), ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  655. if ( ! SUCCEEDED(hr)){
  656. _tprintf("Safe string copy Error\n");
  657. return FALSE;
  658. }
  659. // _tcsncat(szTempCodeFilePath, szCodeFileName, _tcslen(szCodeFileName)+1);
  660. hr = StringCchCatEx(szTempCodeFilePath, MAX_PATH, szCodeFileName, ppszDestEnd, pbRem,MUIRCT_STRSAFE_NULL);
  661. if ( ! SUCCEEDED(hr)){
  662. _tprintf("Safe string copy Error\n");
  663. return FALSE;
  664. }
  665. //if (FindFirstFile("dll\\np2.exe", &w32fd) == INVALID_HANDLE_VALUE)
  666. if (FindFirstFile(szTempCodeFilePath, &w32fd) == INVALID_HANDLE_VALUE)
  667. {
  668. CError ce;
  669. ce.ErrorPrint(_T("CCompactMUIFile::UpdateCodeFiles"), _T("FindFirstFile fail"), szCodeFileName );
  670. return FALSE;
  671. }
  672. // Adding "CMF xxx.cmf" inside Version info.
  673. updateCodeFile(szTempCodeFilePath, pcmui->m_dwIndex);
  674. // update checksum data inside update Code.
  675. CMUIResource cmui; // :: UpdateNtHeader
  676. cmui.UpdateNtHeader(szTempCodeFilePath, cmui.CHECKSUM);
  677. }
  678. return TRUE;
  679. }
  680. BOOL CCompactMUIFile::updateCodeFile(PSTR pszCodeFilePath, DWORD dwIndex)
  681. /*++
  682. Abstract:
  683. update DLL (parent of MUI file)'s version resource by adding "CMF" section, which
  684. contain CMF file and its index inside CMF file. the index can improve searching speed inside MUI loader.
  685. Arguments:
  686. pszCodeFilePath - DLL file path
  687. dwIndex - index of MUI inside CMF file
  688. return:
  689. --*/
  690. {
  691. typedef struct VS_VERSIONINFO
  692. {
  693. USHORT TotalSize;
  694. USHORT DataSize;
  695. USHORT Type;
  696. WCHAR szKey[16]; // L"VS_VERSION_INFO" + unicode null terminator
  697. // Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
  698. // So that compiler will silently add a 2 bytes padding to make
  699. // FixedFileInfo to align in DWORD boundary.
  700. VS_FIXEDFILEINFO FixedFileInfo;
  701. } VS_VERSIONINFO,* PVS_VERSIONINFO;
  702. // using the same structure in ldrrsrc.c because this is smart way to get the exact structuree location.
  703. typedef struct tagVERBLOCK
  704. {
  705. USHORT wTotalLen;
  706. USHORT wValueLen;
  707. USHORT wType;
  708. WCHAR szKey[1];
  709. // BYTE[] padding
  710. // WORD value;
  711. } VERBLOCK;
  712. // this is the structure in the muibld.exe.
  713. typedef struct VAR_SRC_COMPACT
  714. {
  715. WORD wLength;
  716. WORD wValueLength;
  717. WORD wType;
  718. WCHAR szCompactMui[4]; // For storing "CompactMui\0" null-terminated string in Unicode.
  719. // DWORD dwIndex; //
  720. // WCHAR szCompactFileName[32];
  721. } VAR_SRC_COMPACT; //VAR_SRC_CHECKSUM;
  722. if ( pszCodeFilePath == NULL)
  723. return FALSE;
  724. //
  725. // Get VersionInfo structure.
  726. //
  727. DWORD dwHandle;
  728. LPVOID lpVerRes = NULL;
  729. CMUIResource * pcmuir = NULL;
  730. DWORD dwVerSize = GetFileVersionInfoSize( (LPTSTR) pszCodeFilePath, &dwHandle);
  731. lpVerRes = new CHAR[dwVerSize + TEMP_BUFFER];
  732. if (!lpVerRes)
  733. goto exit;
  734. if ( ! GetFileVersionInfo((LPTSTR)pszCodeFilePath, 0 ,dwVerSize, lpVerRes) ) {
  735. _tprintf(_T("Fail to get file version: GetLastError() : %d \n"),GetLastError() ) ;
  736. goto exit;
  737. }
  738. PVS_VERSIONINFO pVersionInfo = (VS_VERSIONINFO *) lpVerRes;
  739. WORD wResVerSize = pVersionInfo ->TotalSize;
  740. WORD wNewResVerSize = wResVerSize; // + sizeof (VAR_SRC_COMPACT);
  741. VERBLOCK * pVerBlock = NULL;
  742. BOOL fSuccess = FALSE;
  743. //
  744. // Adding checksum Resource data into inside VarFileInfo
  745. //
  746. if ( wResVerSize > 0 ) {
  747. if ( wcscmp(pVersionInfo ->szKey,L"VS_VERSION_INFO") ) {
  748. _tprintf(_T("This is not correct Version resource") );
  749. goto exit;
  750. }
  751. WORD wBlockSize = (WORD)DWORD_ALIGNMENT ( sizeof (VS_VERSIONINFO) );
  752. wResVerSize -= wBlockSize;
  753. pVerBlock = (VERBLOCK *) ( pVersionInfo + 1 );
  754. while ( wResVerSize > 0 ) {
  755. if ( ! wcscmp(pVerBlock ->szKey,L"VarFileInfo") ) {
  756. VERBLOCK * pVarVerBlock = pVerBlock;
  757. WORD wVarFileSize = pVerBlock->wTotalLen;
  758. wResVerSize -= wVarFileSize;
  759. WORD wVarBlockSize = (WORD) DWORD_ALIGNMENT (sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
  760. wVarFileSize -= wVarBlockSize;
  761. pVerBlock = (VERBLOCK *)((PBYTE) pVerBlock + wVarBlockSize );
  762. while ((LONG)wVarFileSize > 0 ) {
  763. if ( ! wcscmp(pVerBlock ->szKey,L"Translation") ) {
  764. VAR_SRC_COMPACT * pVarSrcCompMui = (VAR_SRC_COMPACT *)new BYTE[TEMP_BUFFER];
  765. // VAR_SRC_COMPACT * pVarSrcCompMui = new VAR_SRC_COMPACT;
  766. if ( !pVarSrcCompMui) {
  767. _tprintf(_T("Memory Insufficient error in CCompactMUIFile::updateCodeFile"));
  768. goto exit;
  769. }
  770. wVarBlockSize = (WORD)DWORD_ALIGNMENT ( pVerBlock ->wTotalLen );
  771. PBYTE pStartCompMui = (PBYTE) pVerBlock + wVarBlockSize ;
  772. // Fill the structure.
  773. pVarSrcCompMui->wLength = sizeof (VAR_SRC_COMPACT);
  774. pVarSrcCompMui->wValueLength = (strlen(m_strFileName)+1) * sizeof WCHAR + sizeof DWORD;
  775. pVarSrcCompMui->wType = 0;
  776. // wcsncpy(pVarSrcCompMui->szCompactMui, MUI_COMPACT, 4 );
  777. HRESULT hr;
  778. hr = StringCchCopyW(pVarSrcCompMui->szCompactMui, sizeof (pVarSrcCompMui->szCompactMui)/ sizeof(WCHAR),
  779. L"CMF");
  780. if ( ! SUCCEEDED(hr)){
  781. _tprintf("Safe string copy Error\n");
  782. delete [] pVarSrcCompMui;
  783. goto exit;
  784. }
  785. pVarSrcCompMui->wLength = (WORD)DWORD_ALIGNMENT((BYTE)pVarSrcCompMui->wLength); // + sizeof (L"CompactMui"));
  786. // Add DWORD wIndex
  787. memcpy((PBYTE)pVarSrcCompMui + pVarSrcCompMui->wLength, &dwIndex, sizeof DWORD );
  788. pVarSrcCompMui->wLength += sizeof DWORD;
  789. // Add WCHAR Compact file name
  790. WCHAR wstrFileName[MAX_FILENAME_LENGTH];
  791. if (MultiByteToWideChar(CP_ACP, NULL, m_strFileName,
  792. strlen(m_strFileName)+1, wstrFileName, MAX_FILENAME_LENGTH ) == 0)
  793. {
  794. _tprintf("Error happen in updateCodeFile: MultiByteToWideChar; GetLastError() : %d\n", GetLastError() );
  795. delete [] pVarSrcCompMui;
  796. goto exit;
  797. }
  798. memcpy((PBYTE)pVarSrcCompMui + pVarSrcCompMui->wLength, wstrFileName, (wcslen(wstrFileName)+1) * sizeof WCHAR );
  799. pVarSrcCompMui->wLength += (wcslen(wstrFileName) + 1) * sizeof WCHAR;
  800. pVarSrcCompMui->wLength = DWORD_ALIGNMENT(pVarSrcCompMui->wLength);
  801. // memcpy(pStartCompMui,pVarSrcCompMui,sizeof(VAR_SRC_COMPACT) );
  802. pVarVerBlock->wTotalLen += pVarSrcCompMui->wLength; // update length of VarFileInfo
  803. wNewResVerSize += pVarSrcCompMui->wLength;
  804. pVersionInfo ->TotalSize = wNewResVerSize;
  805. wVarFileSize -= wVarBlockSize;
  806. // pVerBlock = (VERBLOCK* ) ( (PBYTE) pVerBlock + pVarSrcCompMui->wLength );
  807. // Push the any block in VarInfo after new inserted block "CompactMui"
  808. if ( wVarFileSize ) {
  809. PBYTE pPushedBlock = new BYTE[wVarFileSize ];
  810. if (pPushedBlock) {
  811. memcpy(pPushedBlock, pStartCompMui, wVarFileSize );
  812. memcpy(pStartCompMui + pVarSrcCompMui->wLength, pPushedBlock ,wVarFileSize );
  813. }
  814. else
  815. {
  816. _tprintf(_T("Memory Insufficient error in CCompactMUIFile::updateCodeFile"));
  817. }
  818. delete [] pPushedBlock;
  819. }
  820. memcpy(pStartCompMui, pVarSrcCompMui, pVarSrcCompMui->wLength );
  821. fSuccess = TRUE;
  822. delete [] pVarSrcCompMui;
  823. break;
  824. }
  825. wVarBlockSize = (WORD)DWORD_ALIGNMENT ( pVerBlock ->wTotalLen );
  826. wVarFileSize -= wVarBlockSize;
  827. pVerBlock = (VERBLOCK* ) ( (PBYTE) pVerBlock + wVarBlockSize );
  828. } // while (wVarFileSize > 0 ) {
  829. pVerBlock = (VERBLOCK* ) ( (PBYTE) pVarVerBlock->wTotalLen );
  830. }
  831. else {
  832. wBlockSize = (WORD) DWORD_ALIGNMENT ( pVerBlock ->wTotalLen );
  833. wResVerSize -= wBlockSize;
  834. pVerBlock = (VERBLOCK * ) ( (PBYTE) pVerBlock + wBlockSize );
  835. }
  836. if (fSuccess)
  837. break;
  838. }
  839. }
  840. //
  841. // Update file by using UpdateResource function
  842. //
  843. BOOL fVersionExist = FALSE;
  844. BOOL fUpdateSuccess = FALSE;
  845. BOOL fEndUpdate = FALSE;
  846. if ( fSuccess ) {
  847. pcmuir = new CMUIResource(); //(pszNewFile);
  848. if(!pcmuir)
  849. goto exit;
  850. if (! pcmuir -> Create(pszCodeFilePath) )
  851. { // load the file .
  852. goto exit;
  853. }
  854. HANDLE hUpdate = ::BeginUpdateResource(pszCodeFilePath, FALSE );
  855. if (hUpdate == NULL)
  856. {
  857. goto exit;
  858. }
  859. cvcstring * cvName = pcmuir->EnumResNames(MAKEINTRESOURCE(RT_VERSION),reinterpret_cast <LONG_PTR> (pcmuir) );
  860. for (UINT j = 0; j < cvName->Size();j ++ ) {
  861. cvword * cvLang = pcmuir->EnumResLangID(MAKEINTRESOURCE(RT_VERSION), cvName->GetValue(j), reinterpret_cast <LONG_PTR> (pcmuir) );
  862. for (UINT k = 0; k < cvLang->Size();k ++ ) {
  863. fUpdateSuccess = ::UpdateResource(hUpdate, MAKEINTRESOURCE(RT_VERSION),cvName->GetValue(j),cvLang->GetValue(k),lpVerRes,wNewResVerSize);
  864. fVersionExist = TRUE;
  865. }
  866. }
  867. pcmuir->FreeLibrary();
  868. fEndUpdate = ::EndUpdateResource(hUpdate, FALSE);
  869. CloseHandle(hUpdate);
  870. }
  871. else
  872. {
  873. goto exit;
  874. }
  875. if( ! fVersionExist ){
  876. _tprintf(_T("no RT_VERSION type exist in the file %s \n"), pszCodeFilePath);
  877. }
  878. exit:
  879. if(lpVerRes)
  880. delete []lpVerRes;
  881. if(pcmuir)
  882. delete pcmuir;
  883. return ( fEndUpdate & fVersionExist & fUpdateSuccess );
  884. }
  885. ////////////////////////////////////////////////////////////////////////////////////////////////
  886. //
  887. // CMUIFile implementation
  888. //
  889. ///////////////////////////////////////////////////////////////////////////////////////////////
  890. CMUIFile::CMUIFile()
  891. {
  892. m_MUIHeader.wHeaderSize = sizeof COMPACT_MUI;
  893. m_MUIHeader.dwFileVersionMS = 0;
  894. m_MUIHeader.dwFileVersionLS = 0;
  895. m_MUIHeader.Checksum[16] = 0; //new BYTE[16];
  896. m_MUIHeader.wReserved = 0;
  897. m_MUIHeader.ulpOffset = 0;
  898. m_MUIHeader.dwFileSize = 0;
  899. m_MUIHeader.wFileNameLenWPad =0;
  900. m_MUIHeader.wstrFieName[MAX_FILENAME_LENGTH] = '\0';
  901. m_pbImageBase = NULL;
  902. m_dwIndex = 0xFFFF; // index start from 0.
  903. m_strFileName = new TCHAR[MAX_FILENAME_LENGTH];
  904. }
  905. CMUIFile::CMUIFile(CMUIFile & cmf)
  906. {
  907. //REVISIT : initialize copy constructor
  908. }
  909. CMUIFile::~CMUIFile()
  910. {
  911. if (m_pbImageBase)
  912. {
  913. delete m_pbImageBase;
  914. }
  915. if (m_strFileName)
  916. {
  917. delete []m_strFileName;
  918. }
  919. }
  920. CMUIFile & CMUIFile::operator=(CMUIFile &cmf)
  921. {
  922. if (&cmf == this)
  923. return *this;
  924. m_MUIHeader.wHeaderSize = cmf.m_MUIHeader.wHeaderSize;
  925. m_MUIHeader.dwFileVersionMS = cmf.m_MUIHeader.dwFileVersionMS;
  926. m_MUIHeader.dwFileVersionLS = cmf.m_MUIHeader.dwFileVersionLS;
  927. m_MUIHeader.Checksum[16] = cmf.m_MUIHeader.Checksum[16];
  928. m_MUIHeader.wReserved = cmf.m_MUIHeader.wReserved;
  929. m_MUIHeader.ulpOffset = cmf.m_MUIHeader.ulpOffset;
  930. m_MUIHeader.dwFileSize = cmf.m_MUIHeader.dwFileSize;
  931. m_MUIHeader.wFileNameLenWPad = cmf.m_MUIHeader.wFileNameLenWPad;
  932. m_MUIHeader.wstrFieName[MAX_FILENAME_LENGTH] = cmf.m_MUIHeader.wstrFieName[MAX_FILENAME_LENGTH];
  933. return *this;
  934. }
  935. BOOL CMUIFile::Create (PSTR pszMuiFile)
  936. /*++
  937. Abstract:
  938. load file and fill the structure block.
  939. Arguments:
  940. pszMuiFile -
  941. Return:
  942. --*/
  943. //
  944. {
  945. HANDLE hFile = NULL;
  946. HANDLE hMappedFile = NULL;
  947. BOOL fStatus = TRUE;
  948. if (pszMuiFile == NULL){
  949. fStatus = FALSE;
  950. goto Exit;
  951. }
  952. LPCTSTR pszFileName = GetFileNameFromPath(pszMuiFile);
  953. if (strlen (pszMuiFile)+1 > MAX_FILENAME_LENGTH ){
  954. fStatus = FALSE;
  955. goto Exit;; //overflow
  956. }
  957. // strncpy(m_strFileName, pszFileName, strlen (pszFileName)+1 );
  958. PTSTR * ppszDestEnd = NULL;
  959. size_t * pbRem = NULL;
  960. HRESULT hr;
  961. hr = StringCchCopyEx(m_strFileName, MAX_FILENAME_LENGTH, pszFileName, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  962. if ( ! SUCCEEDED(hr)){
  963. _tprintf("Safe string copy Error\n");
  964. fStatus = FALSE;
  965. goto Exit;;
  966. }
  967. //
  968. // Get checksum and file version info.
  969. //
  970. // PBYTE pMD5Checksum = new BYTE[16];
  971. PBYTE pMD5Checksum = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 20);
  972. // version
  973. DWORD dwFileVersionMS,dwFileVersionLS;
  974. dwFileVersionMS = dwFileVersionLS =0;
  975. if (pMD5Checksum)
  976. {
  977. if(! getChecksumAndVersion(pszMuiFile,&pMD5Checksum, &dwFileVersionMS, &dwFileVersionLS) )
  978. {
  979. //CError ce;
  980. //ce.ErrorPrint(_T("CCompactMUIFile::Create"),_T("Failure of GetChecksum()") );
  981. }
  982. else
  983. {
  984. memcpy(m_MUIHeader.Checksum, pMD5Checksum, RESOURCE_CHECKSUM_SIZE);
  985. }
  986. LocalFree(pMD5Checksum);
  987. }
  988. //
  989. // Load a file and map
  990. //
  991. hFile = CreateFile(pszMuiFile, GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
  992. if ( INVALID_HANDLE_VALUE == hFile)
  993. {
  994. CError ce;
  995. ce.ErrorPrint(_T("CMUIFile::Create (PSTR pszMuiFile)"),_T("Failure of CreateFile()"), pszMuiFile );
  996. printf("GetLastError %d", GetLastError());
  997. fStatus = FALSE;
  998. return FALSE;
  999. }
  1000. hMappedFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
  1001. if(hMappedFile == NULL)
  1002. {
  1003. CError ce;
  1004. ce.ErrorPrint(_T("CMUIFile::Create (PSTR pszMuiFile)"),_T("Failure of CreateFileMapping()"), pszMuiFile );
  1005. printf("GetLastError %d", GetLastError());
  1006. fStatus = FALSE;
  1007. goto Exit;;
  1008. }
  1009. PBYTE pbImageBase = (PBYTE)MapViewOfFile(hMappedFile, FILE_MAP_WRITE, NULL, NULL, NULL);
  1010. if (pbImageBase == NULL)
  1011. {
  1012. CError ce;
  1013. ce.ErrorPrint(_T("CMUIFile::Create (PSTR pszMuiFile)"),_T("Failure of MapViewOfFile()"), pszMuiFile );
  1014. printf("GetLastError %d", GetLastError());
  1015. fStatus = FALSE;
  1016. goto Exit;
  1017. }
  1018. // Fill the CMUIFile member data
  1019. m_pbImageBase = pbImageBase;
  1020. //
  1021. // Fill the COMPACT_MUI data field.
  1022. //
  1023. m_MUIHeader.dwFileVersionMS = dwFileVersionMS;
  1024. m_MUIHeader.dwFileVersionLS = dwFileVersionLS;
  1025. //offset, reserver, filesize.
  1026. m_MUIHeader.ulpOffset = 0; // we can't set this now.
  1027. m_MUIHeader.wReserved = 0;
  1028. m_MUIHeader.dwFileSize = GetFileSize(hFile, NULL);
  1029. // File name, filelenwithpadding, mui header size
  1030. // LPWSTR pwstrBuffer = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, 256);
  1031. WCHAR wstrBuffer[MAX_FILENAME_LENGTH];
  1032. // REVISIT; only accept english file name.
  1033. // specify wcslen instead of tcslen becasuse of possible overrun.
  1034. if (MultiByteToWideChar(CP_ACP, NULL, m_strFileName,
  1035. strlen(m_strFileName)+1, wstrBuffer, MAX_FILENAME_LENGTH ) == 0)
  1036. {
  1037. _tprintf("Error happen in Create: MultiByteToWideChar; GetLastError() : %d\n", GetLastError() );
  1038. fStatus = FALSE;
  1039. goto Exit;;
  1040. }
  1041. // wcsncpy(m_MUIHeader.wstrFieName, pwstrBuffer, wcslen(pwstrBuffer)+1); //strlen does not return '\0'
  1042. hr = StringCchCopyW(m_MUIHeader.wstrFieName, sizeof (m_MUIHeader.wstrFieName)/ sizeof(WCHAR),
  1043. wstrBuffer);
  1044. if ( ! SUCCEEDED(hr)){
  1045. _tprintf("Safe string copy Error\n");
  1046. fStatus = FALSE;
  1047. goto Exit;;
  1048. }
  1049. // This should be done in Constructor of CMUIFile
  1050. // pcmui->m_MUIHeader.wHeaderSize = sizeof UP_COMPACT_MUI;
  1051. WORD wTempHeaderSize = m_MUIHeader.wHeaderSize;
  1052. Exit:
  1053. if (hFile)
  1054. CloseHandle(hFile);
  1055. if (hMappedFile)
  1056. CloseHandle(hMappedFile);
  1057. return fStatus;
  1058. // add padding at end of file name as null character.
  1059. // file length include; file string + null character + padding (null character as well)
  1060. }
  1061. #ifdef VARIALBE_MUI_STRUCTURE
  1062. BOOL CMUIFile::Create (PSTR pszMuiFile) //
  1063. /*++
  1064. Abstract:
  1065. load file and fill the structure block for variable MUI structure.
  1066. Arguments:
  1067. Return:
  1068. --*/
  1069. {
  1070. if(pszMuiFile == NULL)
  1071. return FALSE;
  1072. //
  1073. // Get checksum and file version info.
  1074. //
  1075. PBYTE pMD5Checksum = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 16);
  1076. if (pMD5Checksum)
  1077. {
  1078. DWORD FileVersionLS,FileVersionMS;
  1079. if(!getChecksumAndVersion(pszMUIFile,&pMD5Checksum) )
  1080. {
  1081. CError ce;
  1082. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of GetChecksum()") );
  1083. LocalFree(pMD5Checksum);
  1084. return FALSE;
  1085. }
  1086. else
  1087. {
  1088. memcpy(m_MUIHeader.Checksum, pMD5Checksum, RESOURCE_CHECKSUM_SIZE);
  1089. }
  1090. LocalFree(pMD5Checksum);
  1091. }
  1092. //
  1093. // Load a file and map
  1094. //
  1095. HANDLE hFile = CreateFile(pszMUIFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
  1096. if ( INVALID_HANDLE_VALUE == hFile)
  1097. {
  1098. CError ce;
  1099. ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of CreateFile()"), _T("File : %s"), pszMUIFile );
  1100. return FALSE;
  1101. }
  1102. HANDLE hMappedFile = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, NULL, NULL, NULL);
  1103. PBYTE pbImageBase = NULL ; //(PBYTE)MapViewOfFile(hMappedFile, NULL, NULL, NULL, NULL);
  1104. // Fill the CMUIFile member data
  1105. m_pbImageBase = pbImageBase;
  1106. // pcmui->m_hMUIFile = hFile; // do we need file handle ?
  1107. // pcmui->m_wImageSize = GetFileSize(hFile);
  1108. //
  1109. // Fill the COMPACT_MUI data field.
  1110. //
  1111. m_MUIHeader.dwFileVersionMS = dwFileVersionMS;
  1112. m_MUIHeader.dwFileVersionLS = dwFileVersionLS;
  1113. //offset, reserver, filesize.
  1114. m_MUIHeader.ulpOffset = 0; // we can't set this now.
  1115. m_MUIHeader.wReserved = 0;
  1116. m_MUIHeader.dwFileSize = GetFileSize(hFile, NULL);
  1117. // File name, filelenwithpadding, mui header size
  1118. // LPWSTR pwstrBuffer = new WCHAR[MAX_FILENAME_LENGTH];
  1119. WCHAR wstrBuffer[MAX_FILENAME_LENGTH];
  1120. if ( MultiByteToWideChar(CP_ACP, NULL, pszMUIFile,
  1121. strlen(ppszMuiFiles[i]), wstrBuffer, MAX_FILENAME_LENGTH ) == 0)
  1122. {
  1123. _tprintf("Error happen in Create: MultiByteToWideChar; GetLastError() : %d\n", GetLastError() );
  1124. return FALSE;
  1125. }
  1126. //wcsncpy(m_MUIHeader.wstrFieName, pwstrBuffer, wcslen(pwstrBuffer)+1); //strlen does not return '\0'
  1127. HRESULT hr;
  1128. hr = StringCchCopyW(m_MUIHeader.wstrFieName, sizeof (m_MUIHeader.wstrFieName)/ sizeof(WCHAR),
  1129. pwstrBuffer);
  1130. if ( ! SUCCEEDED(hr)){
  1131. _tprintf("Safe string copy Error\n");
  1132. return FALSE;
  1133. }
  1134. // This should be done in Constructor of CMUIFile
  1135. // pcmui->m_MUIHeader.wHeaderSize = sizeof UP_COMPACT_MUI;
  1136. WORD wTempHeaderSize = m_MUIHeader.wHeaderSize;
  1137. BYTE bPadding = DWORD_ALIGNMENT(wTempHeaderSize) - wTempHeaderSize;
  1138. // add padding at end of file name as null character.
  1139. memcpy(m_MUIHeader.wstrFieName + wcslen(m_MUIHeader.wstrFieName)
  1140. + sizeof (WCHAR)/2 , "\0", bPadding);
  1141. // file length include; file string + null character + padding (null character as well)
  1142. m_MUIHeader.wFileNameLenWPad = wcslen(m_MUIHeader.wstrFieName) + (sizeof WCHAR)/2 + bPadding/2;
  1143. m_MUIHeader.wHeaderSize += m_MUIHeader.wFileNameLenWPad; // we have to adjust file name buffer.
  1144. CloseHandle(hFile);
  1145. CloseHandle(hMappedFile);
  1146. }
  1147. #endif
  1148. BOOL CMUIFile::getChecksumAndVersion (LPCTSTR pszMUIFile, unsigned char **ppMD5Checksum, DWORD *dwFileVersionMS, DWORD *dwFileVersionLS )
  1149. /*++
  1150. Abstract:
  1151. getChecksumAndVersion - Get the cehckesum data/version from the MUI file, which will be saved in the CMF header
  1152. as MUI informatio; this can improve MUI loader burden to search checksum/version infomatio of MUI file
  1153. Arguments:
  1154. pszMUIFile - MUI file
  1155. [OUT] ppMD5Checksum - checksum data will be stored in this
  1156. [OUT] dwFileVersionMS - FileversionMS will be stored in this
  1157. [OUT] dwFileVersionLS - FileversionSS will be stored in this
  1158. Return:
  1159. true/false
  1160. --*/
  1161. {
  1162. typedef struct tagVS_FIXEDFILEINFO
  1163. {
  1164. LONG dwSignature; /* e.g. 0xfeef04bd */
  1165. LONG dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
  1166. LONG dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
  1167. LONG dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
  1168. LONG dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
  1169. LONG dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
  1170. LONG dwFileFlagsMask; /* = 0x3F for version "0.42" */
  1171. LONG dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
  1172. LONG dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
  1173. LONG dwFileType; /* e.g. VFT_DRIVER */
  1174. LONG dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
  1175. LONG dwFileDateMS; /* e.g. 0 */
  1176. LONG dwFileDateLS; /* e.g. 0 */
  1177. } VS_FIXEDFILEINFO;
  1178. typedef struct
  1179. {
  1180. USHORT TotalSize;
  1181. USHORT DataSize;
  1182. USHORT Type;
  1183. WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode null terminator
  1184. // Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
  1185. // So that compiler will silently add a 2 bytes padding to make
  1186. // FixedFileInfo to align in DWORD boundary.
  1187. VS_FIXEDFILEINFO FixedFileInfo;
  1188. } RESOURCE, *PRESOURCE; //*Resource;
  1189. typedef struct tagVERBLOCK
  1190. {
  1191. USHORT wTotalLen;
  1192. USHORT wValueLen;
  1193. USHORT wType;
  1194. WCHAR szKey[1];
  1195. // BYTE[] padding
  1196. // WORD value;
  1197. } VERBLOCK,*pVerBlock;
  1198. if (pszMUIFile == NULL || ppMD5Checksum == NULL || dwFileVersionMS == NULL
  1199. || dwFileVersionLS == NULL) {
  1200. return FALSE;
  1201. }
  1202. #ifdef NEVER
  1203. //
  1204. // Get VersionInfo structure.
  1205. //
  1206. DWORD dwHandle;
  1207. DWORD dwVerSize = GetFileVersionInfoSize( (LPTSTR)pszMUIFile, &dwHandle);
  1208. HLOCAL hLocal = LocalAlloc(LMEM_ZEROINIT, dwVerSize );
  1209. LPVOID lpVerRes = LocalLock(hLocal);
  1210. DWORD dwError = GetLastError();
  1211. if ( ! GetFileVersionInfo((LPTSTR)pszMUIFile, 0 ,dwVerSize, lpVerRes) ) {
  1212. _tprintf(_T("Fail to get file version: GetLastError() : %d \n"),GetLastError() ) ;
  1213. return TRUE;
  1214. }
  1215. if (lpVerRes)
  1216. {
  1217. PRESOURCE pResBase = (PRESOURCE) lpVerRes;
  1218. DWORD ResourceSize = dwVerSize;
  1219. if((ResourceSize < sizeof(RESOURCE))
  1220. || _wcsicmp(pResBase->Name,L"VS_VERSION_INFO") != 0)
  1221. {
  1222. CError ce;
  1223. ce.ErrorPrint(_T("CMUIFile::GetCheckSum"), _T("Invalid Version resource") );
  1224. return FALSE;
  1225. }
  1226. ResourceSize -= sizeof (RESOURCE);
  1227. // //
  1228. // Get the beginning address of the children of the version information.
  1229. //
  1230. VERBLOCK* pVerBlock = (VERBLOCK*)(pResBase + 1);
  1231. DWORD BlockLen = 0;
  1232. DWORD VarFileInfoSize = 0;
  1233. while (ResourceSize > 0)
  1234. {
  1235. if (wcscmp(pVerBlock->szKey, L"VarFileInfo") == 0)
  1236. {
  1237. //
  1238. // Find VarFileInfo block. Search the ResourceChecksum block.
  1239. //
  1240. VarFileInfoSize = pVerBlock->wTotalLen;
  1241. BlockLen =DWORD_ALIGNMENT(sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
  1242. VarFileInfoSize -= BlockLen;
  1243. pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
  1244. while (VarFileInfoSize > 0)
  1245. {
  1246. if (wcscmp(pVerBlock->szKey, L"ResourceChecksum") == 0)
  1247. {
  1248. memcpy(*ppMD5Checksum,(unsigned char*)DWORD_ALIGNMENT(PtrToLong(pVerBlock->szKey) + sizeof(L"ResourceChecksum"), 16);
  1249. return TRUE;
  1250. }
  1251. BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
  1252. pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
  1253. VarFileInfoSize -= BlockLen;
  1254. }
  1255. return FALSE;
  1256. }
  1257. BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
  1258. pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
  1259. ResourceSize -= BlockLen;
  1260. }
  1261. }
  1262. #endif
  1263. //#ifdef NEVER
  1264. HMODULE hModule = LoadLibraryEx(pszMUIFile, NULL, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES );
  1265. DWORD dwError = GetLastError();
  1266. if ( hModule )
  1267. {
  1268. HRSRC hrSrc = FindResource(hModule, MAKEINTRESOURCE(1), RT_VERSION);
  1269. if (hrSrc)
  1270. {
  1271. HGLOBAL hgRes = LoadResource(hModule, hrSrc);
  1272. if (hgRes)
  1273. {
  1274. PRESOURCE pResBase = (PRESOURCE)LockResource(hgRes);
  1275. if (pResBase)
  1276. {
  1277. DWORD ResourceSize = SizeofResource(hModule, hrSrc);
  1278. if((ResourceSize < sizeof(RESOURCE))
  1279. || _wcsicmp(pResBase->Name,L"VS_VERSION_INFO") != 0)
  1280. {
  1281. CError ce;
  1282. ce.ErrorPrint(_T("CMUIFile::GetCheckSum"), _T("Invalid Version resource") );
  1283. goto failure;
  1284. }
  1285. *dwFileVersionMS = pResBase->FixedFileInfo.dwFileVersionMS;
  1286. *dwFileVersionLS = pResBase->FixedFileInfo.dwFileVersionLS;
  1287. ResourceSize -= sizeof (RESOURCE);
  1288. // //
  1289. // Get the beginning address of the children of the version information.
  1290. //
  1291. VERBLOCK* pVerBlock = (VERBLOCK*)(pResBase + 1);
  1292. DWORD BlockLen = 0;
  1293. DWORD VarFileInfoSize = 0;
  1294. while (ResourceSize > 0)
  1295. {
  1296. if (wcscmp(pVerBlock->szKey, L"VarFileInfo") == 0)
  1297. {
  1298. //
  1299. // Find VarFileInfo block. Search the ResourceChecksum block.
  1300. //
  1301. VarFileInfoSize = pVerBlock->wTotalLen;
  1302. BlockLen =DWORD_ALIGNMENT(sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
  1303. VarFileInfoSize -= BlockLen;
  1304. pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
  1305. while (VarFileInfoSize > 0)
  1306. {
  1307. if (wcscmp(pVerBlock->szKey, L"ResourceChecksum") == 0)
  1308. {
  1309. PBYTE pbTempChecksum = (unsigned char*)DWORD_ALIGNMENT(PtrToLong(pVerBlock->szKey) + sizeof(L"ResourceChecksum"));
  1310. memcpy(*ppMD5Checksum, pbTempChecksum, 16);
  1311. goto success;
  1312. }
  1313. BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
  1314. pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
  1315. VarFileInfoSize -= BlockLen;
  1316. }
  1317. goto failure;
  1318. }
  1319. BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
  1320. pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
  1321. ResourceSize -= BlockLen;
  1322. } // if (pResBase)
  1323. } // if (hgRes)
  1324. } // if (Resource)
  1325. } // if (hrSrc)
  1326. } // if ( hModule )
  1327. //#endif
  1328. failure:
  1329. FreeLibrary(hModule);
  1330. return FALSE;
  1331. success:
  1332. FreeLibrary(hModule);
  1333. return TRUE;
  1334. };
  1335. BOOL CMUIFile::WriteMUIFile(CMUIFile *pcmui)
  1336. /*++
  1337. Abstract:
  1338. Create and write a new MUI file with a data in CMUIFile.
  1339. Arguments:
  1340. pcmui - CMUIFile class,which should be filled by data
  1341. Return:
  1342. --*/
  1343. {
  1344. if (pcmui == NULL)
  1345. return FALSE;
  1346. HANDLE hFile = CreateFile(pcmui->m_strFileName, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
  1347. if (INVALID_HANDLE_VALUE == hFile)
  1348. {
  1349. CError ce;
  1350. ce.ErrorPrint(_T("CCompactMUIFile::WriteMUIFile"),_T("Failure of CreateFile()"));
  1351. return FALSE;
  1352. }
  1353. DWORD dwWritten;
  1354. if ( WriteFile(hFile, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize, &dwWritten, NULL) )
  1355. {
  1356. CloseHandle(hFile);
  1357. return TRUE;
  1358. }
  1359. CloseHandle(hFile);
  1360. return FALSE;
  1361. };
  1362. LPCTSTR CMUIFile::GetFileNameFromPath(LPCTSTR pszFilePath)
  1363. {
  1364. if ( pszFilePath == NULL)
  1365. return FALSE;
  1366. //
  1367. // Get file name from the path
  1368. //
  1369. DWORD dwLen = _tcslen(pszFilePath);
  1370. // d:\test\test.exe.mui //
  1371. while(dwLen--)
  1372. {
  1373. if (pszFilePath[dwLen] == '\\')
  1374. {
  1375. return pszFilePath+dwLen+1;
  1376. }
  1377. }
  1378. return pszFilePath;
  1379. }
  1380. #ifdef NEVER
  1381. BOOL CMUIFile::getFileVersion(LPCTSTR pszMuiFile, DWORD *dwFileVersionMS, DWORD *dwFileVersionLS)
  1382. /*++
  1383. Abstract:
  1384. get file version.
  1385. Arguments:
  1386. Return:
  1387. --*/
  1388. {
  1389. if ( pszMuiFile == NULL || dwFileVersionMS == NULL || dwFileVersionLS == NULL)
  1390. return FALSE;
  1391. typedef struct tagVS_FIXEDFILEINFO
  1392. {
  1393. LONG dwSignature; /* e.g. 0xfeef04bd */
  1394. LONG dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
  1395. LONG dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
  1396. LONG dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
  1397. LONG dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
  1398. LONG dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
  1399. LONG dwFileFlagsMask; /* = 0x3F for version "0.42" */
  1400. LONG dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
  1401. LONG dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
  1402. LONG dwFileType; /* e.g. VFT_DRIVER */
  1403. LONG dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
  1404. LONG dwFileDateMS; /* e.g. 0 */
  1405. LONG dwFileDateLS; /* e.g. 0 */
  1406. } VS_FIXEDFILEINFO;
  1407. typedef struct
  1408. {
  1409. USHORT TotalSize;
  1410. USHORT DataSize;
  1411. USHORT Type;
  1412. WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode null terminator
  1413. // Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
  1414. // So that compiler will silently add a 2 bytes padding to make
  1415. // FixedFileInfo to align in DWORD boundary.
  1416. VS_FIXEDFILEINFO FixedFileInfo;
  1417. } RESOURCE, *PRESOURCE; //*Resource;
  1418. HMODULE hModule = LoadLibraryEx(pszMuiFile, NULL, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES );
  1419. if ( hModule )
  1420. {
  1421. HRSRC hrSrc = FindResource(hModule, MAKEINTRESOURCE(1), RT_VERSION);
  1422. if (hrSrc)
  1423. {
  1424. HGLOBAL hgRes = LoadResource(hModule, hrSrc);
  1425. if (hgRes)
  1426. {
  1427. PRESOURCE pResBase = (PRESOURCE)LockResource(hrSrc);
  1428. if (pResBase)
  1429. {
  1430. DWORD ResourceSize = SizeofResource(hModule, hrSrc);
  1431. if((ResourceSize < sizeof(RESOURCE))
  1432. || _wcsicmp(pResBase->Name,L"VS_VERSION_INFO") != 0)
  1433. {
  1434. CError ce;
  1435. ce.ErrorPrint(_T("CMUIFile::getFileVersion"), _T("Invalid Version resource") );
  1436. goto failure;
  1437. }
  1438. *dwFileVersionMS = pResBase->FixedFileInfo.dwFileVersionMS;
  1439. *dwFileVersionLS = pResBase->FixedFileInfo.dwFileVersionLS;
  1440. goto success;
  1441. } // if (Resource)
  1442. } // if (hgRes)
  1443. } //if (hrSrc)
  1444. }//if ( hModule )
  1445. success:
  1446. FreeLibrary(hModule);
  1447. return TRUE;
  1448. failure:
  1449. FreeLibrary(hModule);
  1450. return FALSE;
  1451. }
  1452. #endif
  1453. ////////////////////////////////////////////////////////////////////////////////////
  1454. //
  1455. // CError Class
  1456. //
  1457. ///////////////////////////////////////////////////////////////////////////////////
  1458. void CError::ErrorPrint(PSTR pszErrorModule, PSTR pszErrorLocation, PSTR pszFile /* = NULL */)
  1459. /*++
  1460. Abstract:
  1461. print error information.
  1462. Arguments:
  1463. pszErrorModule - The function name of error taking place
  1464. pszErrorLocation - The location in the function of error taking place
  1465. pszFile - problematic file, which is used only by file related error such as CreateFile
  1466. Return:
  1467. --*/
  1468. {
  1469. // REVISIT; create Log file.
  1470. if (pszErrorModule == NULL || pszErrorLocation == NULL)
  1471. return ;
  1472. _tprintf(_T(" %s, %s, %s \n"), pszFile ? pszFile : _T(" "), pszErrorModule, pszErrorLocation);
  1473. }