|
|
1.1 ! root 1: // restool.cpp : Parses RES files, making Foundation-ready header files for ! 2: // all dialogs in it. This can make it easier to port the ! 3: // dialog code from existing applications, but it is not ! 4: // intended to make writing new dialog code easier or better. ! 5: // ! 6: // This is a part of the Microsoft Foundation Classes C++ library. ! 7: // Copyright (C) 1992 Microsoft Corporation ! 8: // All rights reserved. ! 9: // ! 10: // This source code is only intended as a supplement to the ! 11: // Microsoft Foundation Classes Reference and Microsoft ! 12: // QuickHelp documentation provided with the library. ! 13: // See these sources for detailed information regarding the ! 14: // Microsoft Foundation Classes product. ! 15: ! 16: #include <afx.h> ! 17: #include <afxcoll.h> ! 18: ! 19: #include <windows.h> ! 20: ! 21: #include <fcntl.h> ! 22: #include <io.h> ! 23: #include <ctype.h> ! 24: ! 25: #include "dlgres.h" ! 26: ! 27: ///////////////////////////////////////////////////////////////////////////// ! 28: ! 29: // forward declarations ! 30: BOOL GenDialog(const char*, const char*, int, long, BYTE*); ! 31: ! 32: BOOL CheckResFile(int fh, long cbytes) ! 33: { ! 34: long lFilesize, lCurloc; ! 35: BYTE ch; ! 36: int iType, inum, n; ! 37: long l; ! 38: BYTE* pBuffer; ! 39: char szDlgName[128]; ! 40: char szResourceName[128]; ! 41: ! 42: lFilesize = cbytes; ! 43: lCurloc = 0; ! 44: if (lCurloc == lFilesize) ! 45: return FALSE; ! 46: while (lCurloc < lFilesize) ! 47: { ! 48: n = _read(fh, &ch, 1); ! 49: if (!CheckReadValue(n)) ! 50: return FALSE; ! 51: if (ch == 0xFF) ! 52: { ! 53: n = _read(fh, &iType, 2); ! 54: if (!CheckReadValue(n)) ! 55: return FALSE; ! 56: } ! 57: else ! 58: { ! 59: while (ch != 0) ! 60: { ! 61: n = _read(fh, &ch, 1); ! 62: if (!CheckReadValue(n)) ! 63: return FALSE; ! 64: } ! 65: } ! 66: // read name of resource ! 67: n = _read(fh, &ch, 1); ! 68: if (!CheckReadValue(n)) ! 69: return FALSE; ! 70: ! 71: if (ch == 0xFF) ! 72: { ! 73: // numbered dialog template resource ! 74: n = _read(fh, &inum, 2); ! 75: if (!CheckReadValue(n)) ! 76: return FALSE; ! 77: sprintf(szDlgName, "DLG%d", inum); ! 78: sprintf(szResourceName, "MAKEINTRESOURCE(%d)", inum); ! 79: } ! 80: else ! 81: { ! 82: char* psz; ! 83: psz = szDlgName; ! 84: while (ch != 0) ! 85: { ! 86: *psz++ = ch; ! 87: n = _read(fh, &ch, 1); ! 88: if (!CheckReadValue(n)) ! 89: return FALSE; ! 90: } ! 91: *psz = 0; ! 92: sprintf(szResourceName, "\"%s\"", szDlgName); ! 93: } ! 94: n = _read(fh, &inum, 2); ! 95: if (!CheckReadValue(n)) ! 96: return FALSE; ! 97: n = _read(fh, &l, sizeof(long)); ! 98: if (!CheckReadValue(n)) ! 99: return FALSE; ! 100: ! 101: pBuffer = new BYTE[(size_t)l]; ! 102: if (!pBuffer) ! 103: return FALSE; ! 104: ! 105: n = _read(fh, pBuffer, (int)l); ! 106: ! 107: if (iType == 5) ! 108: { ! 109: // Convert all but first letter of "class name" to lower case. ! 110: // ! 111: { ! 112: char* pch = szDlgName; ! 113: if (*pch) ! 114: { ! 115: *pch = toupper(*pch); ! 116: for (pch++; *pch; pch++) ! 117: *pch = tolower(*pch); ! 118: } ! 119: } ! 120: ! 121: if (!GenDialog(szDlgName, szResourceName, inum, l, pBuffer)) ! 122: return FALSE; ! 123: } ! 124: ! 125: delete pBuffer; ! 126: ! 127: if (n != l) ! 128: return FALSE; ! 129: ! 130: lCurloc = _lseek(fh, 0l, 1); ! 131: } ! 132: if (lCurloc != lFilesize) ! 133: return FALSE; ! 134: ! 135: return TRUE; ! 136: } ! 137: ! 138: int main(int argc, char* argv[]) ! 139: { ! 140: int fh; ! 141: long lBytes; ! 142: ! 143: if (argc != 2) ! 144: { ! 145: fprintf(stderr, "restool : usage: restool file.res >file.h\n"); ! 146: fprintf(stderr, " Parses RES files, making Foundation-ready H files for\n"); ! 147: fprintf(stderr, " all dialogs in it. This can make it easier to port the\n"); ! 148: fprintf(stderr, " dialog code from existing applications.\n"); ! 149: fprintf(stderr, " The output should be redirected into an H file for use.\n"); ! 150: exit(1); ! 151: } ! 152: ! 153: fh = _open(argv[1], O_BINARY); ! 154: if (fh == -1) ! 155: { ! 156: fprintf(stderr, "restool : Cannot open file %s for reading.\n", argv[1]); ! 157: exit(1); ! 158: } ! 159: lBytes = _lseek(fh, 0l, 2); ! 160: _lseek(fh, 0l, 0); ! 161: ! 162: printf("// restool has generated the following header code from %s\n\n", argv[1]); ! 163: if (!CheckResFile(fh, lBytes)) ! 164: { ! 165: fprintf(stderr, "restool : Cannot parse file %s; may be invalid.\n", argv[1]); ! 166: exit(1); ! 167: } ! 168: printf("\n\n// END OF restool code\n"); ! 169: ! 170: return 0; ! 171: } ! 172: ! 173: ///////////////////////////////////////////////////////////////////////////// ! 174: // Information for control types ! 175: ! 176: struct ControlType ! 177: { ! 178: BYTE code; // if 0 => end, if 0xFF => match any ! 179: BYTE style; // lower 4 bits of style ! 180: // 0xFF => accept any style ! 181: ! 182: const char* pszClass; // if NULL use previous ! 183: const char* pszNoun; // if NULL use previous ! 184: int nCount; // significant only if pszNoun != NULL ! 185: }; ! 186: ! 187: ControlType types[] = ! 188: { ! 189: { BUTTONCODE, BS_AUTOCHECKBOX, "CButton", "Check" }, ! 190: { BUTTONCODE, BS_CHECKBOX, NULL, NULL }, ! 191: { BUTTONCODE, BS_3STATE, NULL, NULL }, ! 192: { BUTTONCODE, BS_AUTO3STATE, NULL, NULL }, ! 193: { BUTTONCODE, BS_AUTORADIOBUTTON, NULL, "Option" }, ! 194: { BUTTONCODE, BS_RADIOBUTTON, NULL, NULL }, ! 195: { BUTTONCODE, BS_GROUPBOX, NULL, "Group" }, ! 196: { BUTTONCODE, BS_PUSHBUTTON, NULL, "Button" }, ! 197: { BUTTONCODE, BS_DEFPUSHBUTTON, NULL, NULL }, ! 198: { EDITCODE, 0xFF, "CEdit", "Edit" }, ! 199: { STATICCODE, SS_SIMPLE, "CStatic", "Text" }, ! 200: { STATICCODE, SS_LEFT, NULL, NULL }, ! 201: { STATICCODE, SS_CENTER, NULL, NULL }, ! 202: { STATICCODE, SS_RIGHT, NULL, NULL }, ! 203: { STATICCODE, SS_LEFTNOWORDWRAP, NULL, NULL }, ! 204: { STATICCODE, SS_ICON, NULL, "Icon" }, ! 205: { STATICCODE, SS_BLACKRECT, NULL, "Box" }, ! 206: { STATICCODE, SS_GRAYRECT, NULL, NULL }, ! 207: { STATICCODE, SS_WHITERECT, NULL, NULL }, ! 208: { STATICCODE, SS_BLACKFRAME, NULL, NULL }, ! 209: { STATICCODE, SS_GRAYFRAME, NULL, NULL }, ! 210: { STATICCODE, SS_WHITEFRAME, NULL, NULL }, ! 211: { LISTBOXCODE, 0xFF, "CListBox", "List" }, ! 212: { COMBOBOXCODE, 0xFF, "CComboBox", "Combo" }, ! 213: { SCROLLBARCODE, 0, "CScrollBar", "HScroll" }, ! 214: { SCROLLBARCODE, SBS_VERT, NULL, "VScroll" }, ! 215: { 0xFF, 0xFF, "CWnd", "Control" }, // 2nd last ! 216: { 0 } ! 217: }; ! 218: ! 219: void InitCounts() ! 220: { ! 221: for (register ControlType* pType = types; pType->code != 0; pType++) ! 222: if (pType->pszNoun != NULL) ! 223: pType->nCount = 0; ! 224: } ! 225: ! 226: // IsLabel: ! 227: // Simple logic for determining if an item is really a label. ! 228: // Labels do not (usually) need any code, so none is generated. ! 229: // ! 230: BOOL IsLabel(BYTE code, DLGITEMTEMPLATE* pDit, BYTE nextCode) ! 231: { ! 232: if (pDit->id == -1) ! 233: return TRUE; // may not be real label, but ignore anyway ! 234: ! 235: if (code == STATICCODE && nextCode != 0) ! 236: { ! 237: // static code with something after it ! 238: if (pDit->style & SS_NOPREFIX) ! 239: return FALSE; // no accelerator => probably not a label ! 240: ! 241: switch (pDit->style & 0xf) ! 242: { ! 243: case SS_LEFT: case SS_CENTER: case SS_RIGHT: ! 244: case SS_SIMPLE: case SS_LEFTNOWORDWRAP: ! 245: break; // keep going ! 246: default: ! 247: return FALSE; ! 248: } ! 249: ! 250: // lastly, only keep labels if next item is edit or list/combo ! 251: switch (nextCode) ! 252: { ! 253: case EDITCODE: case LISTBOXCODE: case COMBOBOXCODE: ! 254: return TRUE; ! 255: } ! 256: } ! 257: return FALSE; ! 258: } ! 259: ! 260: ///////////////////////////////////////////////////////////////////////////// ! 261: ! 262: // ControlInfo: ! 263: // Decode control information and place in easy-to-use structure. ! 264: // ! 265: struct ControlInfo ! 266: { ! 267: BYTE code; ! 268: BYTE style; // lower 4 bits of style ! 269: ! 270: const char* pszClass; ! 271: CString memberName; // will be literal text for a label ! 272: UINT id; ! 273: ! 274: // special values ! 275: BOOL bLabel; // label not an interactive control ! 276: int nRadioGroup; // or -1 for none ! 277: ! 278: ControlInfo() // structure initialization ! 279: { ! 280: pszClass = NULL; ! 281: id = 0; ! 282: bLabel = FALSE; ! 283: nRadioGroup = -1; ! 284: } ! 285: }; ! 286: ! 287: struct ControlInfo* DecodeControls(BYTE* pBuffer, BYTE* pEnd, int nCount) ! 288: { ! 289: // decode controls in dialog ! 290: CMapStringToPtr usedNames; ! 291: CString lastLabel, lastLabelLiteral; ! 292: lastLabel.GetBuffer(128); // set a reasonable size ! 293: lastLabelLiteral.GetBuffer(128); // set a reasonable size ! 294: ! 295: struct ControlInfo* pAllInfo = new ControlInfo[nCount]; ! 296: ASSERT(pAllInfo != NULL); ! 297: ! 298: for (int iCtl = 0; iCtl < nCount; iCtl++) ! 299: { ! 300: struct ControlInfo* pInfo = &pAllInfo[iCtl]; ! 301: DLGITEMTEMPLATE* pDit = (DLGITEMTEMPLATE*)pBuffer; ! 302: pBuffer += sizeof(DLGITEMTEMPLATE); ! 303: ! 304: BYTE cTokenCode = *pBuffer++; ! 305: char* pszString = (char*)pBuffer; ! 306: pBuffer = SkipString(pBuffer) + 1; ! 307: ! 308: ASSERT(pBuffer <= pEnd); ! 309: pInfo->code = cTokenCode; ! 310: pInfo->id = pDit->id; ! 311: pInfo->style = (BYTE)(pDit->style&0xf); // lower 4 bits of style ! 312: ! 313: if (*pszString != '\0') ! 314: { ! 315: // save it away as a reasonable symbol ! 316: lastLabelLiteral = pszString; // literal string (for comments) ! 317: lastLabel = ""; ! 318: ! 319: while (*pszString != '\0' && !isalpha(*pszString)) ! 320: pszString++; // skip non-alpha ! 321: ! 322: // include alpha+numbers for the rest of the name ! 323: while (*pszString != '\0') ! 324: { ! 325: if (isalnum(*pszString)) ! 326: lastLabel += *pszString; ! 327: *pszString++; ! 328: } ! 329: } ! 330: ! 331: BYTE nextCode = 0; ! 332: if (pBuffer + sizeof(DLGITEMTEMPLATE) < pEnd) ! 333: nextCode = *(pBuffer+sizeof(DLGITEMTEMPLATE)); ! 334: ! 335: if (IsLabel(cTokenCode, pDit, nextCode)) ! 336: { ! 337: pInfo->bLabel = TRUE; ! 338: pInfo->pszClass = NULL; ! 339: pInfo->memberName = lastLabelLiteral; ! 340: continue; ! 341: } ! 342: ! 343: const char* pszClass = NULL; ! 344: const char* pszNoun = NULL; ! 345: BOOL bExact = FALSE; ! 346: int* pnIndex = NULL; ! 347: for (register ControlType* pType = types; pType->code != 0; pType++) ! 348: { ! 349: if (pType->code == cTokenCode || pType->code == 0xFF) ! 350: { ! 351: // match raw category ! 352: if (pType->pszClass != NULL) ! 353: pszClass = pType->pszClass; ! 354: ASSERT(pszClass != NULL); ! 355: if (pType->pszNoun != NULL) ! 356: { ! 357: pszNoun = pType->pszNoun; ! 358: pnIndex = &pType->nCount; ! 359: } ! 360: ! 361: // check for sub-type match ! 362: if (pType->style == 0xFF || ! 363: ((BYTE)pType->style == (BYTE)(pDit->style&0xf))) ! 364: { ! 365: // exact match ! 366: bExact = TRUE; ! 367: break; ! 368: } ! 369: } ! 370: } ! 371: ! 372: ASSERT(bExact); ! 373: (*pnIndex)++; // bump count of objects using that noun ! 374: ! 375: // save remaining info ! 376: pInfo->pszClass = pszClass; ! 377: CString memberName; ! 378: if (!lastLabel.IsEmpty()) ! 379: { ! 380: pInfo->memberName = lastLabel; ! 381: pInfo->memberName += pszNoun; ! 382: } ! 383: else ! 384: { ! 385: pInfo->memberName = pszNoun; ! 386: char szT[10]; ! 387: pInfo->memberName += _itoa(*pnIndex, szT, 10); ! 388: } ! 389: ! 390: void* p; ! 391: if (usedNames.Lookup(pInfo->memberName, p)) ! 392: { ! 393: // name has already been used in this class ! 394: char szT[10]; ! 395: pInfo->memberName += _itoa(*pnIndex, szT, 10); ! 396: } ! 397: usedNames[pInfo->memberName] = "USED"; ! 398: ! 399: lastLabel = ""; ! 400: lastLabelLiteral = ""; ! 401: } ! 402: ASSERT(pBuffer == pEnd); ! 403: return pAllInfo; // return array ! 404: } ! 405: ! 406: ///////////////////////////////////////////////////////////////////////////// ! 407: // Print out control info ! 408: ! 409: void PrintControls(const struct ControlInfo * pInfo, int nCount, ! 410: DWORD /* styleDlg */) ! 411: { ! 412: for (int iCtl = 0; iCtl < nCount; iCtl++, pInfo++) ! 413: { ! 414: if (pInfo->bLabel) ! 415: { ! 416: printf("\t// label '%s'\n", (const char*)pInfo->memberName); ! 417: } ! 418: else ! 419: { ! 420: // Build normal member type. ! 421: // ! 422: CString typeName = pInfo->pszClass; ! 423: typeName += '&'; // return reference ! 424: if (typeName.GetLength() < 8) ! 425: typeName += '\t'; ! 426: ! 427: // Write out member function definition. ! 428: printf("\t%s %s()\n" ! 429: "\t\t\t{ return *((%s*) GetDlgItem(%d)); } \n", ! 430: (const char*)typeName, ! 431: (const char*)pInfo->memberName, ! 432: pInfo->pszClass, pInfo->id); ! 433: } ! 434: } ! 435: } ! 436: ! 437: ///////////////////////////////////////////////////////////////////////////// ! 438: ! 439: // DetectRadioGroups: ! 440: // Special detection for radio groups. ! 441: // ! 442: void DetectRadioGroups(struct ControlInfo* pInfo, int nCount) ! 443: { ! 444: int nRadioGroup = -1; ! 445: UINT idLast = 0; ! 446: ! 447: for (int iCtl = 0; iCtl < nCount; iCtl++, pInfo++) ! 448: { ! 449: if (pInfo->code == BUTTONCODE && ! 450: (pInfo->style == BS_AUTORADIOBUTTON || ! 451: pInfo->style == BS_RADIOBUTTON)) ! 452: { ! 453: if (pInfo->id != idLast+1) ! 454: { ! 455: // start new group ! 456: nRadioGroup = -1; ! 457: } ! 458: pInfo->nRadioGroup = ++nRadioGroup; ! 459: // next in sequence ! 460: } ! 461: else ! 462: { ! 463: nRadioGroup = -1; ! 464: } ! 465: idLast = pInfo->id; ! 466: } ! 467: } ! 468: ! 469: ! 470: ///////////////////////////////////////////////////////////////////////////// ! 471: ! 472: // GenDialog: ! 473: // Do the actual code-generation work. ! 474: // ! 475: BOOL GenDialog(const char* pszName, const char* pszResourceName, ! 476: int /* flags */, long l, BYTE* pBuffer) ! 477: { ! 478: BYTE* pEnd = &pBuffer[l]; ! 479: ! 480: InitCounts(); ! 481: ! 482: DLGTEMPLATE* pdt = (DLGTEMPLATE*)pBuffer; ! 483: pBuffer += sizeof(DLGTEMPLATE); ! 484: DWORD styleDlg = pdt->style; ! 485: BYTE cdit = pdt->cdit; ! 486: ! 487: fprintf(stderr, "restool : Generating header for dialog %s.\n", pszName); ! 488: ! 489: // Make sure there is no menu string... ! 490: if (*pBuffer != '\0') ! 491: fprintf(stderr, "\nrestool : WARNING: Menus in dialogs are not supported.\n"); ! 492: pBuffer = SkipString(pBuffer); ! 493: ! 494: // Make sure only generic window class used ! 495: ! 496: if (*pBuffer != '\0') ! 497: fprintf(stderr, "\nrestool : WARNING: Only generic window classes are supported.\n"); ! 498: pBuffer = SkipString(pBuffer); ! 499: ! 500: // Deal with caption string... ! 501: char* pszCaption = (char*) pBuffer; ! 502: pBuffer = SkipString(pBuffer); ! 503: ! 504: // Skip over font data if present ! 505: if (styleDlg & DS_SETFONT) ! 506: pBuffer = SkipString(pBuffer + sizeof(short int)); ! 507: ! 508: // preliminary stuff ! 509: const char* pszBaseClass; ! 510: ! 511: BOOL bModal = ((styleDlg & (DS_SYSMODAL | DS_MODALFRAME)) != 0); ! 512: pszBaseClass = bModal ? "CModalDialog" : "CDialog"; ! 513: ! 514: printf("///////////////////////////////////////////////////////////\n"); ! 515: printf("// class C%s manages the %s dialog resource\n\n", pszName, ! 516: pszResourceName); ! 517: printf("class C%s : public %s\n", pszName, pszBaseClass); ! 518: printf("{\n"); ! 519: printf("public:\n"); ! 520: ! 521: // Write the constructor. ! 522: // ! 523: printf("\tC%s(CWnd* pParentWnd = NULL)\n", pszName); ! 524: if (bModal) ! 525: { ! 526: // CModalDialog constructor ! 527: printf("\t\t: %s(%s, pParentWnd)\n", pszBaseClass, pszResourceName); ! 528: printf("\t\t\t{ }\n"); ! 529: } ! 530: else ! 531: { ! 532: // CModal dialog constructor + create modeless ! 533: printf("\t\t{\n"); ! 534: printf("\t\t\tVERIFY(Create(%s, pParentWnd));\n", pszResourceName); ! 535: printf("\t\t}\n"); ! 536: } ! 537: ! 538: // Write the public member variable declarations. ! 539: // ! 540: printf("\n\t// Attributes\n"); ! 541: struct ControlInfo* pAllInfo; ! 542: pAllInfo = DecodeControls(pBuffer, pEnd, cdit); ! 543: DetectRadioGroups(pAllInfo, cdit); ! 544: PrintControls(pAllInfo, cdit, styleDlg); ! 545: ! 546: // Write the member function declarations. ! 547: printf("\n\t// Operations\n"); ! 548: ! 549: // Write the overriding virtual member function declarations. ! 550: // ! 551: printf("\n\t// Overridables\n"); ! 552: ! 553: // Write the message-map and message-handling member function declarations. ! 554: // ! 555: printf("\n\t// Implementation\n"); ! 556: printf("private:\n"); ! 557: printf("\tBOOL OnInitDialog();\n"); ! 558: printf("\tDECLARE_MESSAGE_MAP()\n"); ! 559: printf("};\n\n"); ! 560: return TRUE; ! 561: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.