home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c031 / 3.ddi / MFC / SAMPLES / RESTOOL / RESTOOL.CP$ / restool
Encoding:
Text File  |  1992-03-11  |  14.6 KB  |  562 lines

  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. }
  562.