|
|
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;
1.1.1.2 ! root 485: int cdit = pdt->cdit;
1.1 root 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.