RWRES.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:19k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /****************************** Module Header *******************************
  11. * Module Name: rwres.c
  12. *
  13. * Does all the reading and writing of the .RES (resource) file.
  14. *
  15. * Functions:
  16. *
  17. *    OpenResFile()
  18. *    WriteRes()
  19. *    LoadResFile()
  20. *    IsValidResFile()
  21. *    SafeParseResHeader()
  22. *    SafeNameOrdLen()
  23. *    SafeDWordAlign()
  24. *    WriteDlgIncludeRes()
  25. *
  26. * Comments:
  27. *
  28. ****************************************************************************/
  29. #include "dlgedit.h"
  30. #include "dlgfuncs.h"
  31. #include "dlgextrn.h"
  32. /*
  33.  * The bytes in the special RT_RESOURCE32 type resource that is the
  34.  * first resource in every Win32 format res file.  The first 8 bytes
  35.  * in this resource's header were specially designed to be invalid
  36.  * for a 16 bit format resource file, so that tools can determine
  37.  * immediately if they are reading a 16 bit or a Win32 format res
  38.  * file.
  39.  */
  40. static BYTE abResource32[] = {
  41.     0x00, 0x00, 0x00, 0x00,                 // DataSize (0 bytes).
  42.     0x20, 0x00, 0x00, 0x00,                 // HeaderSize (32 bytes).
  43.     0xff, 0xff, 0x00, 0x00,                 // Type (RT_RESOURCE32).
  44.     0xff, 0xff, 0x00, 0x00,                 // Name (ordinal 0).
  45.     0x00, 0x00, 0x00, 0x00,                 // DataVersion
  46.     0x00, 0x00,                             // MemoryFlags
  47.     0x00, 0x00,                             // LanguageId
  48.     0x00, 0x00, 0x00, 0x00,                 // Version
  49.     0x00, 0x00, 0x00, 0x00                  // Characteristics
  50. };
  51. STATICFN BOOL LoadResFile(HANDLE hfRes, LPTSTR pszFullResFile,
  52.     LPTSTR pszIncludeBuf);
  53. STATICFN BOOL IsValidResFile(PRES pRes, INT cbFileSize);
  54. STATICFN PRES SafeParseResHeader(PRES pRes, INT cbMaxSize);
  55. STATICFN INT SafeNameOrdLen(LPTSTR psz, INT cbMaxLen);
  56. STATICFN VOID SafeDWordAlign(PBYTE *ppb, PINT pcbMax);
  57. STATICFN BOOL WriteDlgIncludeRes(HANDLE hfWrite, LPTSTR pszFullResFile);
  58. /************************************************************************
  59. * OpenResFile
  60. *
  61. * High level function to load the data in a resource file.  The
  62. * function LoadResFile is called to do the actual work, after
  63. * this code does some housekeeping.
  64. *
  65. * Arguments:
  66. *     LPTSTR pszFullPath - The full path to the resource file.
  67. *
  68. * Returns:
  69. *     TRUE if resource file was opened; otherwise, FALSE.
  70. *
  71. ************************************************************************/
  72. BOOL OpenResFile(
  73.     LPTSTR pszFullPath)
  74. {
  75.     HCURSOR hcurSave;
  76.     PRESLINK prl;
  77.     PRESLINK prlSave;
  78.     BOOL fSuccess = FALSE;
  79.     INT cDlg;
  80.     HANDLE hfRes;
  81.     TCHAR szInclude[CCHMAXPATH];
  82.     TCHAR szFullInclude[CCHMAXPATH];
  83.     BOOL fIncOpened = FALSE;
  84.     hcurSave = SetCursor(hcurWait);
  85.     /*
  86.      * Close any existing resource and include file and free memory.
  87.      * It is assumed that if either had been changed, the user was asked
  88.      * if they wanted to save them, because it is too late now.
  89.      */
  90.     FreeRes();
  91.     FreeInclude();
  92.     if ((hfRes = CreateFile(pszFullPath, GENERIC_READ,
  93.             FILE_SHARE_READ, NULL, OPEN_EXISTING,
  94.             FILE_FLAG_SEQUENTIAL_SCAN, NULL)) != (HANDLE)-1 &&
  95.             LoadResFile(hfRes, pszFullPath, szInclude)) {
  96.         lstrcpy(szFullResFile, pszFullPath);
  97.         pszResFile = FileInPath(szFullResFile);
  98.         ShowFileStatus(TRUE);
  99.         /*
  100.          * If there was a DLGINCLUDE resource found, try and open the
  101.          * specified include file, after making sure that it is a
  102.          * fully formed path.
  103.          */
  104.         if (*szInclude) {
  105.             /*
  106.              * Does the include filespec from the res file appear to
  107.              * be a simple filename without a path?  If so, look for
  108.              * it in the same directory that the res file is in.
  109.              * Otherwise, assume it has a fully qualified path.
  110.              */
  111.             if (!HasPath(szInclude)) {
  112.                 lstrcpy(szFullInclude, szFullResFile);
  113.                 lstrcpy(FileInPath(szFullInclude), szInclude);
  114.             }
  115.             else {
  116.                 lstrcpy(szFullInclude, szInclude);
  117.             }
  118.             fIncOpened = OpenIncludeFile(szFullInclude);
  119.         }
  120.         /*
  121.          * If there wasn't an include resource found, or there was
  122.          * but it couldn't be opened, we want to ask the user for the
  123.          * include file to use for this resource file.
  124.          */
  125.         if (!fIncOpened)
  126.             Open(FILE_INCLUDE);
  127.         /*
  128.          * Start counting the dialogs in the resource, but stop at two.
  129.          */
  130.         cDlg = 0;
  131.         for (cDlg = 0, prl = gprlHead; prl; prl = prl->prlNext) {
  132.             if (prl->fDlgResource) {
  133.                 if (++cDlg > 1)
  134.                     break;
  135.                 prlSave = prl;
  136.             }
  137.         }
  138.         /*
  139.          * If there are multiple dialogs, display the "Select Dialog"
  140.          * dialog to ask the user which one they want to edit.  If
  141.          * there is exactly one dialog, just go ahead and show it
  142.          * initially.
  143.          */
  144.         if (cDlg == 1)
  145.             ResLinkToDialog(prlSave);
  146.         else if (cDlg > 1)
  147.             SelectDialogDialog();
  148.         fSuccess = TRUE;
  149.     }
  150.     if (hfRes != (HANDLE)-1)
  151.         CloseHandle(hfRes);
  152.     ShowFileStatus(TRUE);
  153.     SetCursor(hcurSave);
  154.     return fSuccess;
  155. }
  156. /************************************************************************
  157. * LoadResFile
  158. *
  159. * Loads the resource file specified by the passed in file handle.
  160. * This function first verifies that it is a valid resource file.
  161. *
  162. * Arguments:
  163. *   HANDLE hfRes           - File handle to read from.
  164. *   LPTSTR pszFullResFile  - Full name of resource file being loaded.
  165. *   LPTSTR pszIncludeBuf   - Where to return the include file name, if
  166. *                            a DLGINCLUDE resource is found in the res
  167. *                            file.  If not, this buffer gets a null byte
  168. *                            as its first character.
  169. *
  170. * Returns:
  171. *   TRUE if load was successful; otherwise, FALSE is returned.
  172. *
  173. ************************************************************************/
  174. STATICFN BOOL LoadResFile(
  175.     HANDLE hfRes,
  176.     LPTSTR pszFullResFile,
  177.     LPTSTR pszIncludeBuf)
  178. {
  179.     HANDLE hAllRes;
  180.     PRES pRes;
  181.     PRES pResAll;
  182.     PRESLINK prl;
  183.     PRESLINK prlT;
  184.     INT cbRead;
  185.     LPTSTR pszResType;
  186.     DWORD cbFileSize;
  187.     cbFileSize = GetFileSize((HANDLE)hfRes, NULL);
  188.     if (!(hAllRes = GlobalAlloc(GMEM_MOVEABLE, cbFileSize))) {
  189.         Message(MSG_OUTOFMEMORY);
  190.         return FALSE;
  191.     }
  192.     *pszIncludeBuf = CHAR_NULL;
  193.     pRes = pResAll = (PRES)GlobalLock(hAllRes);
  194.     if ((cbRead = _lread((HFILE)hfRes, (LPSTR)pResAll, cbFileSize)) != -1 &&
  195.             cbRead == (INT)cbFileSize) {
  196.         if (!IsValidResFile(pResAll, cbFileSize)) {
  197.             Message(MSG_BADRESFILE, pszFullResFile);
  198.         }
  199.         else do {
  200.             pszResType = ResourceType(pRes);
  201.             if (IsOrd(pszResType) && OrdID(pszResType) == ORDID_RT_DLGINCLUDE) {
  202.                 /*
  203.                  * Pass back the include file name.  This resource
  204.                  * will not be saved in the res list because it is
  205.                  * going to be explicitly written out later if
  206.                  * necessary.
  207.                  */
  208.                 NameOrdCpy(pszIncludeBuf, (LPTSTR)SkipResHeader(pRes));
  209.             }
  210.             else if (IsOrd(pszResType) &&
  211.                     OrdID(pszResType) == ORDID_RT_RESOURCE32) {
  212.                 /*
  213.                  * This is the dummy resource that identifies a
  214.                  * 32 bit resource file.  This resource should be
  215.                  * skipped also.
  216.                  */
  217.             }
  218.             else {
  219.                 /*
  220.                  * This is some other kind of a resource.
  221.                  * Save it in the resource list.
  222.                  */
  223.                 if (!(prlT = AllocResLink(pRes))) {
  224.                     FreeResList();
  225.                     break;
  226.                 }
  227.                 if (!gprlHead) {
  228.                     gprlHead = prl = prlT;
  229.                 }
  230.                 else {
  231.                     prl->prlNext = prlT;
  232.                     prl = prlT;
  233.                 }
  234.             }
  235.             /*
  236.              * Move to the next resource.
  237.              */
  238.             pRes = (PRES)((PBYTE)pRes + pRes->HeaderSize + pRes->DataSize);
  239.             DWordAlign((PBYTE *)&pRes);
  240.         } while (pRes < (PRES)((PBYTE)pResAll + cbFileSize));
  241.     }
  242.     GlobalUnlock(hAllRes);
  243.     GlobalFree(hAllRes);
  244.     return (gprlHead ? TRUE : FALSE);
  245. }
  246. /************************************************************************
  247. * IsValidResFile
  248. *
  249. * This function does some basic checks on the resource file in memory
  250. * pointed to by pbRes.  It does this by walking through the resource
  251. * checking for the resource header info and lengths.
  252. *
  253. * Arguments:
  254. *   PRES pRes      - Pointer to the first resource in the file.
  255. *   INT cbFileSize - Size of the file in memory.
  256. *
  257. * Returns:
  258. *   TRUE if it is a valid resource file, FALSE if not.
  259. *
  260. ************************************************************************/
  261. STATICFN BOOL IsValidResFile(
  262.     PRES pRes,
  263.     INT cbFileSize)
  264. {
  265.     INT cbCurLoc = 0;
  266.     PRES pResT;
  267.     /*
  268.      * The file is zero size.
  269.      */
  270.     if (!cbFileSize)
  271.         return FALSE;
  272.     pResT = pRes;
  273.     while (cbCurLoc < cbFileSize) {
  274.         /*
  275.          * Check this resource for validity.
  276.          */
  277.         if (!(pResT = SafeParseResHeader(pResT, cbFileSize - cbCurLoc)))
  278.             return FALSE;
  279.         /*
  280.          * Point just past the resource that was just checked.
  281.          */
  282.         cbCurLoc = (PBYTE)pResT - (PBYTE)pRes;
  283.     }
  284.     return (cbCurLoc == cbFileSize) ? TRUE : FALSE;
  285. }
  286. /************************************************************************
  287. * SafeParseResHeader
  288. *
  289. * This function parses the specified resource header and returns a
  290. * pointer to the next resource header in the resource file.  It does
  291. * it in a safe manner, not touching memory beyond the maximum size
  292. * specified.  If the resource header is somehow messed up and
  293. * specifies a size that is larger than will fit in the given maximum
  294. * size, NULL is returned.
  295. *
  296. * Arguments:
  297. *   PRES pRes     - Pointer to the resource.
  298. *   INT cbMaxSize - Maximum size the resource can be.
  299. *
  300. * Returns:
  301. *   A pointer to just past this resource, or NULL if the resource
  302. *   is larger than cbMaxSize.
  303. *
  304. ************************************************************************/
  305. STATICFN PRES SafeParseResHeader(
  306.     PRES pRes,
  307.     INT cbMaxSize)
  308. {
  309.     INT cbLen;
  310.     DWORD cbDataSize;
  311.     PBYTE pb;
  312.     pb = (PBYTE)pRes;
  313.     /*
  314.      * There must be room for the first part of the resource header.
  315.      */
  316.     if (sizeof(RES) > cbMaxSize)
  317.         return FALSE;
  318.     pb += sizeof(RES);
  319.     cbMaxSize -= sizeof(RES);
  320.     /*
  321.      * Parse the type field then skip over it.
  322.      */
  323.     cbLen = SafeNameOrdLen((LPTSTR)pb, cbMaxSize);
  324.     if (cbLen > cbMaxSize)
  325.         return NULL;
  326.     pb += cbLen;
  327.     cbMaxSize -= cbLen;
  328.     /*
  329.      * Parse the name field then skip over it.
  330.      */
  331.     cbLen = SafeNameOrdLen((LPTSTR)pb, cbMaxSize);
  332.     if (cbLen > cbMaxSize)
  333.         return NULL;
  334.     pb += cbLen;
  335.     cbMaxSize -= cbLen;
  336.     SafeDWordAlign(&pb, &cbMaxSize);
  337.     /*
  338.      * There must be room for the second part of the resource header.
  339.      */
  340.     if (sizeof(RES2) > cbMaxSize)
  341.         return FALSE;
  342.     pb += sizeof(RES2);
  343.     cbMaxSize -= sizeof(RES2);
  344.     /*
  345.      * The header size field must be valid.
  346.      */
  347.     if (pRes->HeaderSize != (DWORD)(pb - (PBYTE)pRes))
  348.         return FALSE;
  349.     /*
  350.      * Calculate the size of the data, taking into account any
  351.      * padding that may be at the end to make it DWORD aligned.
  352.      */
  353.     cbDataSize = pRes->DataSize;
  354.     DWordAlign((PBYTE *)&cbDataSize);
  355.     /*
  356.      * There must be room enough left for the data.
  357.      */
  358.     if (cbDataSize > (DWORD)cbMaxSize)
  359.         return FALSE;
  360.     return (PRES)(pb + cbDataSize);
  361. }
  362. /************************************************************************
  363. * SafeNameOrdLen
  364. *
  365. * This function returns the size of the specified name/ordinal.  It
  366. * does it in a safe manner, not touching memory beyond the specified
  367. * maximum size.  If it is a string and the terminating null is not
  368. * found within cbMaxLen bytes, then cbMaxLen plus one is returned.
  369. *
  370. * Arguments:
  371. *   LPTSTR psz   - Pointer to the name/ordinal.
  372. *   INT cbMaxLen - Maximum length to probe.
  373. *
  374. * Returns:
  375. *   The length of the ordinal if it is an ordinal, or the length
  376. *   of the string (plus the null terminator) if it is a string.
  377. *
  378. ************************************************************************/
  379. STATICFN INT SafeNameOrdLen(
  380.     LPTSTR psz,
  381.     INT cbMaxLen)
  382. {
  383.     INT cbLen = 0;
  384.     if (cbMaxLen == 0)
  385.         return 1;
  386.     if (IsOrd(psz))
  387.         return sizeof(ORDINAL);
  388.     for (cbLen = 0; cbLen < cbMaxLen && *psz; psz++, cbLen += sizeof(TCHAR))
  389.         ;
  390.     /*
  391.      * Account for the null terminator.
  392.      */
  393.     cbLen += sizeof(TCHAR);
  394.     return cbLen;
  395. }
  396. /************************************************************************
  397. * SafeDWordAlign
  398. *
  399. * This function aligns the passed pointer to a DWORD boundary.  At the
  400. * same time, it subtracts from the specified counter the amount that
  401. * it had to add to the pointer, if any.
  402. *
  403. * Arguments:
  404. *   PBYTE *ppb  - Points to the pointer to align.
  405. *   PINT pcbMax - Points to the current count to decrement.
  406. *
  407. ************************************************************************/
  408. STATICFN VOID SafeDWordAlign(
  409.     PBYTE *ppb,
  410.     PINT pcbMax)
  411. {
  412.     INT cbAlign;
  413.     cbAlign = (4 - (((WORD)(DWORD)*ppb) & 3)) % 4;
  414.     *ppb += cbAlign;
  415.     *pcbMax -= cbAlign;
  416. }
  417. /************************************************************************
  418. * WriteRes
  419. *
  420. * Worker routine that does the actual writing out of the resource data.
  421. *
  422. * Arguments:
  423. *   HANDLE hfWrite         - Resource file to write to.
  424. *   LPTSTR pszFullResFile  - Full pathname to the resource file that
  425. *                            is being written.
  426. *
  427. * Returns:
  428. *   TRUE if successful; otherwise, FALSE.
  429. *
  430. ************************************************************************/
  431. BOOL WriteRes(
  432.     HANDLE hfWrite,
  433.     LPTSTR pszFullResFile)
  434. {
  435.     PRESLINK prl;
  436.     PRES pRes;
  437.     /*
  438.      * Write the special RT_RESOURCE32 dummy resource to the beginning
  439.      * of the resource file.  This resource is aligned, so no padding
  440.      * needs to be done before writing the resource that follows it.
  441.      */
  442.     if (_lwrite((HFILE)hfWrite, abResource32, sizeof(abResource32)) == -1)
  443.         return FALSE;
  444.     /*
  445.      * Write out any DLGINCLUDE resource there may be.
  446.      */
  447.     if (!WriteDlgIncludeRes(hfWrite, pszFullResFile))
  448.         return FALSE;
  449.     /*
  450.      * Loop through all the resources.
  451.      */
  452.     for (prl = gprlHead; prl; prl = prl->prlNext) {
  453.         if (!(pRes = (PRES)GlobalLock(prl->hRes)))
  454.             return FALSE;
  455.         /*
  456.          * Write the actual data.
  457.          */
  458.         if (_lwrite((HFILE)hfWrite, (LPSTR)pRes, prl->cbRes) == -1)
  459.             return FALSE;
  460.         /*
  461.          * Write pads out to the next DWORD boundary.
  462.          */
  463.         if (!WriteDWordPad(hfWrite, prl->cbRes))
  464.             return FALSE;
  465.         GlobalUnlock(prl->hRes);
  466.     }
  467.     return TRUE;
  468. }
  469. /************************************************************************
  470. * WriteDlgIncludeRes
  471. *
  472. * Writes out a DLGINCLUDE resource to the specified resource file for
  473. * the currently open include file.
  474. *
  475. * Arguments:
  476. *   HANDLE hfWrite         - Resource file handle to write to.
  477. *   LPTSTR pszFullResFile  - Full pathname to the resource file that
  478. *                            is being written.
  479. *
  480. * Returns:
  481. *   Number of characters written if the include resource was
  482. *   written successfully (or there wasn't one to write) or -1
  483. *   if an error occurred.
  484. *
  485. ************************************************************************/
  486. STATICFN BOOL WriteDlgIncludeRes(
  487.     HANDLE hfWrite,
  488.     LPTSTR pszFullResFile)
  489. {
  490.     INT cbResSize;
  491.     INT cbDataSize;
  492.     PRES pResBegin;
  493.     PBYTE pb;
  494.     INT cbWritten;
  495.     LPTSTR pszInc;
  496.     ORDINAL ordDlgIncName;
  497.     BOOL fSuccess = FALSE;
  498.     /*
  499.      * No include file.  Do nothing (return success).
  500.      */
  501.     if (!pszIncludeFile)
  502.         return TRUE;
  503.     /*
  504.      * If the include file is in a different directory than the resource
  505.      * file, write the full path to it.  Otherwise, we just write the
  506.      * include file name.
  507.      */
  508.     if (DifferentDirs(pszFullResFile, szFullIncludeFile))
  509.         pszInc = szFullIncludeFile;
  510.     else
  511.         pszInc = pszIncludeFile;
  512.     /*
  513.      * The DLGINCLUDE resource name always is the same (a value of 1).
  514.      */
  515.     WriteOrd(&ordDlgIncName, ORDID_DLGINCLUDE_NAME);
  516.     /*
  517.      * Determine the size of the resource data.
  518.      */
  519.     cbDataSize = NameOrdLen(pszInc);
  520.     /*
  521.      * Determine the resource size.  Note that there is no need for
  522.      * DWORD padding after the res header, because the header will
  523.      * be aligned (there are no strings in it).
  524.      */
  525.     cbResSize = sizeof(RES) +                       // First part of res header.
  526.             sizeof(ORDINAL) +                       // Type ordinal.
  527.             sizeof(ORDINAL) +                       // Name ordinal.
  528.             sizeof(RES2) +                          // Second half of header.
  529.             cbDataSize;                             // Size of data.
  530.     if (!(pResBegin = (PRES)MyAlloc(cbResSize)))
  531.         return FALSE;
  532.     /*
  533.      * Write the resource header.
  534.      */
  535.     pb = WriteResHeader(pResBegin, cbDataSize, ORDID_RT_DLGINCLUDE,
  536.             (LPTSTR)&ordDlgIncName, MMF_MOVEABLE | MMF_PURE | MMF_DISCARDABLE,
  537.             0, 0, 0, 0);
  538.     /*
  539.      * Write the resource data.  This is simply the name
  540.      * of the include file.
  541.      */
  542.     NameOrdCpy((LPTSTR)pb, pszInc);
  543.     /*
  544.      * Write the resource to the file.
  545.      */
  546.     cbWritten = _lwrite((HFILE)hfWrite, (LPSTR)pResBegin, cbResSize);
  547.     if (cbWritten == cbResSize) {
  548.         /*
  549.          * Write pads out to the next DWORD boundary.
  550.          */
  551.         if (WriteDWordPad(hfWrite, cbWritten))
  552.             fSuccess = TRUE;
  553.     }
  554.     MyFree(pResBegin);
  555.     return fSuccess;
  556. }