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