Figure 2    Simplified View of the PERsrc Classes

 class PERsrcTbl
 {
     PERsrcTbl               // Constructor
     ~PERsrcTbl              // Destructor
     GetNextResourceType     // Enumeration
     GetResourceTypeByName
     GetResourceTypeById
 }
 
 class PERsrcType
 {
     ~PERsrcType             // Destructor
     GetNextResourceInst     // Enumeration
     GetResourceInstByName
     GetResourceInstById
     Id                      // Get Id of resource
     IsNamed                 // Is this a named resource?
     Name                    // Get name of resource
 };
 
 class PERsrcInst
 {
     ~PERsrcInst             // Destructor
     GetData                 // Get pointer to resource instance data
     Id                      // Get Id of resource
     IsNamed                 // Is this a named resource?
     Name                    // Get name of resource
     Size                    // Get size of resource instance, in btyes
     CodePage                // Get code page for this resource instance
 };

Figure 3   DlgDump

DlgDump.CPP


 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, January 1998
 // Program: DlgDump.EXE
 // FILE: DlgDump.CPP
 //==========================================
 #include <windows.h>
 #include <stdio.h>
 #include "MSJPERsrc.h"
 
 BOOL DumpDialog( PVOID pDlg );  // In DlgDumpHelper.H
 
 //=============================== Global Variables ============================
 char g_szHelpText[] = 
 "Dialog Dumper - Matt Pietrek, 1998 for MSJ\n"
 "Syntax: DlgDump <Executable Name>\n";
 
 PSTR g_pszFile = 0;
 
 //==================================== Code ===================================
 
 
 BOOL DumpAllDialogs( PSTR pszFilename )
 {
     // initial hook up to the resources
     PERsrcTbl rsrcTbl( pszFilename );
     
     // Locate the Dialog resources
     PPERsrcType pDlgs = rsrcTbl.GetResourceTypeById( (WORD)RT_DIALOG );
     
     if ( !pDlgs )       // No dialogs?  We're done!
         return FALSE;
 
     PPERsrcInst pDlgInst = 0;   // Begin enumeration by passing 0
 
     // Enumerate through each dialog instance...    
     while ( pDlgInst = pDlgs->GetNextResourceInst( pDlgInst ) )
     {
         // Get a pointer to the raw dialog template
         PVOID pDlgData = pDlgInst->GetData();
         
         if ( pDlgInst )
         {
             printf( "====================\n" );
 
             if ( pDlgInst->IsNamed() )  // Does the dialog have a name? Get it!
             {
                 char szDlgName[256];
                 pDlgInst->Name( szDlgName, sizeof(szDlgName) );
                 printf( "Dialog name: %s\n", szDlgName );
             }
             else    // Dialog is identified by an integer ID
                 printf( "Dialog id: %u\n", pDlgInst->Id() );
                 
             DumpDialog( pDlgData );     // The real work. In DlgDumpHelper.CPP
 
             // We don't have to explicitly delete pDlgInst because the
             // enumeration method does this for us          
             printf( "\n" );
         }                                       
     }
             
     delete pDlgs;   // Delete pointer to the dialog collection
     
     return TRUE;
 }
 
 BOOL ProcessCommandLine( int argc, char *argv[] )
 {
     if ( argc != 2 )    // One parameter (the filename) should be passed
         return FALSE;
 
     g_pszFile = argv[1];         // First real argument is first filename
                        
     return TRUE;
 }
 
 
 int main( int argc, char * argv[] )
 {   
     if ( !ProcessCommandLine( argc, argv ) )
     {
         printf( g_szHelpText );
                 
         return 0;
     }
 
     DumpAllDialogs( g_pszFile );
 
     return 0;
 }

Figure 4   DlgDumpHelper.CPP


 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, January 1998
 // Program: DlgDump.EXE
 // FILE: DlgDumpHelper.CPP
 //==========================================
 #include <windows.h>
 #include <stdio.h>
 // Data and macro definitions to make bitfield/flag decoding easier
 
 typedef struct
 {
     DWORD   flag;
     PSTR    name;
 } DWORD_FLAG_DESCRIPTIONS;
 
 #define FLAG_AS_STRING( f ) { f, #f },
 
 #define WS_STYLE_FLAGS              \
 FLAG_AS_STRING( WS_POPUP )          \
 FLAG_AS_STRING( WS_CHILD )          \
 FLAG_AS_STRING( WS_MINIMIZE )       \
 FLAG_AS_STRING( WS_VISIBLE )        \
 FLAG_AS_STRING( WS_DISABLED )       \
 FLAG_AS_STRING( WS_CLIPSIBLINGS )   \
 FLAG_AS_STRING( WS_CLIPCHILDREN )   \
 FLAG_AS_STRING( WS_MAXIMIZE )       \
 FLAG_AS_STRING( WS_BORDER )         \
 FLAG_AS_STRING( WS_DLGFRAME )       \
 FLAG_AS_STRING( WS_VSCROLL )        \
 FLAG_AS_STRING( WS_HSCROLL )        \
 FLAG_AS_STRING( WS_SYSMENU )        \
 FLAG_AS_STRING( WS_THICKFRAME )     \
 FLAG_AS_STRING( WS_GROUP )          \
 FLAG_AS_STRING( WS_TABSTOP )        \
 
 DWORD_FLAG_DESCRIPTIONS WndStyleFlags[] =   // Style flags common to all wnds
 {
 WS_STYLE_FLAGS
 };
 
 #define NUMBER_WND_STYLE_FLAGS \
     (sizeof(WndStyleFlags) / sizeof(WndStyleFlags[0]))
 
 DWORD_FLAG_DESCRIPTIONS DlgStyleFlags[] = // All style flags used by dialogs
 {
 WS_STYLE_FLAGS
 FLAG_AS_STRING( DS_ABSALIGN )
 FLAG_AS_STRING( DS_SYSMODAL )
 FLAG_AS_STRING( DS_LOCALEDIT )
 FLAG_AS_STRING( DS_SETFONT )
 FLAG_AS_STRING( DS_MODALFRAME )
 FLAG_AS_STRING( DS_NOIDLEMSG )
 FLAG_AS_STRING( DS_SETFOREGROUND )
 FLAG_AS_STRING( DS_3DLOOK )
 FLAG_AS_STRING( DS_FIXEDSYS )
 FLAG_AS_STRING( DS_NOFAILCREATE )
 FLAG_AS_STRING( DS_CONTROL )
 FLAG_AS_STRING( DS_CENTER )
 FLAG_AS_STRING( DS_CENTERMOUSE )
 FLAG_AS_STRING( DS_CONTEXTHELP )
 };
 
 #define NUMBER_DLG_STYLE_FLAGS \
     (sizeof(DlgStyleFlags) / sizeof(DlgStyleFlags[0]))
 
 // Helper function that takes a set of flags, and constructs a string that
 // contains the names of all the flags that are set
 void GetBitfieldsAsString(  DWORD dwStyle, DWORD_FLAG_DESCRIPTIONS *, 
                             unsigned maxFlags, PSTR pszBuffer, unsigned cbLen )
 {
     if ( !cbLen || !pszBuffer )
         return;
     pszBuffer[0] = 0;   // Start it out null terminated
     BOOL fAtLeastOneFlag = FALSE;
     for ( unsigned i = 0; i < maxFlags; i++ )
     {
         if ( dwStyle & DlgStyleFlags[i].flag )
         {
             if ( fAtLeastOneFlag )
                 pszBuffer += sprintf(pszBuffer, " | %s",DlgStyleFlags[i].name);
             else
             {
                 fAtLeastOneFlag = TRUE;
                 pszBuffer += sprintf( pszBuffer, "%s", DlgStyleFlags[i].name );
             }
         }       
     }
 }
 // Helper function that reads a Unicode string out of a dialog template,
 // and stores the results in an ANSI (8-bit) buffer.  Returns a pointer to
 // the byte immediately following the string.
 PWORD GetDlgEmbeddedString( PWORD pwsz, PSTR pszBuffer, unsigned cbLen )
 {
     if ( !cbLen || !pszBuffer )
         return FALSE;
         
     *pszBuffer = 0;
         
     while ( *pwsz )     // Loop through all chars in the unicode string
     {
         if ( cbLen )    // While there's room, copy to the output buffer
             *pszBuffer++ = (BYTE)*pwsz;         
         pwsz++;
     }
     
     // Null terminate the output string
     if ( cbLen )                
         *pszBuffer = 0;         // Space was left over
     else
         *(pszBuffer-1) = 0;     // Wrote to the entire buffer.  Back up and
                                 // null out the last character
         
     return pwsz+1;  // return next WORD past the null terminator
 }
 
 PSTR GetDlgItemClassIdAsString( WORD classId )
 {
     switch ( classId )
     {
         case 0x0080: return "Button";
         case 0x0081: return "Edit";
         case 0x0082: return "Static";
         case 0x0083: return "List box";
         case 0x0084: return "Scroll bar";
         case 0x0085: return "Combo box";
         default: return "unknown";
     }
 }
 // Input: a ptr.  Output: the ptr aligned to a DWORD.
 #define ALIGN_DWORD( type, p ) ( (type)(((DWORD)p+3) & ~3 ))
 // Displays all the fields of a dialog control.  Returns the next address
 // following the control's data.
 LPDLGITEMTEMPLATE DumpDialogItem( LPDLGITEMTEMPLATE pDlgItemTemplate )
 {
     char szDlgItemStyles[512];
 
     // Emits "warning" if the WS_VISIBLE flag isn't set 
     if ( 0 == (pDlgItemTemplate->style & WS_VISIBLE) )
         printf( "  *** Dialog item not visible ***\n" );
     // Start out by printing all the fixed fields in the DLGITEMTEMPLATE
     GetBitfieldsAsString(   pDlgItemTemplate->style,
                             WndStyleFlags, NUMBER_WND_STYLE_FLAGS,
                             szDlgItemStyles, sizeof(szDlgItemStyles) );
 
     printf( "  style: %X (%s)\n", pDlgItemTemplate->style, szDlgItemStyles ); 
     printf( "  dwExtendedStyle: %X\n", pDlgItemTemplate->dwExtendedStyle); 
 
     printf( "  Coords: (%d,%d) - (%d,%d)\n",
                 pDlgItemTemplate->x, pDlgItemTemplate->y,
                 pDlgItemTemplate->x + pDlgItemTemplate->cx,
                 pDlgItemTemplate->y + pDlgItemTemplate->cy );
     printf( "  id: %d\n", (signed short)pDlgItemTemplate->id);
     
     PWORD pClass, pTitle, pCreationData;
     char szAnsiString[256];
     // Following the fixed DLGITEMTEMPLATE, first up is the window class
     pClass = (PWORD)(pDlgItemTemplate+1);   // ptr math!
     if ( *pClass )
     {
         if ( 0xFFFF == *pClass )
         {
             pClass++;
             printf( "  Class: %s\n", GetDlgItemClassIdAsString(*pClass++) );
         }
         else
         {
             pClass = GetDlgEmbeddedString(  pClass, szAnsiString,
                                             sizeof(szAnsiString) );
             printf( "  Class: %s\n", szAnsiString );
         }
     }
     else
         pClass++;
     // Following the window class array is the title array
     pTitle = pClass;
     if ( *pTitle )
     {
         if ( 0xFFFF == *pTitle )
         {
             pTitle++;
             printf( "  Title resource ID: %u\n", *pTitle++ );
         }
         else
         {
             pTitle = GetDlgEmbeddedString(  pTitle, szAnsiString,
                                             sizeof(szAnsiString) );
                                             
             printf( "  Title: %s\n", szAnsiString );
         }
     }
     else
         pTitle++;
 
     pCreationData = pTitle;
     // Following the title array is the (optional) creation data.  We won't
     // show it here, because it's usually not meaningful as ASCII text
     if ( *pCreationData )
     {
         // Adjust for the creation data.  *pCreationData is in bytes, rather
         // than WORDs, so we divide by sizeof(DWORD) to make the ptr addition
         // come out correctly
         pCreationData = (PWORD)( (PBYTE)pCreationData + *pCreationData );
     }
     else
         pCreationData++;
     // Return value is next byte after the DLGITEMTEMPLATE and its
     // variable len  fields     
     return (LPDLGITEMTEMPLATE)pCreationData;
 }
 // Displays all the fields of a dialog template, and then calls DumpDialogItem
 // to display all the controls.
 BOOL DumpDialog( PVOID pDlg )
 {
     LPDLGTEMPLATE pDlgTemplate = (LPDLGTEMPLATE)pDlg;
     
     char szDlgStyles[512];
     PWORD pMenu, pClass, pTitle, pPointSize, pTypeface;
     char szAnsiString[256];
     RECT rectDlg;
     unsigned i;
             
     if ( HIWORD(pDlgTemplate->style) != 0xFFFF )// Is it a regular DLGTEMPLATE?
     {
         // Start out by printing all the fixed fields in the DLGTEMPLATE
         GetBitfieldsAsString(   pDlgTemplate->style,
                                 DlgStyleFlags, NUMBER_DLG_STYLE_FLAGS,
                                 szDlgStyles, sizeof(szDlgStyles) );
         printf( "style: %08X (%s)\n", pDlgTemplate->style, szDlgStyles );
 
         printf( "extended style: %08X\n", pDlgTemplate->dwExtendedStyle );          
 
         printf( "controls: %u\n", pDlgTemplate->cdit );
         printf( "Coords: (%d,%d) - (%d,%d)\n",
                 pDlgTemplate->x, pDlgTemplate->y,
                 pDlgTemplate->x + pDlgTemplate->cx,
                 pDlgTemplate->y + pDlgTemplate->cy );
         rectDlg.left = rectDlg.top = 0;
         rectDlg.right = pDlgTemplate->cx;
         rectDlg.bottom = pDlgTemplate->cy;
         // Following the fixed DLGTEMPLATE, first up is the menu
         pMenu = (PWORD)(pDlgTemplate + 1);  // ptr math!
         if ( *pMenu )
         {
             if ( 0xFFFF == *pMenu )
             {
                 pMenu++;
                 printf( "Menu ID: %u\n", *pMenu++ );
             }
             else
             {
                 pMenu = GetDlgEmbeddedString(   pMenu, szAnsiString,
                                                 sizeof(szAnsiString) );
                 printf( "Menu Name: %s\n", szAnsiString );
             }
         }
         else
             pMenu++;
         
         // Following the menu array is the "window class" array
         pClass = pMenu;
         if ( *pClass )
         {
             if ( 0xFFFF == *pClass )
                 printf( "Class ID: %d\n", (signed short)*pClass++ );
             else
             {
                 pClass = GetDlgEmbeddedString(  pClass, szAnsiString,
                                                 sizeof(szAnsiString) );
                                                 
                 printf( "Class Name: %s\n", szAnsiString );
             }
         }
         else
             pClass++;
         // Following the window class array is the title array
         pTitle = pClass;
         if ( *pTitle )
         {
             pTitle = GetDlgEmbeddedString(  pTitle, szAnsiString,
                                             sizeof(szAnsiString) );
             printf( "Title: %s\n", szAnsiString );
         }
         else
             pTitle++;
         // Following the title array is the point size and font (if DS_SETFONT
         // is set in pDlgTemplate->Style
         if ( pDlgTemplate->style & DS_SETFONT )
         {       
             pPointSize = pTitle;
             pTypeface = pPointSize+1;
             pTypeface = GetDlgEmbeddedString( pTypeface, szAnsiString,
                                               sizeof(szAnsiString) );
             printf( "Font: %u point %s\n", *pPointSize, szAnsiString );
         }
         else
             pTypeface = pTitle; 
 
         LPDLGITEMTEMPLATE pDlgItemTemplate = (LPDLGITEMTEMPLATE)pTypeface;
         
         // Now iterate through each of the controls, calling DumpDialogItem
         for ( i=0; i < pDlgTemplate->cdit; i++ )
         {
             pDlgItemTemplate = ALIGN_DWORD(LPDLGITEMTEMPLATE, pDlgItemTemplate);
 
             printf( "  ----\n" );   // Print separator for next item
 
             // Check that the dialog item is within the bounds of the dialog.
             // If not, emit a warning message
             POINT ctlPt = { pDlgItemTemplate->x, pDlgItemTemplate->y };
             if ( !PtInRect( &rectDlg, ctlPt ) )
                 printf( "  *** Item not within dialog ***\n" );
                 
             pDlgItemTemplate = DumpDialogItem( pDlgItemTemplate );
         }
     }
     else    // Left as an exercise for the reader... :-)
         printf( "DLGTEMPLATEEX type not yet handled\n" );
             
     return TRUE;
 }