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.

1301 lines
35 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // File: res32.cpp
  4. //
  5. // Contents: Implementation for the Resource 32 Read/Write module
  6. //
  7. // Classes: one
  8. //
  9. // History: 31-May-93 alessanm created
  10. //----------------------------------------------------------------------------
  11. #include <afxwin.h>
  12. #include "..\common\rwdll.h"
  13. #include "..\common\rw32hlpr.h"
  14. #include <limits.h>
  15. /////////////////////////////////////////////////////////////////////////////
  16. // Initialization of MFC Extension DLL
  17. static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };
  18. /////////////////////////////////////////////////////////////////////////////
  19. // General Declarations
  20. #define RWTAG "RES32"
  21. /////////////////////////////////////////////////////////////////////////////
  22. // Function Declarations
  23. static UINT GetResInfo(
  24. CFile*,
  25. WORD* wTypeId, LPSTR lplpszTypeId, BYTE bMaxTypeLen,
  26. WORD* wNameId, LPSTR lplpszNameId, BYTE bMaxNameLen,
  27. DWORD* pdwDataVersion,
  28. WORD* pwFlags, WORD* pwLang,
  29. DWORD* pdwVersion, DWORD* pdwCharact,
  30. DWORD* dwSize, DWORD* dwFileOffset, DWORD );
  31. static UINT WriteHeader(
  32. CFile* pFile,
  33. DWORD dwSize,
  34. WORD wTypeId, LPSTR lpszwTypeId,
  35. WORD wNameId, LPSTR lpszwNameId,
  36. DWORD dwDataVersion,
  37. WORD wFlags, WORD wLang,
  38. DWORD dwVersion, DWORD dwCharact );
  39. static UINT WriteImage(
  40. CFile*,
  41. LPVOID lpImage, DWORD dwSize );
  42. static UINT GetUpdatedRes(
  43. LPVOID far * lplpBuffer,
  44. LONG* lSize,
  45. WORD* wTypeId, LPSTR lplpszTypeId,
  46. WORD* wNameId, LPSTR lplpszNameId,
  47. DWORD* dwlang, DWORD* dwSize );
  48. static UINT GenerateFile(
  49. LPCSTR lpszTgtFilename,
  50. HANDLE hResFileModule,
  51. LPVOID lpBuffer,
  52. UINT uiSize,
  53. HINSTANCE hDllInst );
  54. static UINT GetNameOrOrdFile( CFile* pfile, WORD* pwId, LPSTR lpszId, BYTE bMaxStrLen );
  55. /////////////////////////////////////////////////////////////////////////////
  56. // Public C interface implementation
  57. //[registration]
  58. extern "C"
  59. BOOL FAR PASCAL RWGetTypeString(LPSTR lpszTypeName)
  60. {
  61. strcpy( lpszTypeName, RWTAG );
  62. return FALSE;
  63. }
  64. extern "C"
  65. BOOL FAR PASCAL RWValidateFileType (LPCSTR lpszFilename)
  66. {
  67. UINT uiError = ERROR_NO_ERROR;
  68. CFile file;
  69. // Open the file and try to read the information on the resource in it.
  70. if (!file.Open(lpszFilename, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone))
  71. return FALSE;
  72. WORD wTypeId;
  73. static char szTypeId[128];
  74. WORD wNameId;
  75. static char szNameId[128];
  76. WORD wDummy;
  77. DWORD dwDummy;
  78. WORD wLang;
  79. DWORD dwSize;
  80. DWORD dwFileOffset;
  81. DWORD filelen = file.GetLength();
  82. // File begins with a null resource entry. Check for signature.
  83. { DWORD datasize, headsize;
  84. // Filelen to at least 32 bytes, the size of a resource entry with
  85. // datasize = 0... Note: A file consisting of just a null header is accepted.
  86. if (filelen < 32) {
  87. file.Close();
  88. return FALSE;
  89. }
  90. // datasize to be 0 (although >0 everywhere else)
  91. file.Read(&datasize, 4);
  92. if (datasize != 0) {
  93. file.Close();
  94. return FALSE;
  95. }
  96. // headsize to be 32 (although >=32 everywhere else)
  97. file.Read(&headsize, 4);
  98. if (headsize != 32) {
  99. file.Close();
  100. return FALSE;
  101. }
  102. // Other tests possible here
  103. // Skip to end of first (null) resource entry
  104. file.Seek(headsize, CFile::begin);
  105. }
  106. // See that rest of file contains recognizable resource entries
  107. while(filelen - file.GetPosition()>0) {
  108. if (!GetResInfo( &file,
  109. &wTypeId, &szTypeId[0], 128,
  110. &wNameId, &szNameId[0], 128,
  111. &dwDummy,
  112. &wDummy, &wLang,
  113. &dwDummy, &dwDummy,
  114. &dwSize, &dwFileOffset, filelen) ) {
  115. // This is not a valid resource file
  116. file.Close();
  117. return FALSE;
  118. }
  119. }
  120. file.Close();
  121. return TRUE;
  122. }
  123. extern "C"
  124. UINT
  125. APIENTRY
  126. RWReadTypeInfo(
  127. LPCSTR lpszFilename,
  128. LPVOID lpBuffer,
  129. UINT* puiSize
  130. )
  131. {
  132. UINT uiError = ERROR_NO_ERROR;
  133. BYTE far * lpBuf = (BYTE far *)lpBuffer;
  134. LONG lBufSize = (LONG)*puiSize;
  135. // we can consider the use of a CMemFile so we get the same speed as memory access.
  136. CFile file;
  137. if (!RWValidateFileType(lpszFilename))
  138. return ERROR_RW_INVALID_FILE;
  139. // Make sure we are using the right code page and global settings
  140. // Get the pointer to the function
  141. HINSTANCE hDllInst = LoadLibrary("iodll.dll");
  142. if (hDllInst)
  143. {
  144. UINT (FAR PASCAL * lpfnGetSettings)(LPSETTINGS);
  145. // Get the pointer to the function to get the settings
  146. lpfnGetSettings = (UINT (FAR PASCAL *)(LPSETTINGS))
  147. GetProcAddress( hDllInst, "RSGetGlobals" );
  148. if (lpfnGetSettings!=NULL) {
  149. SETTINGS settings;
  150. (*lpfnGetSettings)(&settings);
  151. g_cp = settings.cp;
  152. g_bAppend = settings.bAppend;
  153. g_bUpdOtherResLang = settings.bUpdOtherResLang;
  154. strcpy( g_char, settings.szDefChar );
  155. }
  156. FreeLibrary(hDllInst);
  157. }
  158. // Open the file and try to read the information on the resource in it.
  159. if (!file.Open(lpszFilename, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone))
  160. return ERROR_FILE_OPEN;
  161. // we try to read as much information as we can
  162. // Because this is a res file we can read all the information we need.
  163. WORD wTypeId;
  164. static char szTypeId[128];
  165. WORD wNameId;
  166. static char szNameId[128];
  167. WORD wDummy;
  168. DWORD dwDummy;
  169. WORD wLang;
  170. DWORD dwSize;
  171. DWORD dwFileOffset;
  172. UINT uiOverAllSize = 0;
  173. // The first resource should be: Null. Skipp it
  174. file.Seek( 32, CFile::begin);
  175. DWORD filelen = file.GetLength();
  176. while(filelen-file.GetPosition()>0) {
  177. GetResInfo( &file,
  178. &wTypeId, &szTypeId[0], 128,
  179. &wNameId, &szNameId[0], 128,
  180. &dwDummy,
  181. &wDummy, &wLang,
  182. &dwDummy, &dwDummy,
  183. &dwSize, &dwFileOffset, filelen);
  184. uiOverAllSize += PutWord( &lpBuf, wTypeId, &lBufSize );
  185. uiOverAllSize += PutStringA( &lpBuf, szTypeId, &lBufSize );
  186. // Check if it is alligned
  187. uiOverAllSize += Allign( &lpBuf, &lBufSize , (LONG)uiOverAllSize);
  188. uiOverAllSize += PutWord( &lpBuf, wNameId, &lBufSize );
  189. uiOverAllSize += PutStringA( &lpBuf, szNameId, &lBufSize );
  190. // Check if it is alligned
  191. uiOverAllSize += Allign( &lpBuf, &lBufSize, (LONG)uiOverAllSize);
  192. uiOverAllSize += PutDWord( &lpBuf, (DWORD)wLang, &lBufSize );
  193. uiOverAllSize += PutDWord( &lpBuf, dwSize, &lBufSize );
  194. uiOverAllSize += PutDWord( &lpBuf, dwFileOffset, &lBufSize );
  195. }
  196. file.Close();
  197. *puiSize = uiOverAllSize;
  198. return uiError;
  199. }
  200. extern "C"
  201. DWORD
  202. APIENTRY
  203. RWGetImage(
  204. LPCSTR lpszFilename,
  205. DWORD dwImageOffset,
  206. LPVOID lpBuffer,
  207. DWORD dwSize
  208. )
  209. {
  210. UINT uiError = ERROR_NO_ERROR;
  211. BYTE far * lpBuf = (BYTE far *)lpBuffer;
  212. DWORD dwBufSize = dwSize;
  213. // we can consider the use of a CMemFile so we get the same speed as memory access.
  214. CFile file;
  215. // Open the file and try to read the information on the resource in it.
  216. if (!file.Open(lpszFilename, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone))
  217. return (DWORD)ERROR_FILE_OPEN;
  218. if ( dwImageOffset!=(DWORD)file.Seek( dwImageOffset, CFile::begin) )
  219. return (DWORD)ERROR_FILE_INVALID_OFFSET;
  220. if (dwSize>UINT_MAX) {
  221. // we have to read the image in different steps
  222. return (DWORD)0L;
  223. } else uiError = file.Read( lpBuf, (UINT)dwSize);
  224. file.Close();
  225. return (DWORD)uiError;
  226. }
  227. extern "C"
  228. UINT
  229. APIENTRY
  230. RWParseImage(
  231. LPCSTR lpszType,
  232. LPVOID lpImageBuf,
  233. DWORD dwImageSize,
  234. LPVOID lpBuffer,
  235. DWORD dwSize
  236. )
  237. {
  238. UINT uiError = ERROR_NO_ERROR;
  239. BYTE far * lpBuf = (BYTE far *)lpBuffer;
  240. DWORD dwBufSize = dwSize;
  241. // The Type we can parse are only the standard ones
  242. // This function should fill the lpBuffer with an array of ResItem structure
  243. switch ((UINT)LOWORD(lpszType)) {\
  244. /*
  245. case 1:
  246. uiError = ParseEmbeddedFile( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  247. break;
  248. case 3:
  249. uiError = ParseEmbeddedFile( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  250. break;
  251. */
  252. case 4:
  253. uiError = ParseMenu( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  254. break;
  255. case 5:
  256. uiError = ParseDialog( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  257. break;
  258. case 6:
  259. uiError = ParseString( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  260. break;
  261. case 9:
  262. uiError = ParseAccel( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  263. break;
  264. case 11:
  265. uiError = ParseMsgTbl( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  266. break;
  267. case 16:
  268. uiError = ParseVerst( lpImageBuf, dwImageSize, lpBuffer, dwSize );
  269. break;
  270. default:
  271. break;
  272. }
  273. return uiError;
  274. }
  275. extern"C"
  276. UINT
  277. APIENTRY
  278. RWWriteFile(
  279. LPCSTR lpszSrcFilename,
  280. LPCSTR lpszTgtFilename,
  281. HANDLE hResFileModule,
  282. LPVOID lpBuffer,
  283. UINT uiSize,
  284. HINSTANCE hDllInst,
  285. LPCSTR lpszSymbolPath
  286. )
  287. {
  288. UINT uiError = ERROR_NO_ERROR;
  289. BYTE far * lpBuf = LPNULL;
  290. UINT uiBufSize = uiSize;
  291. // we can consider the use of a CMemFile so we get the same speed as memory access.
  292. CFile fileIn;
  293. CFile fileOut;
  294. BOOL bfileIn = TRUE;
  295. // Open the file and try to read the information on the resource in it.
  296. CFileStatus status;
  297. if (CFile::GetStatus( lpszSrcFilename, status )) {
  298. // check if the size of the file is not null
  299. if (!status.m_size)
  300. CFile::Remove(lpszSrcFilename);
  301. }
  302. // Get the handle to the IODLL
  303. hDllInst = LoadLibrary("iodll.dll");
  304. // Get the pointer to the function
  305. if (!hDllInst)
  306. return ERROR_DLL_LOAD;
  307. if (!fileIn.Open(lpszSrcFilename, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) {
  308. uiError = GenerateFile(lpszTgtFilename,
  309. hResFileModule,
  310. lpBuffer,
  311. uiSize,
  312. hDllInst
  313. );
  314. FreeLibrary(hDllInst);
  315. return uiError;
  316. }
  317. if (!fileOut.Open(lpszTgtFilename, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary))
  318. return ERROR_FILE_CREATE;
  319. DWORD (FAR PASCAL * lpfnGetImage)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD);
  320. // Get the pointer to the function to extract the resources image
  321. lpfnGetImage = (DWORD (FAR PASCAL *)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD))
  322. GetProcAddress( hDllInst, "RSGetResImage" );
  323. if (lpfnGetImage==NULL) {
  324. FreeLibrary(hDllInst);
  325. return ERROR_DLL_PROC_ADDRESS;
  326. }
  327. // We read the resources from the file and then we check if the resource has been updated
  328. // or if we can just copy it
  329. WORD wTypeId;
  330. char szTypeId[128];
  331. WORD wNameId;
  332. char szNameId[128];
  333. WORD wFlags;
  334. WORD wLang;
  335. DWORD dwDataVersion;
  336. DWORD dwVersion;
  337. DWORD dwCharact;
  338. DWORD dwSize;
  339. DWORD dwFileOffset;
  340. WORD wUpdTypeId = 0;
  341. static char szUpdTypeId[128];
  342. WORD wUpdNameId;
  343. static char szUpdNameId[128];
  344. DWORD dwUpdLang;
  345. DWORD dwUpdSize;
  346. UINT uiBufStartSize = uiBufSize;
  347. DWORD dwImageBufSize;
  348. BYTE far * lpImageBuf;
  349. DWORD filelen = fileIn.GetLength();
  350. DWORD dwHeadSize = 0l;
  351. static BYTE buf[32];
  352. DWORD pad = 0l;
  353. // The first resource should be: Null. Skipp it
  354. fileIn.Read( &buf, 32 );
  355. fileOut.Write( &buf, 32 );
  356. while(filelen-fileIn.GetPosition()>0) {
  357. GetResInfo( &fileIn,
  358. &wTypeId, &szTypeId[0], 128,
  359. &wNameId, &szNameId[0], 128,
  360. &dwDataVersion,
  361. &wFlags, &wLang,
  362. &dwVersion, &dwCharact,
  363. &dwSize, &dwFileOffset, filelen
  364. );
  365. if ((!wUpdTypeId) && (uiBufSize))
  366. GetUpdatedRes( &lpBuffer,
  367. (LONG*)&uiBufSize,
  368. &wUpdTypeId, &szUpdTypeId[0],
  369. &wUpdNameId, &szUpdNameId[0],
  370. &dwUpdLang,
  371. &dwUpdSize
  372. );
  373. if ( (wUpdTypeId==wTypeId) &&
  374. ( (CString)szUpdTypeId==(CString)szTypeId) &&
  375. (wUpdNameId==wNameId) &&
  376. ( (CString)szUpdNameId==(CString)szNameId)
  377. ) {
  378. // The resource has been updated get the image from the IODLL
  379. lpImageBuf = new BYTE[dwUpdSize];
  380. LPSTR lpType = LPNULL;
  381. LPSTR lpRes = LPNULL;
  382. if (wUpdTypeId) {
  383. lpType = (LPSTR)((WORD)wUpdTypeId);
  384. } else {
  385. lpType = &szUpdTypeId[0];
  386. }
  387. if (wUpdNameId) {
  388. lpRes = (LPSTR)((WORD)wUpdNameId);
  389. } else {
  390. lpRes = &szUpdNameId[0];
  391. }
  392. dwImageBufSize = (*lpfnGetImage)( hResFileModule,
  393. lpType,
  394. lpRes,
  395. dwUpdLang,
  396. lpImageBuf,
  397. dwUpdSize
  398. );
  399. if (dwImageBufSize>dwUpdSize ) {
  400. // The buffer is too small
  401. delete []lpImageBuf;
  402. lpImageBuf = new BYTE[dwImageBufSize];
  403. dwUpdSize = (*lpfnGetImage)( hResFileModule,
  404. lpType,
  405. lpRes,
  406. dwUpdLang,
  407. lpImageBuf,
  408. dwImageBufSize
  409. );
  410. if ((dwUpdSize-dwImageBufSize)!=0 ) {
  411. delete []lpImageBuf;
  412. lpImageBuf = LPNULL;
  413. }
  414. }
  415. wUpdTypeId = 0;
  416. } else {
  417. // The fileIn is now correctly positioned at next resource. Save posit.
  418. DWORD dwNextResFilePos = fileIn.GetPosition();
  419. // The resource hasn't been updated copy the image from the file
  420. if(!dwSize) {
  421. FreeLibrary(hDllInst);
  422. return ERROR_NEW_FAILED;
  423. }
  424. lpImageBuf = new BYTE[dwSize];
  425. if(!lpImageBuf) {
  426. FreeLibrary(hDllInst);
  427. return ERROR_NEW_FAILED;
  428. }
  429. if ( dwFileOffset!=(DWORD)fileIn.Seek( dwFileOffset, CFile::begin) ) {
  430. delete []lpImageBuf;
  431. FreeLibrary(hDllInst);
  432. return (DWORD)ERROR_FILE_INVALID_OFFSET;
  433. }
  434. if (dwSize>UINT_MAX) {
  435. // we have to read the image in different steps
  436. delete []lpImageBuf;
  437. FreeLibrary(hDllInst);
  438. return (DWORD)ERROR_RW_IMAGE_TOO_BIG;
  439. } else fileIn.Read( lpImageBuf, (UINT)dwSize);
  440. dwImageBufSize = dwSize;
  441. // This moves us past any pad bytes, to start of next resource.
  442. fileIn.Seek(dwNextResFilePos, CFile::begin);
  443. }
  444. dwHeadSize = WriteHeader(&fileOut,
  445. dwImageBufSize,
  446. wTypeId, &szTypeId[0],
  447. wNameId, &szNameId[0],
  448. dwDataVersion,
  449. wFlags, wLang,
  450. dwVersion, dwCharact );
  451. WriteImage( &fileOut,
  452. lpImageBuf, dwImageBufSize);
  453. BYTE bPad = (BYTE)Pad4((DWORD)dwHeadSize+dwImageBufSize);
  454. if(bPad)
  455. fileOut.Write( &pad, bPad );
  456. if (lpImageBuf) delete []lpImageBuf;
  457. }
  458. fileIn.Close();
  459. fileOut.Close();
  460. FreeLibrary(hDllInst);
  461. return uiError;
  462. }
  463. extern "C"
  464. UINT
  465. APIENTRY
  466. RWUpdateImage(
  467. LPCSTR lpszType,
  468. LPVOID lpNewBuf,
  469. DWORD dwNewSize,
  470. LPVOID lpOldImage,
  471. DWORD dwOldImageSize,
  472. LPVOID lpNewImage,
  473. DWORD* pdwNewImageSize
  474. )
  475. {
  476. UINT uiError = ERROR_NO_ERROR;
  477. // The Type we can parse are only the standard ones
  478. switch ((UINT)LOWORD(lpszType)) {
  479. case 4:
  480. if (lpOldImage)
  481. uiError = UpdateMenu( lpNewBuf, dwNewSize,
  482. lpOldImage, dwOldImageSize,
  483. lpNewImage, pdwNewImageSize );
  484. else uiError = GenerateMenu( lpNewBuf, dwNewSize,
  485. lpNewImage, pdwNewImageSize );
  486. break;
  487. case 5:
  488. if (lpOldImage)
  489. uiError = UpdateDialog( lpNewBuf, dwNewSize,
  490. lpOldImage, dwOldImageSize,
  491. lpNewImage, pdwNewImageSize );
  492. else uiError = GenerateDialog( lpNewBuf, dwNewSize,
  493. lpNewImage, pdwNewImageSize );
  494. break;
  495. case 6:
  496. if (lpOldImage)
  497. uiError = UpdateString( lpNewBuf, dwNewSize,
  498. lpOldImage, dwOldImageSize,
  499. lpNewImage, pdwNewImageSize );
  500. else uiError = GenerateString( lpNewBuf, dwNewSize,
  501. lpNewImage, pdwNewImageSize );
  502. break;
  503. case 9:
  504. if (lpOldImage)
  505. uiError = UpdateAccel( lpNewBuf, dwNewSize,
  506. lpOldImage, dwOldImageSize,
  507. lpNewImage, pdwNewImageSize );
  508. break;
  509. case 11:
  510. if (lpOldImage)
  511. uiError = UpdateMsgTbl( lpNewBuf, dwNewSize,
  512. lpOldImage, dwOldImageSize,
  513. lpNewImage, pdwNewImageSize );
  514. break;
  515. case 16:
  516. if (lpOldImage)
  517. uiError = UpdateVerst( lpNewBuf, dwNewSize,
  518. lpOldImage, dwOldImageSize,
  519. lpNewImage, pdwNewImageSize );
  520. break;
  521. default:
  522. *pdwNewImageSize = 0L;
  523. uiError = ERROR_RW_NOTREADY;
  524. break;
  525. }
  526. return uiError;
  527. }
  528. ///////////////////////////////////////////////////////////////////////////
  529. // Functions implementation
  530. static UINT GenerateFile( LPCSTR lpszTgtFilename,
  531. HANDLE hResFileModule,
  532. LPVOID lpBuffer,
  533. UINT uiSize,
  534. HINSTANCE hDllInst
  535. )
  536. {
  537. UINT uiError = ERROR_NO_ERROR;
  538. BYTE far * lpBuf = LPNULL;
  539. UINT uiBufSize = uiSize;
  540. // we can consider the use of a CMemFile so we get the same speed as memory access.
  541. CFile fileOut;
  542. if (!fileOut.Open(lpszTgtFilename, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary))
  543. return ERROR_FILE_CREATE;
  544. // Get the pointer to the function
  545. if (!hDllInst)
  546. return ERROR_DLL_LOAD;
  547. DWORD (FAR PASCAL * lpfnGetImage)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD);
  548. // Get the pointer to the function to extract the resources image
  549. lpfnGetImage = (DWORD (FAR PASCAL *)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD))
  550. GetProcAddress( hDllInst, "RSGetResImage" );
  551. if (lpfnGetImage==NULL) {
  552. return ERROR_DLL_PROC_ADDRESS;
  553. }
  554. WORD wUpdTypeId = 0;
  555. static char szUpdTypeId[128];
  556. WORD wUpdNameId;
  557. static char szUpdNameId[128];
  558. DWORD dwUpdLang;
  559. DWORD dwUpdSize;
  560. UINT uiBufStartSize = uiBufSize;
  561. DWORD dwImageBufSize;
  562. BYTE far * lpImageBuf;
  563. // First write the NULL resource to make it different from res16
  564. static BYTE bNullHeader[32] = {0,0,0,0,0x20,0,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  565. fileOut.Write(bNullHeader, 32);
  566. while(uiBufSize>0) {
  567. if ((!wUpdTypeId) && (uiBufSize))
  568. GetUpdatedRes( &lpBuffer,
  569. (LONG*)&uiBufSize,
  570. &wUpdTypeId, &szUpdTypeId[0],
  571. &wUpdNameId, &szUpdNameId[0],
  572. &dwUpdLang,
  573. &dwUpdSize
  574. );
  575. // The resource has been updated get the image from the IODLL
  576. if (dwUpdSize){
  577. lpImageBuf = new BYTE[dwUpdSize];
  578. LPSTR lpType = LPNULL;
  579. LPSTR lpRes = LPNULL;
  580. if (wUpdTypeId) {
  581. lpType = (LPSTR)((WORD)wUpdTypeId);
  582. } else {
  583. lpType = &szUpdTypeId[0];
  584. }
  585. if (wUpdNameId) {
  586. lpRes = (LPSTR)((WORD)wUpdNameId);
  587. } else {
  588. lpRes = &szUpdNameId[0];
  589. }
  590. dwImageBufSize = (*lpfnGetImage)( hResFileModule,
  591. lpType,
  592. lpRes,
  593. dwUpdLang,
  594. lpImageBuf,
  595. dwUpdSize
  596. );
  597. if (dwImageBufSize>dwUpdSize ) {
  598. // The buffer is too small
  599. delete []lpImageBuf;
  600. lpImageBuf = new BYTE[dwImageBufSize];
  601. dwUpdSize = (*lpfnGetImage)( hResFileModule,
  602. lpType,
  603. lpRes,
  604. dwUpdLang,
  605. lpImageBuf,
  606. dwImageBufSize
  607. );
  608. if ((dwUpdSize-dwImageBufSize)!=0 ) {
  609. delete []lpImageBuf;
  610. lpImageBuf = LPNULL;
  611. }
  612. }
  613. WriteHeader(&fileOut,
  614. dwImageBufSize,
  615. wUpdTypeId, &szUpdTypeId[0],
  616. wUpdNameId, &szUpdNameId[0],
  617. 0l, 0, 0, 0l, 0l );
  618. WriteImage( &fileOut,
  619. lpImageBuf, dwImageBufSize);
  620. if (lpImageBuf) delete []lpImageBuf;
  621. wUpdTypeId = 0;
  622. } else wUpdTypeId = 0;
  623. }
  624. fileOut.Close();
  625. return uiError;
  626. }
  627. static UINT GetUpdatedRes(
  628. LPVOID far * lplpBuffer,
  629. LONG* lSize,
  630. WORD* wTypeId, LPSTR lpszTypeId,
  631. WORD* wNameId, LPSTR lpszNameId,
  632. DWORD* dwLang, DWORD* dwSize )
  633. {
  634. BYTE** lplpBuf = (BYTE**)lplpBuffer;
  635. UINT uiSize = GetWord( lplpBuf, wTypeId, lSize );
  636. uiSize += GetStringA( lplpBuf, lpszTypeId, lSize );
  637. uiSize += Allign( lplpBuf, lSize, (LONG)uiSize);
  638. uiSize += GetWord( lplpBuf, wNameId, lSize );
  639. uiSize += GetStringA( lplpBuf, lpszNameId, lSize );
  640. uiSize += Allign( lplpBuf, lSize, (LONG)uiSize);
  641. uiSize += GetDWord( lplpBuf, dwLang, lSize );
  642. uiSize += GetDWord( lplpBuf, dwSize, lSize );
  643. return uiSize;
  644. }
  645. static UINT
  646. GetResInfo( CFile* pfile,
  647. WORD* pwTypeId, LPSTR lpszTypeId, BYTE bMaxTypeLen,
  648. WORD* pwNameId, LPSTR lpszNameId, BYTE bMaxNameLen,
  649. DWORD* pdwDataVersion,
  650. WORD* pwFlags, WORD* pwLang,
  651. DWORD* pdwVersion, DWORD* pdwCharact,
  652. DWORD* pdwSize, DWORD* pdwFileOffset,
  653. DWORD dwFileSize )
  654. {
  655. static UINT uiSize;
  656. static LONG lOfsCheck;
  657. static DWORD dwSkip;
  658. static DWORD dwHeadSize;
  659. //Get the data size
  660. pfile->Read( pdwSize, 4 );
  661. if (*pdwSize==0)
  662. // size id 0 the resource file is corrupted or is not a res file
  663. return FALSE;
  664. //Get the Header size
  665. pfile->Read( &dwHeadSize, 4 );
  666. if (dwHeadSize<32)
  667. // should never be smaller than 32
  668. return FALSE;
  669. // get the Type info
  670. uiSize = GetNameOrOrdFile( pfile, pwTypeId, lpszTypeId, bMaxTypeLen);
  671. if (!uiSize)
  672. return FALSE;
  673. // get the Name info
  674. uiSize = GetNameOrOrdFile( pfile, pwNameId, lpszNameId, bMaxNameLen);
  675. if (!uiSize)
  676. return FALSE;
  677. // Skip the Data Version
  678. pfile->Read( pdwDataVersion, 4 );
  679. // Get the Flags
  680. pfile->Read( pwFlags, 2 );
  681. // Get the language ID
  682. pfile->Read( pwLang, 2 );
  683. // Skip the version and the characteristics
  684. pfile->Read( pdwVersion, 4 );
  685. pfile->Read( pdwCharact, 4 );
  686. *pdwFileOffset = pfile->GetPosition();
  687. // calculate if padding nedeed
  688. BYTE bPad = (BYTE)Pad4((DWORD)((*pdwSize)+dwHeadSize));
  689. if(bPad)
  690. pfile->Seek( bPad, CFile::current );
  691. if (*pdwFileOffset>dwFileSize)
  692. return FALSE;
  693. // check if the size is valid
  694. TRY {
  695. lOfsCheck = pfile->Seek(*pdwSize, CFile::current);
  696. } CATCH(CFileException, e) {
  697. // Check is the right exception
  698. return FALSE;
  699. } END_CATCH
  700. if (lOfsCheck!=(LONG)(*pdwFileOffset+*pdwSize+bPad))
  701. return FALSE;
  702. return TRUE;
  703. }
  704. static UINT WriteHeader(
  705. CFile* pFile,
  706. DWORD dwSize,
  707. WORD wTypeId, LPSTR lpszTypeId,
  708. WORD wNameId, LPSTR lpszNameId,
  709. DWORD dwDataVersion,
  710. WORD wFlags, WORD wLang,
  711. DWORD dwVersion, DWORD dwCharact )
  712. {
  713. UINT uiError = ERROR_NO_ERROR;
  714. static WCHAR szwName[128];
  715. static WORD wFF = 0xFFFF;
  716. DWORD dwHeadSize = 0l;
  717. static DWORD Pad = 0L;
  718. DWORD dwOffset = pFile->GetPosition();
  719. pFile->Write( &dwSize, 4 );
  720. // we will have to fix up laxter the size of the resource
  721. pFile->Write( &dwHeadSize, 4 );
  722. if(wTypeId) {
  723. // It is an ordinal
  724. pFile->Write( &wFF, 2 );
  725. pFile->Write( &wTypeId, 2 );
  726. dwHeadSize += 4;
  727. } else {
  728. WORD wLen = (WORD)((_MBSTOWCS( szwName, lpszTypeId, strlen(lpszTypeId)+1))*sizeof(WORD));
  729. pFile->Write( szwName, wLen );
  730. BYTE bPad = (BYTE)Pad4(wLen);
  731. if(bPad)
  732. pFile->Write( &Pad, bPad );
  733. dwHeadSize += wLen+bPad;
  734. }
  735. if(wNameId) {
  736. // It is an ordinal
  737. pFile->Write( &wFF, 2 );
  738. pFile->Write( &wNameId, 2 );
  739. dwHeadSize += 4;
  740. } else {
  741. WORD wLen = (WORD)((_MBSTOWCS( szwName, lpszNameId, strlen(lpszNameId)+1))*sizeof(WORD));
  742. pFile->Write( szwName, wLen );
  743. BYTE bPad = (BYTE)Pad4(wLen);
  744. if(bPad)
  745. pFile->Write( &Pad, bPad );
  746. dwHeadSize += wLen+bPad;
  747. }
  748. pFile->Write( &dwDataVersion, 4 );
  749. pFile->Write( &wFlags, 2 );
  750. pFile->Write( &wLang, 2 );
  751. pFile->Write( &dwVersion, 4 );
  752. pFile->Write( &dwCharact, 4 );
  753. dwHeadSize += 24;
  754. // write the size of the resource
  755. pFile->Seek( dwOffset+4, CFile::begin );
  756. pFile->Write( &dwHeadSize, 4 );
  757. pFile->Seek( dwOffset+dwHeadSize, CFile::begin );
  758. return (UINT)dwHeadSize;
  759. }
  760. static DWORD dwZeroPad = 0x00000000;
  761. static UINT WriteImage(
  762. CFile* pFile,
  763. LPVOID lpImage, DWORD dwSize )
  764. {
  765. UINT uiError = ERROR_NO_ERROR;
  766. if(lpImage)
  767. {
  768. pFile->Write( lpImage, (UINT)dwSize );
  769. // check if we need to have the image alligned
  770. if(Pad4(dwSize))
  771. pFile->Write( &dwZeroPad, Pad4(dwSize) );
  772. }
  773. return uiError;
  774. }
  775. static UINT GetNameOrOrdFile( CFile* pfile, WORD* pwId, LPSTR lpszId, BYTE bMaxStrLen )
  776. {
  777. UINT uiSize = 0;
  778. *pwId = 0;
  779. // read the first WORD to see if it is a string or an ordinal
  780. pfile->Read( pwId, sizeof(WORD) );
  781. if(*pwId==0xFFFF) {
  782. // This is an Ordinal
  783. pfile->Read( pwId, sizeof(WORD) );
  784. *lpszId = '\0';
  785. uiSize = 2;
  786. } else {
  787. uiSize++;
  788. _WCSTOMBS( lpszId, (PWSTR)pwId, 3);
  789. while((*lpszId++) && (bMaxStrLen-2)) {
  790. pfile->Read( pwId, sizeof(WORD) );
  791. _WCSTOMBS( lpszId, (PWSTR)pwId, 3);
  792. uiSize++;
  793. bMaxStrLen--;
  794. }
  795. if ( (!(bMaxStrLen-2)) && (*pwId) ) {
  796. // Failed
  797. return 0;
  798. }
  799. // Check padding
  800. BYTE bPad = Pad4((UINT)(uiSize*sizeof(WORD)));
  801. if(bPad)
  802. pfile->Read( pwId, sizeof(WORD) );
  803. }
  804. return uiSize;
  805. }
  806. ////////////////////////////////////////////////////////////////////////////////
  807. // Helper
  808. ////////////////////////////////////////////////////////////////////////////////
  809. static char szCaption[MAXSTR];
  810. static UINT GenerateMenu( LPVOID lpNewBuf, LONG dwNewSize,
  811. LPVOID lpNewI, DWORD* pdwNewImageSize )
  812. {
  813. UINT uiError = ERROR_NO_ERROR;
  814. BYTE far * lpNewImage = (BYTE far *) lpNewI;
  815. LONG dwNewImageSize = *pdwNewImageSize;
  816. BYTE far * lpBuf = (BYTE far *) lpNewBuf;
  817. LPRESITEM lpResItem = LPNULL;
  818. // We have to read the information from the lpNewBuf
  819. // Updated items
  820. WORD wUpdPos = 0;
  821. WORD fUpdItemFlags;
  822. WORD wUpdMenuId;
  823. char szUpdTxt[256];
  824. LONG dwOverAllSize = 0l;
  825. // invent the menu flags
  826. dwOverAllSize += PutDWord( &lpNewImage, 0L, &dwNewImageSize);
  827. while(dwNewSize>0) {
  828. if (dwNewSize ) {
  829. lpResItem = (LPRESITEM) lpBuf;
  830. wUpdMenuId = LOWORD(lpResItem->dwItemID);
  831. fUpdItemFlags = (WORD)lpResItem->dwFlags;
  832. strcpy( szUpdTxt, lpResItem->lpszCaption );
  833. lpBuf += lpResItem->dwSize;
  834. dwNewSize -= lpResItem->dwSize;
  835. }
  836. dwOverAllSize += PutWord( &lpNewImage, fUpdItemFlags, &dwNewImageSize);
  837. if ( !(fUpdItemFlags & MF_POPUP) )
  838. dwOverAllSize += PutWord( &lpNewImage, wUpdMenuId, &dwNewImageSize);
  839. // Write the text
  840. // check if it is a separator
  841. if ( !(fUpdItemFlags) && !(wUpdMenuId) )
  842. szUpdTxt[0] = 0x00;
  843. dwOverAllSize += PutStringW( &lpNewImage, &szUpdTxt[0], &dwNewImageSize);
  844. }
  845. if (dwOverAllSize>(LONG)*pdwNewImageSize) {
  846. // calc the padding as well
  847. dwOverAllSize += (BYTE)Pad16((DWORD)(dwOverAllSize));
  848. *pdwNewImageSize = dwOverAllSize;
  849. return uiError;
  850. }
  851. *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;
  852. if(*pdwNewImageSize>0) {
  853. // calculate padding
  854. BYTE bPad = (BYTE)Pad16((DWORD)(*pdwNewImageSize));
  855. if (bPad>dwNewImageSize) {
  856. *pdwNewImageSize += bPad;
  857. return uiError;
  858. }
  859. memset(lpNewImage, 0x00, bPad);
  860. *pdwNewImageSize += bPad;
  861. }
  862. return uiError;
  863. }
  864. static
  865. UINT
  866. GenerateString( LPVOID lpNewBuf, LONG dwNewSize,
  867. LPVOID lpNewI, DWORD* pdwNewImageSize )
  868. {
  869. UINT uiError = ERROR_NO_ERROR;
  870. LONG dwNewImageSize = *pdwNewImageSize;
  871. BYTE far * lpNewImage = (BYTE far *) lpNewI;
  872. BYTE far * lpBuf = (BYTE far *) lpNewBuf;
  873. LPRESITEM lpResItem = LPNULL;
  874. // We have to read the information from the lpNewBuf
  875. WORD wLen;
  876. WORD wPos = 0;
  877. LONG dwOverAllSize = 0l;
  878. while(dwNewSize>0) {
  879. if ( dwNewSize ) {
  880. lpResItem = (LPRESITEM) lpBuf;
  881. strcpy( szCaption, lpResItem->lpszCaption );
  882. lpBuf += lpResItem->dwSize;
  883. dwNewSize -= lpResItem->dwSize;
  884. }
  885. wLen = strlen(szCaption);
  886. // Write the text
  887. dwOverAllSize += PutPascalStringW( &lpNewImage, &szCaption[0], wLen, &dwNewImageSize );
  888. }
  889. if (dwOverAllSize>(LONG)*pdwNewImageSize) {
  890. // calc the padding as well
  891. dwOverAllSize += (BYTE)Pad16((DWORD)(dwOverAllSize));
  892. *pdwNewImageSize = dwOverAllSize;
  893. return uiError;
  894. }
  895. *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;
  896. if(*pdwNewImageSize>0) {
  897. // calculate padding
  898. BYTE bPad = (BYTE)Pad16((DWORD)(*pdwNewImageSize));
  899. if (bPad>dwNewImageSize) {
  900. *pdwNewImageSize += bPad;
  901. return uiError;
  902. }
  903. memset(lpNewImage, 0x00, bPad);
  904. *pdwNewImageSize += bPad;
  905. }
  906. return uiError;
  907. }
  908. static
  909. UINT
  910. GenerateDialog( LPVOID lpNewBuf, LONG dwNewSize,
  911. LPVOID lpNewI, DWORD* pdwNewImageSize )
  912. {
  913. // Should be almost impossible for a Dialog to be Huge
  914. UINT uiError = ERROR_NO_ERROR;
  915. BYTE far * lpNewImage = (BYTE far *) lpNewI;
  916. LONG dwNewImageSize = *pdwNewImageSize;
  917. BYTE far * lpBuf = (BYTE far *) lpNewBuf;
  918. LPRESITEM lpResItem = LPNULL;
  919. LONG dwOverAllSize = 0L;
  920. BYTE bIdCount = 0;
  921. // Dialog Elements
  922. DWORD dwStyle = 0L;
  923. DWORD dwExtStyle = 0L;
  924. WORD wNumOfElem = 0;
  925. WORD wX = 0;
  926. WORD wY = 0;
  927. WORD wcX = 0;
  928. WORD wcY = 0;
  929. WORD wId = 0;
  930. char szClassName[128];
  931. WORD wClassName;
  932. //char szCaption[128];
  933. WORD wPointSize = 0;
  934. char szFaceName[128];
  935. WORD wPos = 1;
  936. // Get the infrmation from the updated resource
  937. if ( dwNewSize ) {
  938. lpResItem = (LPRESITEM) lpBuf;
  939. wX = lpResItem->wX;
  940. wY = lpResItem->wY;
  941. wcX = lpResItem->wcX;
  942. wcY = lpResItem->wcY;
  943. wId = LOWORD(lpResItem->dwItemID);
  944. wPointSize = lpResItem->wPointSize;
  945. dwStyle = lpResItem->dwStyle;
  946. dwExtStyle = lpResItem->dwExtStyle;
  947. wClassName = lpResItem->wClassName;
  948. strcpy( szCaption, lpResItem->lpszCaption );
  949. strcpy( szClassName, lpResItem->lpszClassName );
  950. strcpy( szFaceName, lpResItem->lpszFaceName );
  951. if (*szFaceName != '\0')
  952. {
  953. dwStyle |= DS_SETFONT;
  954. }
  955. lpBuf += lpResItem->dwSize;
  956. dwNewSize -= lpResItem->dwSize;
  957. }
  958. DWORD dwPadCalc = dwOverAllSize;
  959. // Header info
  960. dwOverAllSize = PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
  961. dwOverAllSize += PutDWord( &lpNewImage, dwExtStyle, &dwNewImageSize );
  962. // Store the position of the numofelem for a later fixup
  963. BYTE far * lpNumOfElem = lpNewImage;
  964. LONG lSizeOfNum = sizeof(WORD);
  965. dwOverAllSize += PutWord( &lpNewImage, wNumOfElem, &dwNewImageSize );
  966. dwOverAllSize += PutWord( &lpNewImage, wX, &dwNewImageSize );
  967. dwOverAllSize += PutWord( &lpNewImage, wY, &dwNewImageSize );
  968. dwOverAllSize += PutWord( &lpNewImage, wcX, &dwNewImageSize );
  969. dwOverAllSize += PutWord( &lpNewImage, wcY, &dwNewImageSize );
  970. dwOverAllSize += PutNameOrOrd( &lpNewImage, 0, "", &dwNewImageSize );
  971. dwOverAllSize += PutClassName( &lpNewImage, wClassName, &szClassName[0], &dwNewImageSize );
  972. dwOverAllSize += PutCaptionOrOrd( &lpNewImage, 0, &szCaption[0], &dwNewImageSize,
  973. wClassName, dwStyle );
  974. if( dwStyle & DS_SETFONT ) {
  975. dwOverAllSize += PutWord( &lpNewImage, wPointSize, &dwNewImageSize );
  976. dwOverAllSize += PutStringW( &lpNewImage, &szFaceName[0], &dwNewImageSize );
  977. }
  978. // Check if padding is needed
  979. BYTE bPad = (BYTE)Pad4((WORD)(dwOverAllSize-dwPadCalc));
  980. if (bPad) {
  981. if( (bPad)<=dwNewImageSize )
  982. memset( lpNewImage, 0x00, bPad );
  983. dwNewImageSize -= (bPad);
  984. dwOverAllSize += (bPad);
  985. lpNewImage += (bPad);
  986. }
  987. while( dwNewSize>0 ) {
  988. wNumOfElem++;
  989. if ( dwNewSize ) {
  990. TRACE1("\t\tGenerateDialog:\tdwNewSize=%ld\n",(LONG)dwNewSize);
  991. TRACE1("\t\t\t\tlpszCaption=%Fs\n",lpResItem->lpszCaption);
  992. lpResItem = (LPRESITEM) lpBuf;
  993. wX = lpResItem->wX;
  994. wY = lpResItem->wY;
  995. wcX = lpResItem->wcX;
  996. wcY = lpResItem->wcY;
  997. wId = LOWORD(lpResItem->dwItemID);
  998. dwStyle = lpResItem->dwStyle;
  999. dwExtStyle = lpResItem->dwExtStyle;
  1000. wClassName = LOBYTE(lpResItem->wClassName);
  1001. strcpy( szCaption, lpResItem->lpszCaption );
  1002. strcpy( szClassName, lpResItem->lpszClassName );
  1003. lpBuf += lpResItem->dwSize;
  1004. dwNewSize -= lpResItem->dwSize;
  1005. }
  1006. dwPadCalc = dwOverAllSize;
  1007. //write the control
  1008. dwOverAllSize += PutDWord( &lpNewImage, dwStyle, &dwNewImageSize );
  1009. dwOverAllSize += PutDWord( &lpNewImage, dwExtStyle, &dwNewImageSize );
  1010. dwOverAllSize += PutWord( &lpNewImage, wX, &dwNewImageSize );
  1011. dwOverAllSize += PutWord( &lpNewImage, wY, &dwNewImageSize );
  1012. dwOverAllSize += PutWord( &lpNewImage, wcX, &dwNewImageSize );
  1013. dwOverAllSize += PutWord( &lpNewImage, wcY, &dwNewImageSize );
  1014. dwOverAllSize += PutWord( &lpNewImage, wId, &dwNewImageSize );
  1015. dwOverAllSize += PutClassName( &lpNewImage, wClassName, &szClassName[0], &dwNewImageSize );
  1016. dwOverAllSize += PutCaptionOrOrd( &lpNewImage, 0, &szCaption[0], &dwNewImageSize,
  1017. wClassName, dwStyle );
  1018. dwOverAllSize += PutWord( &lpNewImage, 0, &dwNewImageSize );
  1019. // Check if padding is needed
  1020. bPad = (BYTE)Pad4((WORD)(dwOverAllSize-dwPadCalc));
  1021. if (bPad) {
  1022. if( (bPad)<=dwNewImageSize )
  1023. memset( lpNewImage, 0x00, bPad );
  1024. dwNewImageSize -= (bPad);
  1025. dwOverAllSize += (bPad);
  1026. lpNewImage += (bPad);
  1027. }
  1028. }
  1029. if (dwOverAllSize>(LONG)*pdwNewImageSize) {
  1030. // calc the padding as well
  1031. dwOverAllSize += (BYTE)Pad16((DWORD)(dwOverAllSize));
  1032. *pdwNewImageSize = dwOverAllSize;
  1033. return uiError;
  1034. }
  1035. *pdwNewImageSize = *pdwNewImageSize-dwNewImageSize;
  1036. if(*pdwNewImageSize>0) {
  1037. // calculate padding
  1038. BYTE bPad = (BYTE)Pad16((DWORD)(*pdwNewImageSize));
  1039. if (bPad>dwNewImageSize) {
  1040. *pdwNewImageSize += bPad;
  1041. return uiError;
  1042. }
  1043. memset(lpNewImage, 0x00, bPad);
  1044. *pdwNewImageSize += bPad;
  1045. }
  1046. // fixup the number of items
  1047. PutWord( &lpNumOfElem, wNumOfElem, &lSizeOfNum );
  1048. return uiError;
  1049. }
  1050. ////////////////////////////////////////////////////////////////////////////
  1051. // DLL Specific helpers
  1052. ////////////////////////////////////////////////////////////////////////////
  1053. ////////////////////////////////////////////////////////////////////////////
  1054. // DLL Specific code implementation
  1055. ////////////////////////////////////////////////////////////////////////////
  1056. // Library init
  1057. ////////////////////////////////////////////////////////////////////////////
  1058. // This function should be used verbatim. Any initialization or termination
  1059. // requirements should be handled in InitPackage() and ExitPackage().
  1060. //
  1061. extern "C" int APIENTRY
  1062. DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  1063. {
  1064. if (dwReason == DLL_PROCESS_ATTACH)
  1065. {
  1066. // NOTE: global/static constructors have already been called!
  1067. // Extension DLL one-time initialization - do not allocate memory
  1068. // here, use the TRACE or ASSERT macros or call MessageBox
  1069. AfxInitExtensionModule(extensionDLL, hInstance);
  1070. }
  1071. else if (dwReason == DLL_PROCESS_DETACH)
  1072. {
  1073. // Terminate the library before destructors are called
  1074. AfxWinTerm();
  1075. }
  1076. if (dwReason == DLL_PROCESS_DETACH || dwReason == DLL_THREAD_DETACH)
  1077. return 0; // CRT term Failed
  1078. return 1; // ok
  1079. }
  1080. /////////////////////////////////////////////////////////////////////////////