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.

2991 lines
86 KiB

  1. /*****************************************************************************
  2. Copyright (c) 2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. res.cpp
  5. Abstract:
  6. The implementation of CMuiResource, CMuiCmdInfo ..
  7. Revision History:
  8. 2001-10-01 sunggch created.
  9. Revision.
  10. 01/24/02 : create mui file with specified resource type regardless its language id.
  11. ex. muirct -l 0x418 -i 2 3 4 5 6 7 notepad.exe -> notepad.exe.mui include 2 3, 4, 5,
  12. 6, 7 (0x418) resource type although 3 4 5 are 0x409 in original file.
  13. *******************************************************************************/
  14. #include "muirct.h"
  15. #include "resource.h"
  16. #include <Winver.h>
  17. #include <Imagehlp.h>
  18. #include "res.h"
  19. #define LINK_COMMAND_LENGTH 512
  20. #define MAX_ENV_LENGTH 256
  21. #define VERSION_SECTION_BUFFER 300
  22. #define LANG_CHECKSUM_DEFAULT 0x409
  23. BOOL CALLBACK EnumResTypeProc(
  24. HMODULE hModule, // module handle
  25. LPCTSTR pszType, // resource type
  26. LONG_PTR lParam // application-defined parameter
  27. )
  28. /*++
  29. Abstract:
  30. Callback function for Resource Type from EnumResourceType
  31. Arguments:
  32. return:
  33. --*/
  34. {
  35. if (PtrToUlong(pszType) & 0xFFFF0000 ) {
  36. DWORD dwBufSize = _tcslen(pszType) + 1;
  37. LPTSTR pszStrType = new TCHAR[dwBufSize ]; // REVISIT : memory leak, where I have to delete.
  38. if (pszStrType) {
  39. // _tcsncpy(pszStrType, pszType, _tcslen(pszType) + 1);
  40. PTSTR * ppszDestEnd = NULL;
  41. size_t * pbRem = NULL;
  42. HRESULT hr;
  43. hr = StringCchCopyEx(pszStrType, dwBufSize ,pszType, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  44. if ( ! SUCCEEDED(hr)){
  45. _tprintf("Safe string copy Error\n");
  46. return FALSE;
  47. }
  48. ((CResource* )lParam) ->SetResType ( pszStrType );
  49. }
  50. else
  51. {
  52. _tprintf("Insufficient resource in EnumResTypeProc");
  53. return FALSE;
  54. }
  55. }
  56. else {
  57. ((CResource* )lParam) ->SetResType (pszType);
  58. }
  59. return TRUE;
  60. };
  61. BOOL CALLBACK EnumResNameProc(
  62. HMODULE hModule, // module handle
  63. LPCTSTR pszType, // resource type
  64. LPCTSTR pszName, // resource name
  65. LONG_PTR lParam // application-defined parameter
  66. )
  67. /*++
  68. Abstract:
  69. Callback function for Resource Type from EnumResourceName
  70. Arguments:
  71. return:
  72. --*/
  73. {
  74. if (PtrToUlong(pszName) & 0xFFFF0000 ) {
  75. DWORD dwBufSize = _tcslen(pszName) + 1;
  76. LPTSTR pszStrName = new TCHAR [ dwBufSize ];// _tcslen(pszName) + 1 ];
  77. if ( pszStrName ) {
  78. // _tcsncpy(pszStrName, pszName, _tcslen(pszName) + 1);
  79. PTSTR * ppszDestEnd = NULL;
  80. size_t * pbRem = NULL;
  81. HRESULT hr;
  82. hr = StringCchCopyEx(pszStrName, dwBufSize ,pszName, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  83. if ( ! SUCCEEDED(hr)){
  84. _tprintf("Safe string copy Error\n");
  85. return FALSE;
  86. }
  87. ((CResource* )lParam) ->SetResName ( pszStrName );
  88. }
  89. else {
  90. _tprintf("Insufficient resource in EnumResNameProc");
  91. return FALSE;
  92. }
  93. }
  94. else {
  95. ((CResource* )lParam) ->SetResName ( pszName );
  96. }
  97. return TRUE;
  98. }
  99. BOOL CALLBACK EnumResLangProc(
  100. HANDLE hModule, // module handle
  101. LPCTSTR pszType, // resource type
  102. LPCTSTR pszName, // resource name
  103. WORD wIDLanguage, // language identifier
  104. LONG_PTR lParam // application-defined parameter
  105. )
  106. /*++
  107. Callback function for Resource Type from EnumResourceLanguages
  108. --*/
  109. {
  110. ((CResource* )lParam) ->SetResLangID (wIDLanguage);
  111. return TRUE;
  112. }
  113. BOOL CALLBACK EnumChecksumResNameProc(
  114. HMODULE hModule, // module handle
  115. LPCTSTR pszType, // resource type
  116. LPCTSTR pszName, // resource name
  117. LONG_PTR lParam // application-defined parameter
  118. )
  119. /*++
  120. Abstract:
  121. Callback function for Resource name from EnumResourceName, this is only for checksum purpose.
  122. Checksum need to enumerate English file, which is calcuated separately from localiszed file.
  123. Arguments:
  124. return:
  125. --*/
  126. {
  127. CMUIResource * pcmui = (CMUIResource * ) lParam;
  128. HRSRC hRsrc = FindResourceEx (hModule, pszType, pszName, pcmui->m_wChecksumLangId );
  129. if (!hRsrc) {
  130. return TRUE; // Not English resource, skip.
  131. };
  132. HGLOBAL hgMap = LoadResource(hModule, hRsrc);
  133. if (!hgMap) {
  134. return FALSE; // This should never happen!
  135. }
  136. DWORD dwResSize = SizeofResource(hModule, hRsrc );
  137. unsigned char* lpv = (unsigned char*)LockResource(hgMap);
  138. // we leave the data as public for preventing frequent funtion call.
  139. MD5Update(pcmui->m_pMD5, lpv, dwResSize);
  140. return TRUE;
  141. }
  142. BOOL CALLBACK EnumChecksumResTypeProc(
  143. HMODULE hModule, // module handle
  144. LPCTSTR pszType, // resource type
  145. LONG_PTR lParam // application-defined parameter
  146. )
  147. /*++
  148. Abstract:
  149. Callback function for Resource Type from EnumResourceType
  150. Arguments:
  151. return:
  152. --*/
  153. {
  154. if ( pszType == RT_VERSION )
  155. {
  156. return TRUE;
  157. }
  158. else
  159. {
  160. ::EnumResourceNames(hModule, pszType, ( ENUMRESNAMEPROC )EnumChecksumResNameProc, lParam );
  161. }
  162. return TRUE;
  163. }
  164. // Constructor
  165. CResource :: CResource ( ) : m_hRes(0), m_pszFile(NULL),m_hResUpdate(0)
  166. {
  167. m_vwResType = new cvcstring;
  168. if(!m_vwResType)
  169. return;
  170. m_vwResName = new cvcstring;
  171. if(!m_vwResName)
  172. return;
  173. m_vwResLangID = new cvword;
  174. if(!m_vwResLangID)
  175. return;
  176. }
  177. CResource :: ~ CResource ( ) {
  178. if(m_vwResType)
  179. delete m_vwResType;
  180. if(m_vwResName)
  181. delete m_vwResName;
  182. if(m_vwResLangID)
  183. delete m_vwResLangID;
  184. }
  185. CResource :: CResource (const CResource & cr ) : m_hRes(cr.m_hRes),m_hResUpdate(cr.m_hResUpdate),
  186. m_pszFile(cr.m_pszFile)
  187. /*++
  188. Abstract:
  189. copy constructor, we use STL, so just copy without creating new member
  190. Arguments:
  191. return:
  192. --*/
  193. {
  194. assert (&cr);
  195. m_vwResType = new cvcstring;
  196. if (!m_vwResType)
  197. return;
  198. m_vwResType = cr.m_vwResType;
  199. m_vwResName = new cvcstring;
  200. if (!m_vwResName)
  201. return;
  202. m_vwResName = cr.m_vwResName;
  203. m_vwResLangID = new cvword;
  204. if (!m_vwResLangID)
  205. return;
  206. m_vwResLangID = cr.m_vwResLangID;
  207. }
  208. CResource & CResource :: operator = (const CResource & cr )
  209. /*++
  210. Abstract:
  211. operator = function.
  212. Arguments:
  213. return:
  214. --*/
  215. {
  216. assert (&cr);
  217. if ( this == &cr ) {
  218. return *this;
  219. }
  220. m_hRes = cr.m_hRes;
  221. m_pszFile = cr.m_pszFile;
  222. m_vwResType = cr.m_vwResType;
  223. m_vwResName = cr.m_vwResName;
  224. m_vwResLangID = cr.m_vwResLangID;
  225. return *this;
  226. }
  227. cvcstring * CResource :: EnumResTypes (LONG_PTR lParam /*= NULL */)
  228. /*++
  229. Abstract:
  230. Wrapper function of Calling the EnumResourceTypes
  231. Arguments:
  232. return:
  233. resource type saved CVector.
  234. --*/
  235. {
  236. m_vwResType -> Clear();
  237. ::EnumResourceTypes( m_hRes, ( ENUMRESTYPEPROC ) EnumResTypeProc, lParam );
  238. return m_vwResType;
  239. }
  240. cvcstring * CResource :: EnumResNames (LPCTSTR pszType, LONG_PTR lParam /*= NULL */)
  241. /*++
  242. Abstract:
  243. Wrapper function of Calling the EnumResNames
  244. Arguments:
  245. return:
  246. resource type saved CVector.
  247. --*/
  248. {
  249. if (m_vwResType -> Empty() ) {
  250. SetResType(pszType);
  251. }
  252. m_vwResName -> Clear();
  253. EnumResourceNames( m_hRes, pszType, (ENUMRESNAMEPROC) EnumResNameProc, lParam );
  254. return m_vwResName;
  255. }
  256. cvword * CResource :: EnumResLangID ( LPCTSTR lpType, LPCTSTR lpName, LONG_PTR lParam /*= NULL */ )
  257. /*++
  258. Abstract:
  259. Wrapper function of Calling the EnumResourceLanguages
  260. Arguments:
  261. return:
  262. resource name saved CVector.
  263. --*/
  264. {
  265. if (m_vwResType -> Empty() ) {
  266. SetResType( lpType );
  267. }
  268. if (m_vwResName -> Empty() ) {
  269. SetResName( lpName );
  270. }
  271. m_vwResLangID -> Clear();
  272. EnumResourceLanguages( m_hRes, lpType, lpName, (ENUMRESLANGPROC) EnumResLangProc, lParam );
  273. return m_vwResLangID;
  274. }
  275. CMUIResource :: CMUIResource() : CResource()
  276. /*++
  277. Abstract:
  278. this is constructor, but it is disabled after creating of Create() function.
  279. Arguments:
  280. return:
  281. --*/
  282. {
  283. m_wChecksumLangId = 0;
  284. m_pcmTreeRoot = new CMUITree;
  285. if(!m_pcmTreeRoot)
  286. return;
  287. m_pMD5 = new MD5_CTX;
  288. if(!m_pMD5)
  289. return;
  290. }
  291. CMUIResource :: CMUIResource(LPCTSTR pszName) : CResource()
  292. /*++
  293. Abstract:
  294. this is another constructor, but it is disabled after creating of Create() function.
  295. Arguments:
  296. return:
  297. --*/
  298. {
  299. m_wChecksumLangId = 0;
  300. m_pcmTreeRoot = new CMUITree;
  301. if(!m_pcmTreeRoot)
  302. return;
  303. m_pMD5 = new MD5_CTX;
  304. if(!m_pMD5)
  305. return;
  306. }
  307. CMUIResource :: CMUIResource(const CMUIResource & cmui ) : CResource ( cmui )
  308. /*++
  309. Abstract:
  310. just copy constructor. we need this function for proper class
  311. Arguments:
  312. return:
  313. --*/
  314. {
  315. m_wChecksumLangId = 0;
  316. m_pcmTreeRoot = new CMUITree;
  317. if(!m_pcmTreeRoot)
  318. return;
  319. m_pMD5 = new MD5_CTX;
  320. if(!m_pMD5)
  321. return;
  322. }
  323. CMUIResource :: ~CMUIResource()
  324. {
  325. PVOID pcmtLangIDDel, pcmtNameDel, pcmtTypeDel;
  326. CMUITree * pcmtType = m_pcmTreeRoot->m_ChildFirst;
  327. while ( pcmtType ){
  328. CMUITree * pcmtName = pcmtType ->m_ChildFirst;
  329. while ( pcmtName ) {
  330. CMUITree * pcmtLangID = pcmtName ->m_ChildFirst;
  331. while ( pcmtLangID ) {
  332. pcmtLangIDDel = pcmtLangID;
  333. pcmtLangID = pcmtLangID->m_Next;
  334. delete pcmtLangIDDel;
  335. }
  336. pcmtNameDel = pcmtName;
  337. pcmtName = pcmtName->m_Next;
  338. delete pcmtNameDel;
  339. }
  340. pcmtTypeDel = pcmtType;
  341. pcmtType = pcmtType->m_Next;
  342. delete pcmtTypeDel;
  343. }
  344. if (m_pcmTreeRoot)
  345. delete m_pcmTreeRoot;
  346. if (m_pMD5)
  347. delete m_pMD5;
  348. };
  349. CMUIResource & CMUIResource :: operator = (const CMUIResource & cmui)
  350. /*++
  351. Abstract:
  352. operator =
  353. Arguments:
  354. return:
  355. --*/
  356. {
  357. if ( this == & cmui ) {
  358. return *this;
  359. }
  360. CResource::operator = ( cmui );
  361. // m_pszRCFile = cmui.m_pszRCFile;
  362. return *this;
  363. }
  364. BOOL CMUIResource::Create(LPCTSTR pszFile)
  365. /*++
  366. Abstract:
  367. loading the file and saving its path and handle
  368. Arguments:
  369. pszFile - file name for used resource. all this call use this file as resource operation
  370. return:
  371. true/false
  372. --*/
  373. {
  374. if( pszFile == NULL )
  375. return FALSE;
  376. m_pszFile = pszFile;
  377. m_hRes = LoadLibraryEx(m_pszFile,NULL, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES );
  378. if ( ! m_hRes ) {
  379. _tprintf (_T("Error happened while loading file(%s),GetLastError() : %d \n"),m_pszFile, GetLastError() );
  380. _tprintf (_T("Please make sure that file name is *.* format \n") );
  381. return FALSE;
  382. }
  383. return TRUE;
  384. }
  385. BOOL CMUIResource::CreatePE( LPCTSTR pszNewResFile, LPCTSTR pszSrcResFile )
  386. /*++
  387. Abstract:
  388. we have two way of creating new resource dll (MUI) one is using UpdateResource and second is
  389. using muibld source and CreateProcess ("link.exe".... ). this is about first one.
  390. We loading the DLL, which is null PE, and we put the new resource into this file by using UpdateResource
  391. function.
  392. This work properly randomly. need to test more before using this.
  393. I think UpdateResource, EndUpdateResource API has some problem ( surely ).
  394. BUG_BUG>
  395. Arguments:
  396. pszNewResFile : new MUI resource name, which will be created at end of this routine.
  397. pszSrcResFile : original source file. we need this because DeleteResource close the resource file handle.
  398. return:
  399. --*/
  400. {
  401. BOOL bRet = FALSE;
  402. if (pszNewResFile == NULL || pszSrcResFile == NULL)
  403. return FALSE;
  404. //
  405. // create a file from the resource template files, which is PE file inlcuding only version resource.
  406. //
  407. HANDLE hFile = CreateFile(pszNewResFile, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  408. if (hFile == INVALID_HANDLE_VALUE ) {
  409. _tprintf (_T(" CreateFile error in CreatePE ,GetLastError() : %d \n"), GetLastError() );
  410. return FALSE;
  411. }
  412. HMODULE hCurrent = LoadLibrary (_T("muirct.exe") ); // m_hRes
  413. HRSRC hrsrc = ::FindResource(hCurrent, MAKEINTRESOURCE(100),MAKEINTRESOURCE(IDR_PE_TEMPLATE) );
  414. if (!hrsrc) {
  415. _tprintf (_T("Fail to find resource template \n") ); // this should never happen
  416. goto exit;
  417. };
  418. HGLOBAL hgTemplateMap = ::LoadResource(hCurrent, hrsrc);
  419. if (!hgTemplateMap) {
  420. goto exit; // This should never happen!
  421. }
  422. int nsize = ::SizeofResource(hCurrent, hrsrc );
  423. LPVOID lpTempate = ::LockResource(hgTemplateMap);
  424. if (!lpTempate)
  425. goto exit;
  426. DWORD dwWritten;
  427. if ( ! WriteFile(hFile, lpTempate, nsize, &dwWritten, NULL ) ) {
  428. _tprintf (_T("Fail to write new file, GetLastError() : %d \n"), GetLastError() );
  429. goto exit;
  430. }
  431. //
  432. // Update selected resource into Template file
  433. //
  434. HANDLE hUpdate = ::BeginUpdateResource ( pszNewResFile, FALSE );
  435. if (hUpdate) {
  436. HMODULE hModule = LoadLibrary ( pszSrcResFile ); // load the source exe file.
  437. LPCTSTR lpType = NULL;
  438. LPCTSTR lpName = NULL;
  439. WORD wWord = 0;
  440. // Add temperary private method for deleting type that UpdateResource return FALSE.
  441. CheckTypeStability();
  442. BOOL fUpdate;
  443. fUpdate = TRUE;
  444. UINT uiSize = m_cMuiData.SizeofData();
  445. BeginUpdateResource(FALSE);
  446. WORD wLangID = 0;
  447. CMUITree * pcmtType = NULL;
  448. pcmtType = m_pcmTreeRoot->m_ChildFirst;
  449. while ( pcmtType ){
  450. lpType = pcmtType ->m_lpTypeorName;
  451. CMUITree * pcmtName = pcmtType ->m_ChildFirst;
  452. while ( pcmtName ){
  453. lpName = pcmtName->m_lpTypeorName;
  454. CMUITree * pcmtLangID = pcmtName ->m_ChildFirst;
  455. while ( pcmtLangID ) {
  456. wLangID = pcmtLangID->m_wLangID;
  457. HRSRC hRsrc = ::FindResourceEx(hModule, lpType, lpName, wLangID );
  458. if (!hRsrc) {
  459. _tprintf (_T("Fail to find resource from the source,Type (%d), Name (%d),LangID(%d) \n"),PtrToUlong(lpType),PtrToUlong(lpName),wLangID );
  460. goto exit;
  461. };
  462. HGLOBAL hgMap = ::LoadResource(hModule, hRsrc);
  463. if (!hgMap) {
  464. goto exit; // This should never happen!
  465. }
  466. nsize = ::SizeofResource(hModule, hRsrc );
  467. LPVOID lpv = ::LockResource(hgMap);
  468. if (! ::UpdateResource(hUpdate , lpType, lpName, wLangID,lpv, nsize ) ) {
  469. _tprintf(_T("Error in the UpdateResource, GetLastError : %d \n"), GetLastError() );
  470. _tprintf(_T("Resource Type (%d),Name (%d),LangID (%d) \n"),PtrToUlong(lpType),PtrToUlong(lpName),wWord);
  471. }
  472. pcmtLangID = pcmtLangID->m_Next;
  473. }
  474. pcmtName = pcmtName->m_Next;
  475. }
  476. pcmtType = pcmtType->m_Next;
  477. }
  478. bRet = ::EndUpdateResource (hUpdate, FALSE );
  479. }
  480. exit:
  481. if (hFile)
  482. CloseHandle (hFile );
  483. return bRet;
  484. }
  485. BOOL CMUIResource :: DeleteResource (WORD wLang /* = O */)
  486. /*++
  487. Abstract:
  488. Delete all resource saved in the CMUIData, which is filled by FillMuiData.
  489. Currenttly, we don't specify the language ID.
  490. Arguments:
  491. return:
  492. --*/
  493. {
  494. // Add temperary private method for deleting type that UpdateResource return FALSE.
  495. CheckTypeStability();
  496. BOOL fUpdate;
  497. fUpdate = TRUE;
  498. UINT uiSize = m_cMuiData.SizeofData();
  499. BeginUpdateResource(FALSE);
  500. LPCTSTR lpType, lpName = NULL;
  501. WORD wLangID = 0;
  502. CMUITree * pcmtType = NULL;
  503. pcmtType = m_pcmTreeRoot->m_ChildFirst;
  504. while ( pcmtType ){
  505. lpType = pcmtType ->m_lpTypeorName;
  506. CMUITree * pcmtName = pcmtType ->m_ChildFirst;
  507. while ( pcmtName ){
  508. lpName = pcmtName->m_lpTypeorName;
  509. CMUITree * pcmtLangID = pcmtName ->m_ChildFirst;
  510. while ( pcmtLangID ) {
  511. wLangID = pcmtLangID->m_wLangID;
  512. //
  513. // we just delete anything on the MUI Tree without checking language ID.
  514. //
  515. if (wLangID) {
  516. if (! UpdateResource(lpType,lpName, wLangID,NULL,NULL ) ) {
  517. }
  518. }
  519. pcmtLangID = pcmtLangID->m_Next;
  520. }
  521. pcmtName = pcmtName->m_Next;
  522. }
  523. pcmtType = pcmtType->m_Next;
  524. }
  525. FreeLibrary ( ); // this should be done before EndUpdateResource.
  526. return EndUpdateResource (FALSE);
  527. }
  528. void CMUIResource :: PrtVerbose ( DWORD dwRate )
  529. /*++
  530. Abstract:
  531. print out removed resource information.
  532. Arguments:
  533. return:
  534. --*/
  535. {
  536. LPCTSTR lpType = NULL;
  537. LPCTSTR lpName = NULL;
  538. WORD wLangID = 0;
  539. UINT uiSize = m_cMuiData.SizeofData();
  540. _tprintf(_T(" Resource Type : Name : LangID \n\n") );
  541. CMUITree * pcmtType = NULL;
  542. pcmtType = m_pcmTreeRoot->m_ChildFirst;
  543. while ( pcmtType ){
  544. lpType = pcmtType ->m_lpTypeorName;
  545. CMUITree * pcmtName = pcmtType ->m_ChildFirst;
  546. while ( pcmtName ) {
  547. lpName = pcmtName->m_lpTypeorName;
  548. CMUITree * pcmtLangID = pcmtName ->m_ChildFirst;
  549. while ( pcmtLangID ) {
  550. wLangID = pcmtLangID->m_wLangID;
  551. if ( PtrToUlong(lpType) & 0xFFFF0000 && PtrToUlong(lpName) & 0xFFFF0000 ) {
  552. _tprintf(_T(" %-15s :%-15s :%7d \n"),lpType,lpName,wLangID );
  553. }
  554. else if (PtrToUlong(lpType) & 0xFFFF0000 ) {
  555. _tprintf(_T(" %-15s :%-15d :%7d \n"),lpType,PtrToUlong(lpName),wLangID );
  556. }
  557. else if (PtrToUlong(lpName) & 0xFFFF0000 ) {
  558. _tprintf(_T(" %-15d :%-15s :%7d \n"),PtrToUlong(lpType),lpName,wLangID );
  559. }
  560. else {
  561. _tprintf(_T(" %-15d :%-15d :%7d \n"),PtrToUlong(lpType),PtrToUlong(lpName),wLangID );
  562. }
  563. pcmtLangID = pcmtLangID->m_Next;
  564. }
  565. pcmtName = pcmtName->m_Next;
  566. }
  567. pcmtType = pcmtType->m_Next;
  568. }
  569. }
  570. BOOL CMUIResource :: DeleteResItem(LPCTSTR lpType, LPCTSTR lpName /*=NULL */,WORD wLanguageID /* = 0 */)
  571. /*++
  572. Abstract:
  573. we only support deletinog of resource Type items from the resource tree
  574. Arguments:
  575. lpType - resource type
  576. lpName - resource name
  577. return:
  578. --*/
  579. {
  580. if ( lpType == NULL) // no 0 resource type.
  581. return FALSE;
  582. return m_pcmTreeRoot->DeleteType(lpType);
  583. }
  584. BOOL CMUIResource :: FillMuiData(cvcstring * vType, WORD wLanguageID, BOOL fForceLocalizedLangID )
  585. /*++
  586. Abstract:
  587. Fill the CMUIData field (Resource Type, Name, Languge ID ). If lpLangID specified, only reosurce
  588. of this LangID is saved. lpLangID is defualt = NULL
  589. Arguments:
  590. vType - Resource Type CVector (pointer array)
  591. wLanguageID - Specified language ID
  592. return:
  593. Note. Although the resource does not have specified language ID, m_pcmTreeRoot will contain its resource type as
  594. its tree, but not used in writing resource, deletiing resource. we need to create only affected resource tree.
  595. if we add and delete type,name when there is no langID, it works but so much damage to perfomance.
  596. i'm not sure of its deserve because the possilble scenario ( -i 16, 23 && wrong langID ) is so rare.
  597. --*/
  598. {
  599. if (vType == NULL)
  600. return FALSE;
  601. // fill Type
  602. CMUITree * pcmtType = NULL;
  603. CMUITree * pcmtTemp = m_pcmTreeRoot->m_ChildFirst;
  604. // get the last item of previous round. last itme will be used as first item to be added in this round.
  605. //
  606. while ( pcmtTemp ) {
  607. pcmtType = pcmtTemp;
  608. pcmtTemp = pcmtTemp->m_Next;
  609. }
  610. // Add more / new items
  611. for ( UINT i = 0; i < vType ->Size(); i ++ ) {
  612. m_pcmTreeRoot->AddTypeorName(vType ->GetValue(i));
  613. }
  614. // get the first items of added or new.
  615. if (pcmtType) {
  616. pcmtType = pcmtType->m_Next;
  617. }
  618. else {
  619. pcmtType = m_pcmTreeRoot->m_ChildFirst;
  620. }
  621. //
  622. // Fill the resource tree.
  623. //
  624. BOOL fNameLangExist, fTypeLangExit; // flag to tell its name or type has language ID.
  625. CMUITree * pcmtTempDelete = NULL; // delete type or name when no language is specified.
  626. while ( pcmtType ) {
  627. fTypeLangExit = FALSE;
  628. LPCTSTR lpType = pcmtType ->m_lpTypeorName;
  629. cvcstring * vName = EnumResNames( lpType,reinterpret_cast <LONG_PTR> ( this ) );
  630. // fill name of specified type
  631. for (UINT j = 0; j < vName->Size(); j ++ )
  632. pcmtType ->AddTypeorName (vName->GetValue(j) );
  633. CMUITree * pcmtName = pcmtType ->m_ChildFirst;
  634. //
  635. // Fill the tree of m_pcmTreeRoot.
  636. //
  637. while ( pcmtName ) {
  638. fNameLangExist = FALSE;
  639. LPCTSTR lpName = pcmtName->m_lpTypeorName;
  640. cvword * vLangID = EnumResLangID(lpType,lpName,reinterpret_cast <LONG_PTR> ( this ) );
  641. // fill langID of specified name
  642. for (UINT k = 0; k < vLangID->Size(); k ++ ) {
  643. WORD wlangID = vLangID->GetValue(k);
  644. //
  645. // sometimes, VERSION is not localized. VERSION should exist on MUI file.
  646. // But, we don't want to force VERSION to be localized when the file does not contain any localized resource.
  647. // note. we will delete unlocalized version and add it to mui file unless -k argu.
  648. // we add !wLanguageID because we want to force all unlocalized resource(only English) to
  649. // be added to mui file as well.
  650. //
  651. // VERSION will be checeked regardless of fForceLocalizedLangID
  652. if ((WORD)PtrToUlong(lpType) == 16 && wlangID == 0x409 && wLanguageID != 0x409)
  653. {
  654. HRSRC hResInfo = FindResourceEx(lpType, lpName, wLanguageID);
  655. if (hResInfo)
  656. { // This is multi lingual DLL. we don't want to extract English Version resource.
  657. continue;
  658. }
  659. }
  660. //
  661. // Multi-lingual component case, we force english language id into specified only when
  662. // there is not speicifed langauge resource.
  663. //
  664. if (fForceLocalizedLangID && wlangID == 0x409 && wLanguageID != 0x409)
  665. {
  666. HRSRC hResInfo = FindResourceEx(lpType, lpName, wLanguageID);
  667. if (hResInfo)
  668. { // This is multi lingual DLL. we don't want to convert English resource to localized when localized resource exist.
  669. continue;
  670. }
  671. }
  672. //
  673. // Finally, we save language ID or force Only English into specified language ID
  674. //
  675. if ( (wlangID == wLanguageID) ||
  676. (fForceLocalizedLangID && (wlangID != wLanguageID) && wlangID == 0x409) ) // || || (WORD)PtrToUlong(lpType) == 16 ){
  677. {
  678. fNameLangExist = TRUE;
  679. fTypeLangExit = TRUE;
  680. pcmtName ->AddLangID(wlangID); // we only save real lang ID so we can retrieve its data when creating mui file.
  681. }
  682. }
  683. pcmtName = pcmtName->m_Next;
  684. if (!fNameLangExist )
  685. {
  686. pcmtType->DeleteType(lpName); // delete pcmtTmepName containg lpName.
  687. }
  688. }
  689. pcmtType = pcmtType->m_Next;
  690. if (! fTypeLangExit)
  691. {
  692. m_pcmTreeRoot->DeleteType(lpType);
  693. }
  694. }
  695. return TRUE;
  696. }
  697. BOOL CMUIResource::WriteResFile( LPCTSTR pszSource, LPCTSTR pszMuiFile, LPCTSTR lpCommandLine, WORD wLanguageID /* = 0 */ )
  698. /*++
  699. Abstract:
  700. we have two way of creating new resource dll (MUI) one is using UpdateResource and second is
  701. using muibld source and CreateProcess ("link.exe".... ). this is about second one.
  702. we have language ID aruguement here, but does not implement for this because we just retrieve the value after
  703. FillMuiData, which already accept only specified language ID.
  704. Arguments:
  705. pszMuiFile - new MUI Resource name
  706. lpCommandLine - command string used for second arg. of CreateProcess
  707. return:
  708. true/false;
  709. --*/
  710. {
  711. if ( pszSource == NULL || pszMuiFile == NULL || lpCommandLine == NULL)
  712. return FALSE;
  713. HANDLE hFile = CreateFile("temp.res", GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  714. if (hFile == INVALID_HANDLE_VALUE ) {
  715. _tprintf (_T(" File creating error,GetLastError() : %d \n"), GetLastError() );
  716. return FALSE;
  717. }
  718. bInsertHeader(hFile); // this is came from muibld.
  719. LPCTSTR lpType,lpName = NULL;
  720. CMUITree * pcmtType = NULL;
  721. CMUITree * pcmtName = NULL;
  722. CMUITree * pcmtLangID = NULL;
  723. WORD wLangID;
  724. pcmtType = m_pcmTreeRoot->m_ChildFirst;
  725. while ( pcmtType ){
  726. lpType = pcmtType ->m_lpTypeorName;
  727. pcmtName = pcmtType ->m_ChildFirst;
  728. while ( pcmtName ) {
  729. lpName = pcmtName->m_lpTypeorName;
  730. pcmtLangID = pcmtName ->m_ChildFirst;
  731. while ( pcmtLangID ) {
  732. wLangID = pcmtLangID->m_wLangID;
  733. if ( wLangID ) { // some name does not have languge ID yet all or different from user specified.
  734. HRSRC hrsrc = FindResourceEx(lpType,lpName, wLangID );
  735. if (! hrsrc ) {
  736. if ( PtrToUlong(lpType) & 0xFFFF0000 ) {
  737. _tprintf (_T("Fail to find resource type:%s, name:%d \n"), lpType,PtrToUlong(lpName) );
  738. }
  739. else {
  740. _tprintf (_T("Fail to find resource type:%d, name:%d \n"), PtrToUlong(lpType),PtrToUlong(lpName) );
  741. }
  742. return FALSE;
  743. }
  744. //
  745. // sometimes, VERSION resource is not localized, so we need to force
  746. // specified language ID be used for MUI file instead un-localized langID.
  747. // All data in this tree is specified language ID except VERSION; refer to FillMuiData
  748. //
  749. // This operation force not only VERSION, but also any unlocalized(but localizable)
  750. // resource added to mui with localized language ID.
  751. //
  752. WriteResource(hFile, m_hRes, wLanguageID, lpName, lpType, hrsrc );
  753. }
  754. pcmtLangID = pcmtLangID->m_Next;
  755. }
  756. pcmtName = pcmtName->m_Next;
  757. }
  758. pcmtType = pcmtType->m_Next;
  759. }
  760. CloseHandle (hFile );
  761. // call CreateProcess for the link.
  762. PROCESS_INFORMATION piProcInfo;
  763. STARTUPINFO si = { 0 };
  764. si.cb = sizeof (si);
  765. // using the lpEnv from GetEnvironmentStrings for CreateProcess simply does not work correctly,
  766. // so we need to get NTMAKEENV, pBuildArch variable.
  767. TCHAR pApp[MAX_ENV_LENGTH];
  768. TCHAR pBuildArch[MAX_ENV_LENGTH];
  769. TCHAR pCmdLine[LINK_COMMAND_LENGTH];
  770. pApp[sizeof(pApp) / sizeof (TCHAR) -1] = '\0';
  771. pBuildArch[sizeof(pBuildArch) / sizeof (TCHAR) -1] = '\0';
  772. pCmdLine[sizeof(pCmdLine) / sizeof (TCHAR) -1] = '\0';
  773. DWORD dwNtEnv = GetEnvironmentVariable("NTMAKEENV", pApp, sizeof (pApp) / sizeof (TCHAR) );
  774. DWORD dwBuildArch = GetEnvironmentVariable("_BuildArch", pBuildArch, sizeof (pBuildArch) /sizeof(TCHAR) );
  775. if ( _T('\0') == *pApp || _T('\0') == *pBuildArch ) {
  776. _tprintf (_T("This is not SD enviroment, link path should be set by default or same directory ") );
  777. }
  778. if ( dwNtEnv > MAX_ENV_LENGTH || dwBuildArch > MAX_ENV_LENGTH) {
  779. _tprintf (_T("Insufficient buffer in GetEnvironmentVariable") );
  780. return FALSE;
  781. }
  782. // _tcsncat(pApp,_T("\\x86\\link.exe"), _tcslen("\\x86\\link.exe")+1 );
  783. HRESULT hr;
  784. PTSTR * ppszDestEnd = NULL;
  785. size_t * pbRem = NULL;
  786. hr = StringCchCatEx(pApp, sizeof (pApp), _T("\\x86\\link.exe"), ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  787. if ( ! SUCCEEDED(hr)){
  788. _tprintf("Safe string copy Error\n");
  789. return FALSE;
  790. }
  791. if (pApp[sizeof(pApp)/sizeof(TCHAR)-1] != '\0' || pBuildArch[sizeof(pBuildArch)/sizeof(TCHAR)-1] != '\0' )
  792. return FALSE; // overflow
  793. if (!_tcsicmp (pBuildArch,_T("ia64") ) ) {
  794. // _sntprintf(pCmdLine ,LINK_COMMAND_LENGTH, _T("%s /machine:IA64 /out:%s temp.res") ,lpCommandLine, pszMuiFile );
  795. hr = StringCchPrintfEx(pCmdLine, LINK_COMMAND_LENGTH, ppszDestEnd, pbRem,
  796. MUIRCT_STRSAFE_NULL, _T("%s /machine:IA64 /out:%s temp.res"), lpCommandLine, pszMuiFile );
  797. if ( ! SUCCEEDED(hr)){
  798. _tprintf("Safe string copy Error\n");
  799. return FALSE;
  800. }
  801. }
  802. else {
  803. // _sntprintf(pCmdLine ,LINK_COMMAND_LENGTH, _T("%s /machine:IX86 /out:%s temp.res") ,lpCommandLine, pszMuiFile );
  804. hr = StringCchPrintfEx(pCmdLine, LINK_COMMAND_LENGTH, ppszDestEnd, pbRem,
  805. MUIRCT_STRSAFE_NULL, _T("%s /machine:IX86 /out:%s temp.res"), lpCommandLine, pszMuiFile );
  806. if ( ! SUCCEEDED(hr)){
  807. _tprintf("Safe string copy Error\n");
  808. return FALSE;
  809. }
  810. }
  811. if (pCmdLine[sizeof(pCmdLine)/sizeof(TCHAR)-1] != '\0')
  812. return FALSE; // overflow
  813. BOOL bRet = CreateProcess(pApp, pCmdLine,NULL, NULL, 0, 0 , NULL, NULL, &si, &piProcInfo);
  814. if (bRet)
  815. { // child process(link.exe) process the IO, so it wait until it complete I/O.
  816. if( (WaitForSingleObjectEx(piProcInfo.hProcess, 1000, FALSE)) != WAIT_OBJECT_0) {
  817. bRet = FALSE;
  818. }
  819. }
  820. return bRet;
  821. }
  822. BOOL CMUIResource:: WriteResource(HANDLE hFile, HMODULE hModule, WORD wLanguage, LPCSTR lpName, LPCSTR lpType, HRSRC hRsrc)
  823. /*++
  824. Abstract:
  825. this came from muibld. Write resource to file directly. we can make buffer before writing to file
  826. in the future edition
  827. Arguments:
  828. return:
  829. --*/
  830. {
  831. HGLOBAL hRes;
  832. PVOID pv;
  833. LONG ResSize=0L;
  834. DWORD iPadding;
  835. unsigned i;
  836. DWORD dwBytesWritten;
  837. DWORD dwHeaderSize=0L;
  838. // Handle other types other than VS_VERSION_INFO
  839. //...write the resource header
  840. if(!(ResSize= ::SizeofResource(hModule, hRsrc)))
  841. {
  842. return FALSE;
  843. }
  844. //
  845. // Generate an item in the RES format (*.res) file.
  846. //
  847. //
  848. // First, we generated header for this resource.
  849. //
  850. if (!WriteResHeader(hFile, ResSize, lpType, lpName, wLanguage, &dwBytesWritten, &dwHeaderSize))
  851. {
  852. return (FALSE);
  853. }
  854. //Second, we copy resource data to the .res file
  855. if (!(hRes=::LoadResource(hModule, hRsrc)))
  856. {
  857. return FALSE;
  858. }
  859. if(!(pv=::LockResource(hRes)))
  860. {
  861. return FALSE;
  862. }
  863. if (!WriteFile(hFile, pv, ResSize, &dwBytesWritten, NULL))
  864. {
  865. return FALSE;
  866. }
  867. //...Make sure resource is DWORD aligned
  868. iPadding=dwBytesWritten%(sizeof(DWORD));
  869. if(iPadding){
  870. for(i=0; i<(sizeof(DWORD)-iPadding); i++){
  871. PutByte (hFile, 0, &dwBytesWritten, NULL);
  872. }
  873. }
  874. return TRUE;
  875. }
  876. BOOL CMUIResource:: WriteResHeader(
  877. HANDLE hFile, LONG ResSize, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, DWORD* pdwBytesWritten, DWORD* pdwHeaderSize)
  878. /*++
  879. Abstract:
  880. Arguments:
  881. return:
  882. --*/
  883. {
  884. DWORD iPadding;
  885. WORD IdFlag=0xFFFF;
  886. unsigned i;
  887. LONG dwOffset;
  888. //...write the resource's size.
  889. PutDWord(hFile, ResSize, pdwBytesWritten, pdwHeaderSize);
  890. //...Put in bogus header size
  891. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize);
  892. //...Write Resource Type
  893. if(PtrToUlong(lpType) & 0xFFFF0000)
  894. {
  895. PutString(hFile, lpType, pdwBytesWritten, pdwHeaderSize);
  896. }
  897. else
  898. {
  899. PutWord(hFile, IdFlag, pdwBytesWritten, pdwHeaderSize);
  900. PutWord(hFile, (USHORT)lpType, pdwBytesWritten, pdwHeaderSize);
  901. }
  902. //...Write Resource Name
  903. if(PtrToUlong(lpName) & 0xFFFF0000){
  904. PutString(hFile, lpName, pdwBytesWritten, pdwHeaderSize);
  905. }
  906. else{
  907. PutWord(hFile, IdFlag, pdwBytesWritten, pdwHeaderSize);
  908. PutWord(hFile, (USHORT)lpName, pdwBytesWritten, pdwHeaderSize);
  909. }
  910. //...Make sure Type and Name are DWORD-aligned
  911. iPadding=(*pdwHeaderSize)%(sizeof(DWORD));
  912. if(iPadding){
  913. for(i=0; i<(sizeof(DWORD)-iPadding); i++){
  914. PutByte (hFile, 0, pdwBytesWritten, pdwHeaderSize);
  915. }
  916. }
  917. //...More Win32 header stuff
  918. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize);
  919. PutWord(hFile, 0x1030, pdwBytesWritten, pdwHeaderSize);
  920. //...Write Language
  921. PutWord(hFile, wLanguage, pdwBytesWritten, pdwHeaderSize);
  922. //...More Win32 header stuff
  923. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize); //... Version
  924. PutDWord(hFile, 0, pdwBytesWritten, pdwHeaderSize); //... Characteristics
  925. dwOffset=(*pdwHeaderSize)-4;
  926. //...Set file pointer to where the header size is
  927. if(SetFilePointer(hFile, -dwOffset, NULL, FILE_CURRENT));
  928. else{
  929. return FALSE;
  930. }
  931. PutDWord(hFile, (*pdwHeaderSize), pdwBytesWritten, NULL);
  932. //...Set file pointer back to the end of the header
  933. if(SetFilePointer(hFile, dwOffset-4, NULL, FILE_CURRENT));
  934. else {
  935. return FALSE;
  936. }
  937. return (TRUE);
  938. }
  939. BOOL CMUIResource:: bInsertHeader(HANDLE hFile){
  940. DWORD dwBytesWritten;
  941. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  942. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  943. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  944. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  945. PutByte (hFile, 0x20, &dwBytesWritten, NULL);
  946. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  947. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  948. PutByte (hFile, 0x00, &dwBytesWritten, NULL);
  949. PutWord (hFile, 0xffff, &dwBytesWritten, NULL);
  950. PutWord (hFile, 0x00, &dwBytesWritten, NULL);
  951. PutWord (hFile, 0xffff, &dwBytesWritten, NULL);
  952. PutWord (hFile, 0x00, &dwBytesWritten, NULL);
  953. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  954. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  955. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  956. PutDWord (hFile, 0L, &dwBytesWritten, NULL);
  957. return TRUE;
  958. }
  959. void CMUIResource:: PutByte(HANDLE OutFile, TCHAR b, ULONG *plSize1, ULONG *plSize2){
  960. BYTE temp=b;
  961. if (plSize2){
  962. (*plSize2)++;
  963. }
  964. WriteFile(OutFile, &b, 1, plSize1, NULL);
  965. }
  966. void CMUIResource:: PutWord(HANDLE OutFile, WORD w, ULONG *plSize1, ULONG *plSize2){
  967. PutByte(OutFile, (BYTE) LOBYTE(w), plSize1, plSize2);
  968. PutByte(OutFile, (BYTE) HIBYTE(w), plSize1, plSize2);
  969. }
  970. void CMUIResource:: PutDWord(HANDLE OutFile, DWORD l, ULONG *plSize1, ULONG *plSize2){
  971. PutWord(OutFile, LOWORD(l), plSize1, plSize2);
  972. PutWord(OutFile, HIWORD(l), plSize1, plSize2);
  973. }
  974. void CMUIResource:: PutString(HANDLE OutFile, LPCSTR szStr , ULONG *plSize1, ULONG *plSize2){
  975. WORD i = 0;
  976. do {
  977. PutWord( OutFile , szStr[ i ], plSize1, plSize2);
  978. }
  979. while ( szStr[ i++ ] != TEXT('\0') );
  980. }
  981. void CMUIResource:: PutStringW(HANDLE OutFile, LPCWSTR szStr , ULONG *plSize1, ULONG *plSize2){
  982. WORD i = 0;
  983. do {
  984. PutWord( OutFile , szStr[ i ], plSize1, plSize2);
  985. }
  986. while ( szStr[ i++ ] != L'\0' );
  987. }
  988. void CMUIResource:: PutPadding(HANDLE OutFile, int paddingCount, ULONG *plSize1, ULONG *plSize2)
  989. {
  990. int i;
  991. for (i = 0; i < paddingCount; i++)
  992. {
  993. PutByte(OutFile, 0x00, plSize1, plSize2);
  994. }
  995. }
  996. void CMUIResource:: CheckTypeStability()
  997. /* ++
  998. Abstract:
  999. Check the type stability. UpdateResource fail when same resource type contain string and ID resource
  1000. name, in this case, it return TRUE but EndUpdateResource hang or fail. this bug fixed in .NET server (after 3501)
  1001. --*/
  1002. {
  1003. BOOL fUpdate;
  1004. fUpdate = TRUE;
  1005. UINT uiSize = m_cMuiData.SizeofData();
  1006. BeginUpdateResource(FALSE);
  1007. LPCTSTR lpType, lpName = NULL;
  1008. WORD wLangID = 0;
  1009. CMUITree * pcmtType = NULL;
  1010. pcmtType = m_pcmTreeRoot->m_ChildFirst;
  1011. LPCTSTR lpFalseType = NULL;
  1012. while ( pcmtType ){
  1013. lpType = pcmtType ->m_lpTypeorName;
  1014. CMUITree * pcmtName = pcmtType ->m_ChildFirst;
  1015. // it works as long as type has more than 1.
  1016. if (lpFalseType) {
  1017. DeleteResItem(lpFalseType);
  1018. lpFalseType = NULL;
  1019. }
  1020. while ( pcmtName ){
  1021. lpName = pcmtName->m_lpTypeorName;
  1022. CMUITree * pcmtLangID = pcmtName ->m_ChildFirst;
  1023. while ( pcmtLangID ) {
  1024. wLangID = pcmtLangID->m_wLangID;
  1025. if (! UpdateResource(lpType,lpName, wLangID,NULL,NULL ) ) {
  1026. // _tprintf(_T("Resource type (%d),name(%d),langid(%d) deletion fail \n"),PtrToUlong(lpType),PtrToUlong(lpName),wLangID ) ;
  1027. // _tprintf(_T("GetLastError() : %d \n") ,GetLastError() );
  1028. lpFalseType = lpType;
  1029. }
  1030. pcmtLangID = pcmtLangID->m_Next;
  1031. }
  1032. pcmtName = pcmtName->m_Next;
  1033. }
  1034. pcmtType = pcmtType->m_Next;
  1035. }
  1036. //If Type has only 1 items, this routin can check.
  1037. if (lpFalseType) {
  1038. DeleteResItem(lpFalseType);
  1039. lpFalseType = NULL;
  1040. }
  1041. EndUpdateResource (TRUE);
  1042. }
  1043. /*******************************************************************************************
  1044. MD5_CTX * CreateChecksum ( LPCTSTR lpChecsumSrcFile )
  1045. *******************************************************************************************/
  1046. MD5_CTX * CMUIResource:: CreateChecksum (cvcstring * cvChecksumResourceTypes, WORD wChecksumLangId )
  1047. {
  1048. if ( cvChecksumResourceTypes == NULL)
  1049. return FALSE;
  1050. if (wChecksumLangId != LANG_CHECKSUM_DEFAULT)
  1051. {
  1052. if(!FindResourceEx(MAKEINTRESOURCE(16), MAKEINTRESOURCE(1), wChecksumLangId))
  1053. { //
  1054. // It does not has specifed language id in version resource, we supposed that this binary does not
  1055. // have any language id specified at all, so we set it as 0 in order to use English instead.
  1056. //
  1057. wChecksumLangId = LANG_CHECKSUM_DEFAULT;
  1058. }
  1059. }
  1060. m_wChecksumLangId = wChecksumLangId;
  1061. // cvcstring * cvType = EnumResTypes(reinterpret_cast <LONG_PTR> (this) );
  1062. MD5Init(m_pMD5);
  1063. for (UINT i = 0; i < cvChecksumResourceTypes->Size(); i ++ ) {
  1064. if ( cvChecksumResourceTypes->GetValue(i) == RT_VERSION )
  1065. continue;
  1066. else
  1067. ::EnumResourceNames(m_hRes, cvChecksumResourceTypes->GetValue(i), ( ENUMRESNAMEPROC )EnumChecksumResNameProc,reinterpret_cast <LONG_PTR> (this) );
  1068. }
  1069. MD5Final(m_pMD5);
  1070. return m_pMD5;
  1071. }
  1072. MD5_CTX * CMUIResource::CreateChecksumWithAllRes(WORD wChecksumLangId)
  1073. /*++
  1074. --*/
  1075. {
  1076. //
  1077. // We calculate the checksum based of the specified language id.
  1078. //
  1079. if (wChecksumLangId != LANG_CHECKSUM_DEFAULT)
  1080. {
  1081. if(!FindResourceEx(MAKEINTRESOURCE(16), MAKEINTRESOURCE(1), wChecksumLangId))
  1082. { //
  1083. // It does not has specifed language id in version resource, we supposed that this binary does not
  1084. // have any language id specified at all, so we set it as 0 in order to use English instead.
  1085. //
  1086. wChecksumLangId = LANG_CHECKSUM_DEFAULT;
  1087. }
  1088. }
  1089. m_wChecksumLangId = wChecksumLangId;
  1090. MD5Init(m_pMD5);
  1091. ::EnumResourceTypes(m_hRes, (ENUMRESTYPEPROC)EnumChecksumResTypeProc,reinterpret_cast <LONG_PTR> (this));
  1092. MD5Final(m_pMD5);
  1093. return m_pMD5;
  1094. }
  1095. BOOL CMUIResource:: AddChecksumToVersion(BYTE * pbMD5Digest)
  1096. /*++
  1097. Abstract:
  1098. Adding a checksum data to MUI file.
  1099. Arguments:
  1100. pbMD5Digest - MD5 hash data (128 bits)
  1101. return:
  1102. --*/
  1103. {
  1104. typedef struct VS_VERSIONINFO
  1105. {
  1106. USHORT TotalSize;
  1107. USHORT DataSize;
  1108. USHORT Type;
  1109. WCHAR szKey[16]; // L"VS_VERSION_INFO" + unicode null terminator
  1110. // Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
  1111. // So that compiler will silently add a 2 bytes padding to make
  1112. // FixedFileInfo to align in DWORD boundary.
  1113. VS_FIXEDFILEINFO FixedFileInfo;
  1114. } VS_VERSIONINFO,* PVS_VERSIONINFO;
  1115. // using the same structure in ldrrsrc.c because this is smart way to get the exact structuree location.
  1116. typedef struct tagVERBLOCK
  1117. {
  1118. USHORT wTotalLen;
  1119. USHORT wValueLen;
  1120. USHORT wType;
  1121. WCHAR szKey[1];
  1122. // BYTE[] padding
  1123. // WORD value;
  1124. } VERBLOCK;
  1125. // this is the structure in the muibld.exe.
  1126. typedef struct VAR_SRC_CHECKSUM
  1127. {
  1128. WORD wLength;
  1129. WORD wValueLength;
  1130. WORD wType;
  1131. WCHAR szResourceChecksum[17]; // For storing "ResourceChecksum\0" null-terminated string in Unicode.
  1132. // BYTE[] padding
  1133. // DWORD dwChecksum[4]; // 128 bit checksum = 16 bytes = 4 DWORD.
  1134. } VAR_SRC_CHECKSUM;
  1135. if (pbMD5Digest == NULL)
  1136. return FALSE;
  1137. //
  1138. // Get VersionInfo structure.
  1139. //
  1140. DWORD dwHandle;
  1141. LPVOID lpVerRes = NULL;
  1142. DWORD dwVerSize = GetFileVersionInfoSize( (LPTSTR) m_pszFile,&dwHandle);
  1143. lpVerRes = new CHAR[dwVerSize + VERSION_SECTION_BUFFER];
  1144. if(!lpVerRes)
  1145. goto exit;
  1146. if ( ! GetFileVersionInfo((LPTSTR)m_pszFile, 0 ,dwVerSize,lpVerRes) ) {
  1147. _tprintf(_T("Fail to get file version: GetLastError() : %d \n"),GetLastError() ) ;
  1148. printf("%s", m_pszFile);
  1149. goto exit;
  1150. }
  1151. PVS_VERSIONINFO pVersionInfo = (VS_VERSIONINFO *) lpVerRes;
  1152. // Sanity check for the verion info
  1153. LONG lResVerSize = (LONG)pVersionInfo ->TotalSize;
  1154. LONG lNewResVerSize = lResVerSize; // new Vesrion file when UpdateResource
  1155. VERBLOCK * pVerBlock = NULL;
  1156. BOOL fSuccess = FALSE;
  1157. //
  1158. // Adding checksum Resource data into inside VarFileInfo
  1159. //
  1160. if ( lResVerSize > 0 ) {
  1161. if ( wcscmp(pVersionInfo ->szKey,L"VS_VERSION_INFO") ) {
  1162. _tprintf(_T("This is not correct Version resource") );
  1163. goto exit;
  1164. }
  1165. WORD wBlockSize = (WORD)AlignDWORD ( sizeof (VS_VERSIONINFO) );
  1166. lResVerSize -= wBlockSize;
  1167. pVerBlock = (VERBLOCK *) ( pVersionInfo + 1 );
  1168. while ( lResVerSize > 0 ) {
  1169. if ( ! wcscmp(pVerBlock ->szKey,L"VarFileInfo") ) {
  1170. VERBLOCK * pVarVerBlock = pVerBlock;
  1171. LONG lVarFileSize = (LONG)pVerBlock->wTotalLen;
  1172. lResVerSize -= lVarFileSize;
  1173. WORD wVarBlockSize = (WORD) AlignDWORD (sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
  1174. lVarFileSize -= wVarBlockSize;
  1175. pVerBlock = (VERBLOCK *)((PBYTE) pVerBlock + wVarBlockSize );
  1176. while (lVarFileSize > 0 ) {
  1177. if ( ! wcscmp(pVerBlock ->szKey,L"Translation") ) {
  1178. VAR_SRC_CHECKSUM * pVarSrcChecsum = (VAR_SRC_CHECKSUM *)new BYTE[VERSION_SECTION_BUFFER];
  1179. // VAR_SRC_CHECKSUM * pVarSrcChecsum = new VAR_SRC_CHECKSUM;
  1180. if ( !pVarSrcChecsum) {
  1181. _tprintf(_T("Memory Insufficient error in CCompactMUIFile::updateCodeFile"));
  1182. goto exit;
  1183. }
  1184. wVarBlockSize = (WORD)AlignDWORD ( pVerBlock ->wTotalLen );
  1185. PBYTE pStartChecksum = (PBYTE) pVerBlock + wVarBlockSize ;
  1186. // Fill the structure.
  1187. pVarSrcChecsum->wLength = sizeof (VAR_SRC_CHECKSUM);
  1188. pVarSrcChecsum->wValueLength = 16;
  1189. pVarSrcChecsum->wType = 0;
  1190. //wcscpy(pVarSrcChecsum->szResourceChecksum,L"ResourceChecksum");
  1191. PWSTR * ppszDestEnd = NULL;
  1192. size_t * pbRem = NULL;
  1193. HRESULT hr;
  1194. hr = StringCchCopyExW(pVarSrcChecsum->szResourceChecksum, sizeof (pVarSrcChecsum->szResourceChecksum)/ sizeof(WCHAR),
  1195. L"ResourceChecksum", ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  1196. if ( ! SUCCEEDED(hr)){
  1197. _tprintf("Safe string copy Error\n");
  1198. goto exit;
  1199. }
  1200. pVarSrcChecsum->wLength = (WORD)AlignDWORD((BYTE)pVarSrcChecsum->wLength); // + sizeof (L"ResourceChecksum") );
  1201. memcpy((PBYTE)pVarSrcChecsum + pVarSrcChecsum->wLength, pbMD5Digest, RESOURCE_CHECKSUM_SIZE);
  1202. pVarSrcChecsum->wLength += RESOURCE_CHECKSUM_SIZE;
  1203. // memcpy(pStartChecksum,pVarSrcChecsum,sizeof(VAR_SRC_CHECKSUM) );
  1204. // When checksum length is not DWORD, we need to align this.( in this case, redundant)
  1205. pVarSrcChecsum->wLength = (WORD)AlignDWORD((BYTE)pVarSrcChecsum->wLength);
  1206. pVarVerBlock->wTotalLen += pVarSrcChecsum->wLength; // update length of VarFileInfo
  1207. lNewResVerSize += pVarSrcChecsum->wLength;
  1208. pVersionInfo ->TotalSize = (WORD)lNewResVerSize;
  1209. lVarFileSize -= wVarBlockSize;
  1210. // Push the any block in VarInfo after new inserted block "ResourceChecksum"
  1211. if ( lVarFileSize ) {
  1212. PBYTE pPushedBlock = new BYTE[lVarFileSize ];
  1213. if ( pPushedBlock) {
  1214. memcpy(pPushedBlock, pStartChecksum, lVarFileSize );
  1215. memcpy(pStartChecksum + pVarSrcChecsum->wLength, pPushedBlock, lVarFileSize );
  1216. }
  1217. else
  1218. {
  1219. _tprintf(_T("Insufficient memory error in CCompactMUIFile::updateCodeFile"));
  1220. }
  1221. delete []pPushedBlock;
  1222. }
  1223. memcpy(pStartChecksum, pVarSrcChecsum, pVarSrcChecsum->wLength );
  1224. fSuccess = TRUE;
  1225. delete [] pVarSrcChecsum;
  1226. break;
  1227. }
  1228. wVarBlockSize = (WORD)AlignDWORD ( pVerBlock ->wTotalLen );
  1229. lVarFileSize -= wVarBlockSize;
  1230. pVerBlock = (VERBLOCK* ) ( (PBYTE) pVerBlock + wVarBlockSize );
  1231. } // while (lVarFileSize > 0 ) {
  1232. pVerBlock = (VERBLOCK* ) ( (PBYTE) pVarVerBlock->wTotalLen );
  1233. }
  1234. else {
  1235. wBlockSize = (WORD) AlignDWORD ( pVerBlock ->wTotalLen );
  1236. lResVerSize -= wBlockSize;
  1237. pVerBlock = (VERBLOCK * ) ( (PBYTE) pVerBlock + wBlockSize );
  1238. }
  1239. if (fSuccess)
  1240. break;
  1241. }
  1242. }
  1243. //
  1244. // Update file by using UpdateResource function
  1245. //
  1246. BOOL fVersionExist = FALSE;
  1247. BOOL fUpdateSuccess = FALSE;
  1248. BOOL fEndUpdate = FALSE;
  1249. if ( fSuccess ) {
  1250. BeginUpdateResource( FALSE );
  1251. cvcstring * cvName = EnumResNames(MAKEINTRESOURCE(RT_VERSION),reinterpret_cast <LONG_PTR> (this) );
  1252. for (UINT j = 0; j < cvName->Size();j ++ ) {
  1253. cvword * cvLang = EnumResLangID(MAKEINTRESOURCE(RT_VERSION),cvName->GetValue(j),reinterpret_cast <LONG_PTR> (this) );
  1254. for (UINT k = 0; k < cvLang->Size();k ++ ) {
  1255. fUpdateSuccess = UpdateResource(MAKEINTRESOURCE(RT_VERSION),cvName->GetValue(j),cvLang->GetValue(k),lpVerRes,lNewResVerSize);
  1256. fVersionExist = TRUE;
  1257. }
  1258. }
  1259. FreeLibrary();
  1260. fEndUpdate = EndUpdateResource(FALSE);
  1261. }
  1262. else{
  1263. goto exit;
  1264. }
  1265. if( ! fVersionExist ){
  1266. _tprintf(_T("no RT_VERSION type exist in the file %s \n"),m_pszFile);
  1267. }
  1268. exit:
  1269. if(lpVerRes)
  1270. delete []lpVerRes;
  1271. return ( fEndUpdate & fVersionExist & fUpdateSuccess );
  1272. }
  1273. BOOL CMUIResource:: UpdateNtHeader(LPCTSTR pszFileName, DWORD dwUpdatedField )
  1274. /*++
  1275. Abstract:
  1276. Update PE header for checksum, which should be updated for windows setup; Windows setup check the PE file checksum
  1277. on the fly.
  1278. Arguments:
  1279. pszFileName - target file
  1280. dwUpdatedField - updated field in PE structure.
  1281. return:
  1282. --*/
  1283. {
  1284. PIMAGE_NT_HEADERS pNtheader = NULL;
  1285. BOOL bRet = FALSE;
  1286. if (pszFileName == NULL)
  1287. goto exit;
  1288. //
  1289. // Open file with read/write and map file.
  1290. //
  1291. HANDLE hFile = CreateFile(pszFileName,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,
  1292. NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  1293. if (hFile == INVALID_HANDLE_VALUE) {
  1294. _tprintf(_T("Couldn't open a file< %s> with CreateFile \n"), pszFileName );
  1295. goto exit;
  1296. }
  1297. HANDLE hMappedFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL );
  1298. if (hMappedFile == 0 ) {
  1299. _tprintf(_T("Couldn't ope a file mapping with CreateFileMapping \n") );
  1300. goto exit;
  1301. }
  1302. PVOID pImageBase = MapViewOfFile(hMappedFile,FILE_MAP_WRITE, 0, 0, 0);
  1303. if (pImageBase == NULL ) {
  1304. _tprintf(_T("Couldn't mape view of file with MapViewOfFile \n") );
  1305. goto exit;
  1306. }
  1307. //
  1308. // Locate ntheader; same routine of RtlImageNtHeader
  1309. //
  1310. if (pImageBase != NULL && pImageBase != (PVOID)-1) {
  1311. if (((PIMAGE_DOS_HEADER)pImageBase)->e_magic == IMAGE_DOS_SIGNATURE) {
  1312. pNtheader = (PIMAGE_NT_HEADERS)((PCHAR)pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew);
  1313. }
  1314. else
  1315. {
  1316. _tprintf(_T("This file is not PE foramt \n") );
  1317. goto exit;
  1318. }
  1319. }
  1320. //
  1321. // GetChecksum data through ImageHlp function.
  1322. //
  1323. if ( dwUpdatedField & CHECKSUM ) {
  1324. DWORD dwHeaderSum = 0;
  1325. DWORD dwCheckSum = 0;
  1326. MapFileAndCheckSum((PTSTR)pszFileName,&dwHeaderSum,&dwCheckSum);
  1327. if (pNtheader != NULL && dwHeaderSum != dwCheckSum ) {
  1328. pNtheader->OptionalHeader.CheckSum = dwCheckSum;
  1329. }
  1330. }
  1331. //
  1332. // Write checksum data to mapped file directly.
  1333. //
  1334. bRet = TRUE;
  1335. exit:
  1336. if (hFile)
  1337. CloseHandle(hFile);
  1338. if (hMappedFile)
  1339. CloseHandle(hMappedFile);
  1340. if (pImageBase)
  1341. UnmapViewOfFile(pImageBase);
  1342. return bRet;
  1343. }
  1344. /**************************************************************************************************
  1345. CMUIData::CMap::CMap()
  1346. ***************************************************************************************************/
  1347. CMUIData::CMap::CMap() {
  1348. m_lpType = NULL;
  1349. m_lpName = NULL;
  1350. m_wLangID = 0;
  1351. }
  1352. void CMUIData :: SetAllData(LPCTSTR lpType,LPCTSTR lpName, WORD wLang, UINT i )
  1353. /*++
  1354. Abstract:
  1355. Set all resource type,name,langid
  1356. Arguments:
  1357. lpType : resource type,
  1358. lpName : resource name,
  1359. wLang : resource language id
  1360. i : number of resource so far. (index)
  1361. return:
  1362. --*/
  1363. {
  1364. //HLOCAL hMem = LocalAlloc(LMEM_ZEROINIT,sizeof(CMap) );
  1365. // REVISIT : seems like new operator bug. we beat the error by using LocalAlloc at this time.
  1366. // guess : LocalAlloc can be same with HeapCreate in terms of deleting memory when process end.so gabarge collection for these.
  1367. // m_cmap[i] = (CMap*) LocalLock(hMem); // new CMap ;
  1368. // disable below line due to Prefast error,anyway, this routine is dead.
  1369. #ifdef NEVER
  1370. CMap * pCmap = new CMap;
  1371. pCmap->m_lpType = lpType;
  1372. pCmap->m_lpName = lpName;
  1373. pCmap->m_wLangID = wLang;
  1374. m_iSize = i + 1;
  1375. #endif
  1376. }
  1377. void CMUIData::SetType(UINT index, LPCTSTR lpType)
  1378. {
  1379. m_cmap[index].m_lpType = lpType;
  1380. }
  1381. CMUIData::~ CMUIData() {
  1382. // for ( UINT i = 0; i < m_iSize; i ++ )
  1383. // delete m_cmap[i];
  1384. if (m_cmap)
  1385. delete [] m_cmap;
  1386. };
  1387. CMUIData::CMap* CMUIData::m_cmap = NULL;
  1388. CMUIData::CMap* CMUIData::m_poffset = NULL;
  1389. const UINT CMUIData::MAX_SIZE_RESOURCE = 1000;
  1390. UINT CMUIData::m_index = 0;
  1391. PVOID CMUIData::CMap::operator new (size_t size)
  1392. /*++
  1393. Abstract:
  1394. Arguments:
  1395. return:
  1396. --*/
  1397. {
  1398. static DWORD dwExpand = 0;
  1399. if ( ! m_cmap ) {
  1400. m_cmap = m_poffset = ::new CMap[ MAX_SIZE_RESOURCE ];
  1401. if (! m_cmap)
  1402. _tprintf(_T("resource insufficient") );
  1403. dwExpand ++;
  1404. m_index ++;
  1405. return m_poffset;
  1406. }
  1407. if ( m_index < MAX_SIZE_RESOURCE * dwExpand ) {
  1408. m_index ++;
  1409. return ++ m_poffset ;
  1410. }
  1411. else {
  1412. dwExpand ++;
  1413. CMap * ptbase = NULL;
  1414. CMap * ptoffset = NULL;
  1415. size_t tsize = dwExpand *MAX_SIZE_RESOURCE;
  1416. ptbase = ptoffset = ::new CMap [ tsize ];
  1417. for ( UINT i = 0; i < ( dwExpand - 1 ) * MAX_SIZE_RESOURCE; i ++ ) {
  1418. memcpy( ptoffset++, &m_cmap [i],sizeof(CMap) );
  1419. }
  1420. ::delete [] m_cmap;
  1421. m_cmap = ptbase;
  1422. m_poffset = ptoffset;
  1423. m_index ++;
  1424. return m_poffset;
  1425. }
  1426. }
  1427. void CMUIData::CMap::operator delete ( void *p ) {
  1428. m_poffset = m_poffset - 1;
  1429. }
  1430. // this can be removed ? I mean, just use API instead of Wrapper. but m_hResUpdate also is member of this file.
  1431. // I just live this one .
  1432. inline HANDLE CResource::BeginUpdateResource(BOOL bDeleteExistingResources )
  1433. {
  1434. return (m_hResUpdate = ::BeginUpdateResource( m_pszFile, bDeleteExistingResources) );
  1435. };
  1436. inline BOOL CResource:: UpdateResource (LPCTSTR lpType,LPCTSTR lpName,WORD wLanguage, LPVOID lpData, DWORD cbData) {
  1437. return ::UpdateResource( m_hResUpdate, lpType, lpName, wLanguage, lpData, cbData );
  1438. };
  1439. inline BOOL CResource::EndUpdateResource(BOOL bDiscard)
  1440. {
  1441. return ::EndUpdateResource (m_hResUpdate, bDiscard );
  1442. }
  1443. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1444. //
  1445. // CMuiCmdInfo
  1446. //
  1447. //////////////////////////////////////////////////////////////////////////////////////////////////
  1448. CMuiCmdInfo :: CMuiCmdInfo() : CCommandInfo() ,m_uiCount(0){
  1449. m_buf = NULL;
  1450. m_buf2 = NULL;
  1451. };
  1452. CMuiCmdInfo :: ~CMuiCmdInfo() {
  1453. if ( m_buf )
  1454. delete [] m_buf;
  1455. if (m_buf2)
  1456. delete [] m_buf2;
  1457. };
  1458. CMuiCmdInfo :: CMuiCmdInfo ( CMuiCmdInfo& cav ):CCommandInfo(cav) // : m_mArgList = cav.m_mArgList
  1459. {
  1460. m_pszArgLists = NULL;
  1461. }
  1462. // no implementatin and can't be used by client
  1463. CMuiCmdInfo& CMuiCmdInfo :: operator = ( CMuiCmdInfo& cav )
  1464. {
  1465. return *this;
  1466. }
  1467. void CMuiCmdInfo :: SetArgLists(LPTSTR pszArgLists, LPTSTR pszArgNeedValueList, LPTSTR pszArgAllowFileValue,
  1468. LPTSTR pszArgAllowMultiValue )
  1469. /*++
  1470. Abstract:
  1471. Set internal arguments list with new arugments lists
  1472. Arguments:
  1473. pszArgLists - string of arguments list, each character of this string is argument.
  1474. it does not allow string arg. like -kb, -ad.
  1475. pszArgNeedValueList - Argument requiring values.
  1476. pszArgAllowFileValue - Argument allowing file name value
  1477. pszArgAllowMultiValue - Argument allowing multiple file value
  1478. return:
  1479. --*/
  1480. {
  1481. if ( pszArgLists == NULL || pszArgNeedValueList == NULL ||
  1482. pszArgAllowFileValue == NULL || pszArgAllowMultiValue == NULL)
  1483. return ;
  1484. m_pszArgLists = pszArgLists;
  1485. m_pszArgNeedValueList = pszArgNeedValueList;
  1486. m_pszArgAllowMultiValue = pszArgAllowMultiValue;
  1487. m_pszArgAllowFileValue = pszArgAllowFileValue;
  1488. }
  1489. BOOL CMuiCmdInfo :: CreateArgList(INT argc, TCHAR * argv [] )
  1490. /*++
  1491. Abstract:
  1492. Create mapping table with its argument and its values. The argument type are classified by
  1493. 1. No need values
  1494. 2. No File Arguments. regardless of one or muliple values "a""i", "k", "y" "o","p",
  1495. 3. File, no Multiple. "c", "f", "d","e",
  1496. 4. File, Multiple. "m", "a"
  1497. Arguments:
  1498. argc : arguments count
  1499. argv : argument values pointer to string array
  1500. return:
  1501. --*/
  1502. {
  1503. DWORD dwBufSize = 0;
  1504. HRESULT hr;
  1505. PTSTR * ppszDestEnd = NULL;
  1506. size_t * pbRem = NULL;
  1507. if ( argc < 2 ) {
  1508. _tprintf(_T("MUIRCT [-h|?] -l langid [-i resource_type] [-k resource_type] [-y resource_type] \n") );
  1509. _tprintf(_T("source_filename, [language_neutral_filename], [MUI_filename] \n\n"));
  1510. return FALSE;
  1511. }
  1512. LPCTSTR lpVal = NULL;
  1513. for ( int i = 1; i < argc; ) {
  1514. if ( lpVal = getArgValue (argv[i]) ) {
  1515. if ( ++ i >= argc ) { // we need a source file name
  1516. _tprintf ("MUIRCT needs a source file name and new dll name or file name does not have format *.* \n" );
  1517. _tprintf(_T("MUIRCT [-h|?] -l langid [-i resource_type] [-k resource_type] [-y resource_type] \n") );
  1518. _tprintf(_T("source_filename, [language_neutral_filename], [MUI_filename] \n\n"));
  1519. return FALSE;
  1520. }
  1521. // #ifdef NEVER
  1522. if ( getArgValue(argv[i]) )
  1523. {
  1524. if (!isNeedValue(lpVal) ) // -i -X ... case. -i don't need values.
  1525. {
  1526. m_cmap[m_uiCount].m_first = lpVal;
  1527. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = _T("ALL");
  1528. m_uiCount ++;
  1529. //i--; // this is not a value for argument.
  1530. continue;
  1531. }
  1532. else
  1533. {
  1534. _tprintf ("%s argument need values. e.g. muirct -l 0x0409 \n " , argv[ i- 1 ] );
  1535. return FALSE;
  1536. }
  1537. }
  1538. if (!isAllowFileValue(lpVal) )
  1539. {
  1540. m_cmap[m_uiCount].m_first = lpVal;
  1541. while (i < argc && !getArgValue (argv[i]) && !isFile(argv[i]) )
  1542. {
  1543. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = argv [i];
  1544. i++ ;
  1545. }
  1546. m_uiCount ++;
  1547. i--;
  1548. }
  1549. else if (isAllowFileValue(lpVal) && isAllowMultiFileValues(lpVal) )
  1550. {
  1551. m_cmap[m_uiCount].m_first = lpVal;
  1552. while (i < argc && !getArgValue ( argv[ i ] ))
  1553. {
  1554. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = argv [i];
  1555. i++ ;
  1556. }
  1557. m_uiCount ++;
  1558. i--;
  1559. }
  1560. else if (isAllowFileValue(lpVal) && !isAllowMultiFileValues(lpVal) )
  1561. {
  1562. m_cmap[m_uiCount].m_first = lpVal;
  1563. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = argv [i];
  1564. m_uiCount ++;
  1565. }
  1566. else
  1567. {
  1568. _tprintf(_T(" <%s> is not a supported argument\n"), lpVal );
  1569. return FALSE;
  1570. }
  1571. i++;
  1572. }
  1573. // #endif
  1574. #ifdef NEVER
  1575. if ( ! getArgValue( argv [ i] ) && (! isFile ( argv[ i ] ) || isAllowFileValue(lpVal) ) ) {
  1576. m_cmap[m_uiCount].m_first = lpVal;
  1577. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = argv [i];
  1578. // // the argu. is in the if() are arg. allowing multiple values.
  1579. // while ( ++ i < argc && ! getArgValue ( argv[ i ] ) && (! isFile ( argv[ i ] )
  1580. // || _T('m') == *lpVal || _T('a') == *lpVal) )// prevent "" be called
  1581. while ( ++ i < argc && ! getArgValue ( argv[ i ] ) && (! isFile ( argv[ i ] )
  1582. || isAllowMultiFileValues(lpVal) ) )// prevent "" be called
  1583. {
  1584. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = argv [i];
  1585. }
  1586. m_uiCount ++;
  1587. }
  1588. else { // "-i" argument or file.
  1589. if ( isNeedValue (argv [i-1] ) ) {
  1590. _tprintf ("%s argument need values. e.g. muirct -l 0x0409 \n " , argv[ i- 1 ] );
  1591. return FALSE;
  1592. }
  1593. else {
  1594. m_cmap[m_uiCount].m_first = lpVal;
  1595. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount].m_count++] = _T("ALL"); // need to revisit.
  1596. m_uiCount ++;
  1597. }
  1598. }
  1599. } // if ( lpVal = getArgValue ( argv[i] ) ) {
  1600. #endif
  1601. else if (! isFile( argv [i]) ) {
  1602. if ( _T('h') == argv[i][1] || _T('H') == argv[i][1] || _T('?') == argv[i][1] ) {
  1603. _tprintf(_T("\n\n") );
  1604. _tprintf(_T("MUIRCT [-h|?] -l langid [-c checksum_file ] [-i removing_resource_types] \n" ) );
  1605. _tprintf(_T(" [ -k keeping_resource_types] [ -y keeping_resource_types] [-v level] source_file \n" ) );
  1606. _tprintf(_T(" [langue_neutral_filename] [MUI_filename]\n\n") );
  1607. _tprintf(_T("-h(elp) or -? : Show help screen.\n\n") );
  1608. _tprintf(_T("-l(anguage)langid: Extract only resource in this language.\n") );
  1609. _tprintf(_T(" The language resource must be specified. The value is in decimal.\n\n") );
  1610. _tprintf(_T("-c(hecksum file) : Calculate the checksum on the based of this file,and put this data \n") );
  1611. _tprintf(_T(" into language_neutral_file and mui_file.\n\n") );
  1612. _tprintf(_T("-i(clude removed): Include certain resource types,\n") );
  1613. _tprintf(_T("resource_type e.g. -i 2 3 4 or -i reginst avi 3 4 .\n") );
  1614. _tprintf(_T(" -i (to inlcude all resources). \n" ) );
  1615. _tprintf(_T(" Multiple inclusion is possible. If this\n") );
  1616. _tprintf(_T(" flag is not used, all types are included like -i \n") );
  1617. _tprintf(_T(" Standard resource types must be specified\n") );
  1618. _tprintf(_T(" by number. See below for list.\n") );
  1619. _tprintf(_T(" Types 1 and 12 are always included in pairs,\n") );
  1620. _tprintf(_T(" even if only one is specified. Types 3 and 14\n") );
  1621. _tprintf(_T(" are always included in pairs, too.\n\n\n") );
  1622. _tprintf(_T("-k(eep resource) : Keep specified resources in langue_neutral_file and \n") );
  1623. _tprintf(_T(" also included in mui file.\n") );
  1624. _tprintf(_T(" Its usage is same with -i argument. \n\n") );
  1625. _tprintf(_T("-y : This is same with -k argument except it does not check \n") );
  1626. _tprintf(_T(" if the values are in the -i values.\n\n") );
  1627. _tprintf(_T("-o : This is same with -i argument except it does not check \n") );
  1628. _tprintf(_T(" if the types are exist in the source file.\n\n") );
  1629. _tprintf(_T("-z : Calculate and insert only checksum data to specific file \n") );
  1630. _tprintf(_T(" eg. muirct -c notepad.exe -i[-o] 3 4 5 6 8 -z notepad2.exe .\n\n") );
  1631. _tprintf(_T("-p : Delete types from source file, but does not want to add into mui file \n\n") );
  1632. _tprintf(_T("-x : Add all resource types into MUI file as specified language id \n"));
  1633. _tprintf(_T(" regardless of language ID \n\n"));
  1634. _tprintf(_T("-v(erbose) level : Print all affected resource type, name, langID when level is 2.\n\n") );
  1635. _tprintf(_T("source_filename : The localized source file (no wildcard support)\n\n") );
  1636. _tprintf(_T("language_neutral_: Optional. If no filename is specified,\n") );
  1637. _tprintf(_T("_filename a second extension .new is added to the\n") );
  1638. _tprintf(_T(" source_filename.\n\n") );
  1639. _tprintf(_T("mui_filename : Optional. If no target_filename is specified,\n") );
  1640. _tprintf(_T(" a second extension .mui is added to the \n") );
  1641. _tprintf(_T(" source_filename.\n\n") );
  1642. _tprintf(_T("-m : CMF, enumerate compacted mui files \n") );
  1643. _tprintf(_T(" eg. muirct -m notepad.exe.mui foo.dll.mui bar.dll.mui .\n\n") );
  1644. _tprintf(_T("-e : CMF, the directory of matching execute file of compacted mui files \n\n") );
  1645. _tprintf(_T("-f : CMF, newly created CMF file name \n") );
  1646. _tprintf(_T(" eg, muirct -m foo.dll.mui bar.dll.mui -f far.cmf -d c:\\file\\exe \n\n") );
  1647. _tprintf(_T("-d : CMF, dump CMF headers information \n\n\n") );
  1648. _tprintf(_T("Standard Resource Types: CURSOR(1) BITMAP(2) ICON(3) MENU(4) DIALOG(5)\n") );
  1649. _tprintf(_T("STRING(6) FONTDIR(7) FONT(8) ACCELERATORS(9) RCDATA(10) MESSAGETABLE(11)\n") );
  1650. _tprintf(_T("GROUP_CURSOR(12) GROUP_ICON(14) VERSION(16)\n\n\n") );
  1651. }
  1652. else {
  1653. _tprintf(_T("%s argument is not supported \n" ),argv[i] );
  1654. _tprintf(_T("MUIRCT needs a source file name and new dll name or file name does not have format *.* \n" ) );
  1655. _tprintf(_T("MUIRCT [-h|?] -l langid [-i resource_type] [-k resource_type] [-y resource_type] \n") );
  1656. _tprintf(_T("source_filename, [language_neutral_filename], [MUI_filename] \n\n"));
  1657. }
  1658. return FALSE;
  1659. } // ! isFile( argv [i] ) ) {
  1660. else {
  1661. m_cmap[m_uiCount].m_first = _T("source");
  1662. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount++].m_count++] = argv[i++];
  1663. //m_mArgList.insert(make_pair(,argv[i++] ) );
  1664. if ( i < argc ) {
  1665. m_cmap[m_uiCount].m_first = _T("muidll");
  1666. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount++].m_count++] = argv[i++];
  1667. // m_mArgList.insert(make_pair("muidll",argv[i++] ) );
  1668. if ( i < argc ) {
  1669. m_cmap[m_uiCount].m_first = _T("muires");
  1670. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount++].m_count++] = argv[i++];
  1671. // m_mArgList.insert(make_pair("muires",argv[i] ) );
  1672. }
  1673. else {
  1674. dwBufSize = _tcslen(argv[i-2]) + 10;
  1675. m_buf = new TCHAR[dwBufSize]; // 10 is enough number, actually we need just 4 .
  1676. if (m_buf == NULL) {
  1677. _tprintf(_T("Insufficient memory resource\n"));
  1678. return FALSE;
  1679. }
  1680. memcpy ( m_buf, argv[i-2], _tcslen(argv[i-2])+1 ) ; // source.mui instead of newfile.mui
  1681. // _tcscat(m_buf,_T(".mui" ) );
  1682. hr = StringCchCatEx(m_buf, dwBufSize , _T("mui"), ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  1683. if ( ! SUCCEEDED(hr)){
  1684. _tprintf("Safe string copy Error\n");
  1685. return FALSE;
  1686. }
  1687. m_cmap[m_uiCount].m_first = "muires";
  1688. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount++].m_count++] = m_buf; // argv[i++];
  1689. //i++;
  1690. }
  1691. }
  1692. else {
  1693. dwBufSize = _tcslen(argv[i-1]) + 10;
  1694. m_buf = new TCHAR[dwBufSize];
  1695. if (m_buf == NULL) {
  1696. _tprintf(_T("Insufficient memory resource\n"));
  1697. return FALSE;
  1698. }
  1699. memcpy (m_buf, argv[i-1], _tcslen(argv[i-1])+1 );
  1700. // _tcscat(m_buf,_T(".new") );
  1701. hr = StringCchCatEx(m_buf, dwBufSize , _T(".new"), ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  1702. if ( ! SUCCEEDED(hr)){
  1703. _tprintf("Safe string copy Error\n");
  1704. return FALSE;
  1705. }
  1706. m_cmap[m_uiCount].m_first = _T("muidll");
  1707. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount++].m_count++] = m_buf; // argv[i];
  1708. //m_mArgList.insert(make_pair("muidll",argv[i]));
  1709. dwBufSize = _tcslen(argv[i-1])+ 10;
  1710. m_buf2 = new TCHAR[dwBufSize];
  1711. if (m_buf2 == NULL) {
  1712. _tprintf(_T("Insufficient memory resource\n"));
  1713. return FALSE;
  1714. }
  1715. memcpy (m_buf2, argv[i-1], _tcslen(argv[i-1])+1 );
  1716. // _tcscat(m_buf2,_T(".mui") );
  1717. hr = StringCchCatEx(m_buf2, dwBufSize , _T(".mui"), ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  1718. if ( ! SUCCEEDED(hr)){
  1719. _tprintf("Safe string copy Error\n");
  1720. return FALSE;
  1721. }
  1722. m_cmap[m_uiCount].m_first = _T("muires");
  1723. m_cmap[m_uiCount].m_second[m_cmap[m_uiCount++].m_count++] = m_buf2; // argv[i++];
  1724. //i ++;
  1725. // m_mArgList.insert(make_pair("muires",argv[i]));
  1726. }; // if ( i < argc )
  1727. }; // else if (! isFile( argv [i] ) ) {
  1728. }; // for (
  1729. return TRUE;
  1730. }
  1731. LPTSTR* CMuiCmdInfo :: GetValueLists ( LPCTSTR pszKey, DWORD& dwCount )
  1732. /*++
  1733. Abstract:
  1734. Return the second (value) and its count by its key
  1735. Arguments:
  1736. pszKey - key (arguments)
  1737. [OUT] dwCount - number of values of this key(argument)
  1738. return:
  1739. pointer to array of values
  1740. --*/
  1741. {
  1742. if (pszKey == NULL)
  1743. return FALSE;
  1744. for (UINT i = 0; i < m_uiCount; i ++ ) {
  1745. if (! _tcsicmp (m_cmap[i].m_first, pszKey) ) {
  1746. dwCount = m_cmap[i].m_count;
  1747. return m_cmap[i].m_second;
  1748. }
  1749. }
  1750. dwCount = 0;
  1751. return NULL;
  1752. }
  1753. LPCTSTR CMuiCmdInfo :: getArgValue ( LPTSTR pszArg )
  1754. /*++
  1755. Abstract:
  1756. return the second pointer(value ) of first pointer(key)
  1757. Arguments:
  1758. return:
  1759. pointer to value
  1760. --*/
  1761. {
  1762. if ( pszArg == NULL)
  1763. return FALSE;
  1764. LPCTSTR lpArg = CharLower(pszArg);
  1765. LPCTSTR pszArgTemp = m_pszArgLists;
  1766. if ( _T('-') == *lpArg || _T('/') == *lpArg ) {
  1767. lpArg++;
  1768. while ( *pszArgTemp != _T('\0') ) {
  1769. if ( *lpArg == *pszArgTemp++ ) {
  1770. return lpArg;
  1771. }
  1772. }
  1773. }
  1774. #ifdef NEVER
  1775. if ( _T('i') == *++lpArg || _T('k') == *lpArg || _T('l') == *lpArg ||
  1776. _T('v') == *lpArg || _T('c') == *lpArg || _T('y') == *lpArg ) {
  1777. return lpArg;
  1778. }
  1779. #endif
  1780. // printf("%s\n", lpArg);
  1781. return NULL;
  1782. }
  1783. LPCTSTR CMuiCmdInfo::getArgString(LPTSTR pszArg)
  1784. /*++
  1785. Abstract:
  1786. check the string and return its value if it is argument that has string value
  1787. Arguments:
  1788. pszArg - speicific argument
  1789. return:
  1790. pointer to character field of argument ( -s, /s. only return s )
  1791. --*/
  1792. {
  1793. if (pszArg == NULL)
  1794. return FALSE;
  1795. LPCTSTR lpArg = CharLower(pszArg);
  1796. // if ( *lpArg == '-' || *lpArg == '/' )
  1797. // if ( *++lpArg == 's' || *lpArg == 'p' )
  1798. // return lpArg;
  1799. return NULL;
  1800. }
  1801. BOOL CMuiCmdInfo :: isFile ( LPCTSTR pszArg )
  1802. /*++
  1803. Abstract:
  1804. check if the string has file format(*.*) or not
  1805. Arguments:
  1806. pszArg : specific argument
  1807. return:
  1808. --*/
  1809. {
  1810. if(pszArg == NULL)
  1811. return FALSE;
  1812. for (int i = 0; _T('\0') != pszArg[i] ; i ++ ) {
  1813. if ( _T('.') == pszArg [i] )
  1814. return TRUE;
  1815. }
  1816. return FALSE;
  1817. }
  1818. BOOL CMuiCmdInfo :: isNumber ( LPCTSTR pszArg )
  1819. /*++
  1820. Abstract:
  1821. heck if the string has file number ( 10, 16 base )
  1822. Arguments:
  1823. pszArg : specific argument
  1824. return:
  1825. --*/
  1826. {
  1827. if (pszArg == NULL)
  1828. return FALSE;
  1829. for ( int i = 0; _T('\0') != pszArg[i]; i ++ ) {
  1830. if ( _T('0') == pszArg[0] && _T('x') == pszArg[1] )
  1831. return TRUE;
  1832. if ( pszArg[i] < '0' || pszArg[i] > '9' )
  1833. return FALSE;
  1834. }
  1835. return TRUE;
  1836. };
  1837. BOOL CMuiCmdInfo::isNeedValue( LPCTSTR pszArg )
  1838. /*++
  1839. Abstract:
  1840. check if argument should have value or can stand alone.
  1841. Arguments:
  1842. pszArg - specific argument
  1843. return:
  1844. --*/
  1845. {
  1846. if (pszArg == NULL)
  1847. return FALSE;
  1848. LPCTSTR lpArg = CharLower((LPTSTR)pszArg);
  1849. LPCTSTR pszArgTemp = m_pszArgNeedValueList;
  1850. if ( _T('-') == *lpArg || _T('/') == *lpArg )
  1851. {
  1852. lpArg++;
  1853. }
  1854. while ( *pszArgTemp != _T('\0') ) {
  1855. if ( *lpArg == *pszArgTemp++ ) {
  1856. return TRUE;
  1857. }
  1858. }
  1859. #ifdef NEVER
  1860. if ( _T('k') == *++lpArg || _T('l') == *lpArg || _T('c') == *lpArg )
  1861. return TRUE;
  1862. #endif
  1863. return FALSE;
  1864. }
  1865. BOOL CMuiCmdInfo::isAllowFileValue(LPCTSTR pszArg)
  1866. /*++
  1867. Abstract:
  1868. Check if argument allow file as its value
  1869. Arguments:
  1870. pszArg - specific argument
  1871. return:
  1872. --*/
  1873. {
  1874. if(pszArg == NULL)
  1875. return FALSE;
  1876. LPCTSTR lpArg = CharLower((LPTSTR)pszArg);
  1877. LPCTSTR pszArgTemp = m_pszArgAllowFileValue;
  1878. if ( _T('-') == *lpArg || _T('/') == *lpArg )
  1879. {
  1880. lpArg++;
  1881. }
  1882. while ( *pszArgTemp != _T('\0') ) {
  1883. if ( *lpArg == *pszArgTemp++ ) {
  1884. return TRUE;
  1885. }
  1886. }
  1887. return FALSE;
  1888. }
  1889. BOOL CMuiCmdInfo::isAllowMultiFileValues(LPCTSTR pszArg)
  1890. /*++
  1891. Abstract:
  1892. Check if the argument all multiple file names as its values
  1893. Arguments:
  1894. pszArg - specific argument
  1895. return:
  1896. --*/
  1897. {
  1898. if (pszArg == NULL)
  1899. return FALSE;
  1900. LPCTSTR lpArg = CharLower((LPTSTR)pszArg);
  1901. LPCTSTR pszArgTemp = m_pszArgAllowMultiValue;
  1902. if ( _T('-') == *lpArg || _T('/') == *lpArg )
  1903. {
  1904. lpArg++;
  1905. }
  1906. while ( *pszArgTemp != _T('\0') ) {
  1907. if ( *lpArg == *pszArgTemp++ ) {
  1908. return TRUE;
  1909. }
  1910. }
  1911. return FALSE;
  1912. }
  1913. template <class T>
  1914. CVector<T> :: CVector ( const CVector<T> &cv ) {
  1915. base = offset = new T [MAX_SIZE];
  1916. for (int i = 0; i < cv.offset - cv.base; i ++ )
  1917. base[i] = cv.base[i];
  1918. offset = &base[i];
  1919. }
  1920. template <class T>
  1921. CVector<T> & CVector<T> :: operator = (const CVector<T> & cv ) {
  1922. if ( this == &cv)
  1923. return *this;
  1924. for (int i = 0; i < cv.offset - cv.base; i ++ )
  1925. base[i] = cv.base[i];
  1926. offset = &base[i];
  1927. return *this;
  1928. }
  1929. template <class T>
  1930. BOOL CVector<T> :: Empty() {
  1931. if ( offset - base )
  1932. return FALSE;
  1933. else
  1934. return TRUE;
  1935. }
  1936. /* // The definition of member template is outside the class.
  1937. Visual C++ has a limitation in which member templates must be fully defined within the enclosing class.
  1938. See KB article Q239436 for more information about LNK2001 and member templates.
  1939. template <class T>
  1940. BOOL CVector<T> :: Find(DWORD dwValue) {
  1941. for ( UINT i = 0; i < offset - base; i ++ ) {
  1942. if ( PtrToUlong( base+i ) & 0xFFFF0000) {
  1943. if ( !( _tcstoul( base+i, NULL, 10 ) - dwValue ) )
  1944. return TRUE;
  1945. }
  1946. else {
  1947. if (! ( PtrToUlong(base+i ) - dwValue ) )
  1948. return TRUE;
  1949. }
  1950. }
  1951. return FALSE;
  1952. };
  1953. */
  1954. void CMUITree::AddTypeorName( LPCTSTR lpTypeorName )
  1955. /*++
  1956. Abstract:
  1957. This is Resource Tree creation : Resource tree has multiple tree
  1958. argument
  1959. Arguments:
  1960. lpTypeorName - LPCTSTR type or name
  1961. return:
  1962. --*/
  1963. {
  1964. if (lpTypeorName == NULL)
  1965. return ;
  1966. LPTSTR lpTempTypeorName = NULL;
  1967. CMUITree * pcmType = new CMUITree;
  1968. if (!pcmType)
  1969. return;
  1970. if ( 0xFFFF0000 & PtrToUlong(lpTypeorName) )
  1971. { // how about 64 bit ?
  1972. DWORD dwBufSize = _tcslen(lpTypeorName) + 1;
  1973. lpTempTypeorName = new TCHAR [dwBufSize ];
  1974. if (!lpTempTypeorName)
  1975. return;
  1976. // _tcscpy(lpTempTypeorName,lpTypeorName);
  1977. PTSTR * ppszDestEnd = NULL;
  1978. size_t * pbRem = NULL;
  1979. HRESULT hr;
  1980. hr = StringCchCopyEx(lpTempTypeorName, dwBufSize ,lpTypeorName, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
  1981. if ( ! SUCCEEDED(hr)){
  1982. _tprintf("Safe string copy Error\n");
  1983. delete pcmType;
  1984. delete [] lpTempTypeorName;
  1985. return ;
  1986. }
  1987. }
  1988. pcmType->m_lpTypeorName = lpTempTypeorName ? lpTempTypeorName : lpTypeorName;
  1989. if ( m_ChildFirst ) {
  1990. CMUITree * pTemp = m_ChildFirst; // tricky : we put the value of next of child, not this->m_Next;
  1991. CMUITree * pTempPre = pTemp;
  1992. while ( pTemp = pTemp->m_Next )
  1993. pTempPre = pTemp;
  1994. pTempPre ->m_Next = pTemp = pcmType;
  1995. }
  1996. else
  1997. m_ChildFirst = pcmType;
  1998. }
  1999. void CMUITree::AddLangID ( WORD wLangID )
  2000. /*++
  2001. Abstract:
  2002. This is language ID tree of resource tree, we need another one besides AddTypeorName because
  2003. we want to handle LPCTSTR and WORD separately
  2004. Arguments:
  2005. wLangID - language ID
  2006. return:
  2007. --*/
  2008. {
  2009. CMUITree * pcmType = new CMUITree;
  2010. if(!pcmType)
  2011. return;
  2012. pcmType->m_wLangID = wLangID;
  2013. if ( m_ChildFirst ) {
  2014. CMUITree * pmuTree = m_ChildFirst; // tricky : we put the value of next of child, not this->m_Next;
  2015. while ( pmuTree = pmuTree->m_Next );
  2016. pmuTree = pcmType;
  2017. }
  2018. else
  2019. m_ChildFirst = pcmType;
  2020. }
  2021. BOOL CMUITree::DeleteType ( LPCTSTR lpTypeorName )
  2022. /*++
  2023. Abstract:
  2024. This is just for deleting method of resource tree. you can delete resource type or name, but
  2025. not support language id. can be expanded by adding more arguments (lpType,lpName,lpLaguageID)
  2026. Arguments:
  2027. lpTypeorName : LPCTSTR type or name
  2028. return:
  2029. --*/
  2030. {
  2031. if (lpTypeorName == NULL)
  2032. return FALSE;
  2033. CMUITree * pcmTree = m_ChildFirst;
  2034. // delete first
  2035. // the other case : impossible of being same two value.
  2036. if (! pcmTree ) {
  2037. _tprintf("No resource type in the resource tree \n");
  2038. return FALSE;
  2039. }
  2040. if ( (0xFFFF0000 & PtrToUlong(lpTypeorName) ) && (0xFFFF0000 & PtrToUlong(pcmTree->m_lpTypeorName) ) ) {
  2041. if (! _tcsicmp(pcmTree->m_lpTypeorName, lpTypeorName ) ){
  2042. m_ChildFirst = pcmTree->m_Next;
  2043. CMUITree * pChild = pcmTree->m_ChildFirst;
  2044. CMUITree * pChildNext = NULL;
  2045. while ( pChild ) {
  2046. pChildNext = pChild->m_Next;
  2047. delete pChild;
  2048. pChild = pChildNext;
  2049. }
  2050. delete pcmTree;
  2051. return TRUE;
  2052. }
  2053. }
  2054. else if ( !(0xFFFF0000 & PtrToUlong(lpTypeorName) ) && !(0xFFFF0000 & PtrToUlong(pcmTree->m_lpTypeorName) ) ) {
  2055. if (!( PtrToUlong(pcmTree->m_lpTypeorName)- PtrToUlong(lpTypeorName ) ) ){
  2056. m_ChildFirst = pcmTree->m_Next;
  2057. CMUITree * pChild = pcmTree->m_ChildFirst;
  2058. CMUITree * pChildNext = NULL;
  2059. while ( pChild ) {
  2060. pChildNext = pChild->m_Next;
  2061. delete pChild;
  2062. pChild = pChildNext;
  2063. }
  2064. delete pcmTree;
  2065. return TRUE;
  2066. }
  2067. }
  2068. // delete middle or last
  2069. CMUITree * pcmTreePre = pcmTree;
  2070. while( pcmTree = pcmTree->m_Next ) {
  2071. if ( (0xFFFF0000 & PtrToUlong(lpTypeorName) ) && (0xFFFF0000 & PtrToUlong(pcmTree->m_lpTypeorName) ) ) {
  2072. if (! _tcsicmp(pcmTree->m_lpTypeorName,lpTypeorName ) ){
  2073. pcmTreePre->m_Next = pcmTree->m_Next;
  2074. CMUITree * pChild = pcmTree->m_ChildFirst;
  2075. CMUITree * pChildNext = NULL;
  2076. while ( pChild ) {
  2077. pChildNext = pChild->m_Next;
  2078. delete pChild;
  2079. pChild = pChildNext;
  2080. }
  2081. delete pcmTree;
  2082. return TRUE;
  2083. }
  2084. }
  2085. else if ( !(0xFFFF0000 & PtrToUlong(lpTypeorName) ) && !(0xFFFF0000 & PtrToUlong(pcmTree->m_lpTypeorName) ) ) {
  2086. if (!( PtrToUlong(pcmTree->m_lpTypeorName)- PtrToUlong(lpTypeorName ) ) ){
  2087. pcmTreePre->m_Next = pcmTree->m_Next;
  2088. CMUITree * pChild = pcmTree->m_ChildFirst;
  2089. CMUITree * pChildNext = NULL;
  2090. while ( pChild ) {
  2091. pChildNext = pChild->m_Next;
  2092. delete pChild;
  2093. pChild = pChildNext;
  2094. }
  2095. delete pcmTree;
  2096. return TRUE;
  2097. }
  2098. }
  2099. pcmTreePre = pcmTree;
  2100. } // while
  2101. return FALSE;
  2102. }
  2103. DWORD CMUITree::NumOfChild()
  2104. /*++
  2105. Abstract:
  2106. Calculate a number of child.
  2107. Arguments:
  2108. return:
  2109. --*/
  2110. {
  2111. DWORD dwCont = 0;
  2112. if (m_ChildFirst)
  2113. {
  2114. dwCont++;
  2115. CMUITree * pcMuitree = m_ChildFirst;
  2116. while (pcMuitree = pcMuitree->m_Next) {
  2117. dwCont++;
  2118. }
  2119. }
  2120. return dwCont;
  2121. };