Copyright © Microsoft Corporation. This document is an archived reproduction of a version originally published by Microsoft. It may have slight formatting modifications for consistency and to improve readability.
Figure 2   DEPENDS Output for MSDEV.EXE


 LZ32.dll
 VERSION.dll
 comdlg32.dll
 COMCTL32.dll
 SHELL32.dll
 WINMM.dll
 ole32.dll
 RPCRT4.dll
 ADVAPI32.dll
 USER32.dll
 GDI32.dll
 MFC40.DLL
 MSVCIRT.dll
 ntdll.dll
 KERNEL32.dll
 MSVCRT.dll
 MSVCRT40.dll
 MSVCSHL.dll
 MSDEV.EXE

Figure 3   CLOCK.EXE Version Information

COMCTL32.dll

   CompanyName Microsoft Corporation
   FileDescription Custom Controls Library
   FileVersion 4.70
   InternalName COMMCTRL
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename COMMCTRL.DLL
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.70
SHELL32.dll

   CompanyName Microsoft Corporation
   FileDescription Windows Shell Common Dll
   FileVersion 4.00
   InternalName SHELL32
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename SHELL32.DLL
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
RPCRT4.dll

   CompanyName Microsoft Corporation
   FileDescription Remote Procedure Call Runtime
   FileVersion 4.00
   InternalName rpcrt4.dll
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename rpcrt4.dll
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
ADVAPI32.dll

   CompanyName Microsoft Corporation
   FileDescription Advanced Windows 32 Base API
   FileVersion 4.00
   InternalName advapi32.dll
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename advapi32.dll
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
GDI32.dll

   CompanyName Microsoft Corporation
   FileDescription GDI Client DLL
   FileVersion 4.00
   InternalName gdi32
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename gdi32
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
USER32.dll

   CompanyName Microsoft Corporation
   FileDescription Windows NT USER API Client DLL
   FileVersion 4.00
   InternalName user32
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename user32
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
KERNEL32.dll

   CompanyName Microsoft Corporation
   FileDescription Windows NT BASE API Client DLL
   FileVersion 4.00
   InternalName kernel32
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename kernel32
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
ntdll.dll

   CompanyName Microsoft Corporation
   FileDescription NT Layer DLL
   FileVersion 4.00
   InternalName ntdll.dll
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename ntdll.dll
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
comdlg32.dll

   CompanyName Microsoft Corporation
   FileDescription Common Dialogs DLL
   FileVersion 4.00
   InternalName comdlg32
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename comdlg32.dll
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00
clock.exe

   CompanyName Microsoft Corporation
   FileDescription Clock Applet
   FileVersion 4.00
   InternalName clock
   LegalCopyright Copyright (C) Microsoft Corp. 1981-1996
   OriginalFilename CLOCK.EXE
   ProductName Microsoft®Windows NT(TM) Operating System
   ProductVersion 4.00


Figure 4   MODULE_DEPENDENCY_LIST Class

DependencyList.h


 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: DependencyList.h
 //==========================================
 #ifndef __DEPLIST_H__
 #define __DEPLIST_H__

 #ifndef __MODULEFILEINFO_H__
 #include "modulefileinfo.h"
 #endif

 enum errModuleDependencyList {  errMDL_NO_ERROR,
                                 errMDL_FILE_NOT_FOUND,
                                 errMDL_NOT_PE_FILE,
                                 errMDL_GENERAL_FAILURE };

 //
 // The MODULE_DEPENDENCY_LIST class creates a linked list of MODULE_FILE_INFO
 // structures. In theory, this list will represent every executable file
 // loaded by the Win32 loader when the executable is loaded. The class creates
 // the list by starting with the file passed to the constructor, and recursing
 // through all the import tables.
 //
 class MODULE_DEPENDENCY_LIST
 {
     public:

     MODULE_DEPENDENCY_LIST( PSTR pszFileName );

     ~MODULE_DEPENDENCY_LIST( );

     BOOL IsValid( void ){ return (BOOL)(m_errorType = = errMDL_NO_ERROR); }

     errModuleDependencyList GetErrorType( void ){ return m_errorType; }

     PSTR GetErrorString( void );

     PMODULE_FILE_INFO GetNextModule( PMODULE_FILE_INFO p );

     PMODULE_FILE_INFO LookupModule( PSTR pszFileName, BOOL fFullName );

     unsigned GetNumberOfModules( void ){ return m_cModules; }

     protected:

     unsigned            m_cModules;         // Number of modules in list

     PMODULE_FILE_INFO   m_pList;            // Pointer to head of linked list

     // Recursively adds modules to the list
     errModuleDependencyList AddModule( PSTR pszFullName );

     errModuleDependencyList m_errorType;    // Error type
 };

 #endif
DependencyList.cpp

 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: DependencyList.cpp
 //==========================================
 #include <windows.h>
 #include <malloc.h>
 #pragma hdrstop
 #include "peexe.h"
 #include "dependencylist.h"

 MODULE_DEPENDENCY_LIST::MODULE_DEPENDENCY_LIST( PSTR pszFileName )
 {
     m_errorType = errMDL_GENERAL_FAILURE;
     m_cModules = 0;
     m_pList = 0;

     // Make a copy of the path that we can modify to get just the path portion
     PSTR pszJustPath = strdup( pszFileName );
     if ( !pszJustPath )
         return;

     BOOL fHasPath = FALSE;
     PSTR pszEnd = strrchr( pszJustPath, '\\' );
     if ( pszEnd )
     {
         *pszEnd = 0;    /// Strip off the filename
         fHasPath = TRUE;
     }

     //
     // If a path was part of the input filename, save the current directory,
     // then switch to the new directory.
     //
     char szOriginalPath[MAX_PATH];
     if ( fHasPath )
     {
         // This doesn't take into account "App_Paths"!
         GetCurrentDirectory(MAX_PATH, szOriginalPath);  // Save original dir
         SetCurrentDirectory( pszJustPath );             // Switch to app's dir
     }

     //
     // recursively build the module list
     //
     m_errorType = AddModule( pszFileName );

     if ( fHasPath )     // Set things back to the way they were
         SetCurrentDirectory( szOriginalPath );

     free( pszJustPath );    // Free the copy of the path that we allocated
 }


 MODULE_DEPENDENCY_LIST::~MODULE_DEPENDENCY_LIST( )
 {
     PMODULE_FILE_INFO pTemp;

     // Delete each MODULE_FILE_INFO structures in the regular linked list
     pTemp = m_pList;
     while ( pTemp )
     {
         pTemp = m_pList->m_pNext;

         // Before we delete the module, delete each MODULE_FILE_INFO
         // structures in the not found list
         PMODULE_FILE_INFO pNotFound = m_pList->m_pNotFoundNext;
         while ( pNotFound )
         {
             pNotFound = m_pList->m_pNotFoundNext->m_pNotFoundNext;
             delete m_pList->m_pNotFoundNext;
             m_pList->m_pNotFoundNext = pNotFound;
         }

         // Now it's OK to delete the module
         delete m_pList;
         m_pList = pTemp;
         m_cModules--;
     }

     m_pList = 0;
 }



 PMODULE_FILE_INFO MODULE_DEPENDENCY_LIST::GetNextModule( PMODULE_FILE_INFO p )
 {
     // Returns the next module in the linked list of MODULE_FILE_INFO's
     return p ? p->m_pNext : m_pList;
 }


 // Given the name of a file, find the MODULE_FILE_INFO structure that
 // represents it.  The fFullName parameter specifies whether the full path
 // names or just the base file names will be compared.
 PMODULE_FILE_INFO MODULE_DEPENDENCY_LIST::LookupModule( PSTR pszFileName,
                                                         BOOL fFullName )
 {
     PMODULE_FILE_INFO p = m_pList;  // Start at the list head

     while ( p ) // While there's still entries in the list...
     {
         PSTR pszCompName = fFullName ? p->m_szFullName : p->m_szBaseName;

         if ( 0 = = lstrcmpi( pszFileName, pszCompName ) )
             return p;

         p = p->m_pNext;
     }

     return 0;
 }


 PSTR MODULE_DEPENDENCY_LIST::GetErrorString( void )
 {
     switch ( m_errorType )
     {
         case errMDL_NO_ERROR:       return "No error";
         case errMDL_FILE_NOT_FOUND: return "File not found";
         case errMDL_NOT_PE_FILE:    return "Not a PE file";
         case errMDL_GENERAL_FAILURE:return "General failure";
         default:                    return "<Error ???>";
     }
 }


 // Adds a modules to the MODULE_FILE_INFO list.  If the module imports other
 // modules, this routine recurses to add them, and check their imports.
 errModuleDependencyList
 MODULE_DEPENDENCY_LIST::AddModule( PSTR pszFileName )
 {
     PE_EXE peFile( pszFileName );       // Get easy access to the executable

     if ( FALSE = = peFile.IsValid() )    // A valid PE file???
         return (errModuleDependencyList)peFile.GetErrorType();

     PMODULE_FILE_INFO pNew = new MODULE_FILE_INFO( pszFileName );
     if ( !pNew )
         return errMDL_GENERAL_FAILURE;

     pNew->m_pNext = m_pList;
     m_pList = pNew;

     m_cModules++;

     //
     // Now see if this module imports any other modules.  If so, we need
     // to recurse and add them as well.
     //
     if (0 = = peFile.GetDataDirectoryEntrySize( IMAGE_DIRECTORY_ENTRY_IMPORT ))
         return errMDL_NO_ERROR;

     // Make a pointer to the imports table
     PIMAGE_IMPORT_DESCRIPTOR pImportDir;
     pImportDir = (PIMAGE_IMPORT_DESCRIPTOR)
         peFile.GetDataDirectoryEntryPointer(IMAGE_DIRECTORY_ENTRY_IMPORT);
     if ( !pImportDir )
         return errMDL_NO_ERROR;

     // While there are still non-null IMAGE_IMPORT_DESCRIPTORs...
     while ( pImportDir->Name )
     {
         // Get a pointer to the imported module's base name
         PSTR pszBaseName;
         pszBaseName = (PSTR)peFile.GetReadablePointerFromRVA(pImportDir->Name);
         if ( !pszBaseName )
             break;

         // Check to see if it's already in our list.  Don't add again if so.
         if ( 0 = = LookupModule( pszBaseName, FALSE ) )
         {
             // Search path supposedly has the same searching algorithm as
             // the the Win32 loader...
             char szPath[MAX_PATH];
             PSTR pszDontCare;
             if ( SearchPath(0, pszBaseName, 0, MAX_PATH, szPath, &pszDontCare))
                 AddModule( szPath );
             else
                 pNew->AddNotFoundModule( pszBaseName );
         }

         pImportDir++;   // Advance to next imported module
     }

     return errMDL_NO_ERROR;
}

Figure 5   PE_EXE Class

PeExe.h


 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: PeExe.h
 //==========================================
 #ifndef __PEEXE_H__
 #define __PEEXE_H__

 #ifndef __EXEFILE_H__
 #include "exefile.h"
 #endif

 class PE_EXE : public EXE_FILE
 {
     public:

     PE_EXE( PSTR pszFileName );
     ~PE_EXE( ){ }

     IsValid() { return m_pNtHdr ? TRUE : FALSE; }

     // For those who want at the data directly
     PIMAGE_NT_HEADERS GetIMAGE_NT_HEADERS( void ) { return m_pNtHdr; }

     // IMAGE_FILE_HEADER fields
     WORD    GetMachine( void )
                 { return m_pNtHdr->FileHeader.Machine; }
     WORD    GetNumberOfSections( void )
                 { return m_pNtHdr->FileHeader.NumberOfSections; }
     DWORD   GetTimeDateStamp(void)
                 { return m_pNtHdr->FileHeader.TimeDateStamp; }
     DWORD   GetCharacteristics( void )
                 { return m_pNtHdr->FileHeader.Characteristics; }

     // IMAGE_OPTIONAL_HEADER fields
     DWORD   GetSizeOfCode( void )
             { return m_pNtHdr->OptionalHeader.SizeOfCode; }
     DWORD   GetSizeOfInitializedData( void )
             { return m_pNtHdr->OptionalHeader.SizeOfInitializedData; }
     DWORD   GetSizeOfUninitializedData( void )
             { return m_pNtHdr->OptionalHeader.SizeOfUninitializedData; }
     DWORD   GetAddressOfEntryPoint( void )
             { return m_pNtHdr->OptionalHeader.AddressOfEntryPoint; }
     DWORD   GetBaseOfCode( void )
             { return m_pNtHdr->OptionalHeader.BaseOfCode; }
     DWORD   GetBaseOfData( void )
             { return m_pNtHdr->OptionalHeader.BaseOfData; }
     DWORD   GetImageBase( void )
             { return m_pNtHdr->OptionalHeader.ImageBase; }
     DWORD   GetSectionAlignment( void )
             { return m_pNtHdr->OptionalHeader.SectionAlignment; }
     DWORD   GetFileAlignment( void )
             { return m_pNtHdr->OptionalHeader.FileAlignment; }
     WORD    GetMajorOperatingSystemVersion( void )
             { return m_pNtHdr->OptionalHeader.MajorOperatingSystemVersion; }
     WORD    GetMinorOperatingSystemVersion( void )
             { return m_pNtHdr->OptionalHeader.MinorOperatingSystemVersion; }
     WORD    GetMajorImageVersion( void )
             { return m_pNtHdr->OptionalHeader.MajorImageVersion; }
     WORD    GetMinorImageVersion( void )
             { return m_pNtHdr->OptionalHeader.MinorImageVersion; }
     WORD    GetMajorSubsystemVersion( void )
             { return m_pNtHdr->OptionalHeader.MajorSubsystemVersion; }
     WORD    GetMinorSubsystemVersion( void )
             { return m_pNtHdr->OptionalHeader.MinorSubsystemVersion; }
 //    DWORD   GetWin32VersionValue( void )
 //          { return m_pNtHdr->OptionalHeader.Win32VersionValue; }
     DWORD   GetSizeOfImage( void )
             { return m_pNtHdr->OptionalHeader.SizeOfImage; }
     DWORD   GetSizeOfHeaders( void )
             { return m_pNtHdr->OptionalHeader.SizeOfHeaders; }
     WORD    GetSubsystem( void )
             { return m_pNtHdr->OptionalHeader.Subsystem; }
     DWORD   GetSizeOfStackReserve( void )
             { return m_pNtHdr->OptionalHeader.SizeOfStackReserve; }
     DWORD   GetSizeOfStackCommit( void )
             { return m_pNtHdr->OptionalHeader.SizeOfStackCommit; }
     DWORD   GetSizeOfHeapReserve( void )
             { return m_pNtHdr->OptionalHeader.SizeOfHeapReserve; }
     DWORD   GetSizeOfHeapCommit( void )
             { return m_pNtHdr->OptionalHeader.SizeOfHeapCommit; }

     DWORD   GetDataDirectoryEntryRVA( DWORD id );
     PVOID   GetDataDirectoryEntryPointer( DWORD id );
     DWORD   GetDataDirectoryEntrySize( DWORD id );

     PVOID   GetReadablePointerFromRVA( DWORD rva );

     protected:

     DWORD   RVAToFileOffset( DWORD rva );

     PIMAGE_NT_HEADERS m_pNtHdr;
 };

 #endif
PeExe.cpp

 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: PeExe.cpp
 //==========================================
 #include <windows.h>
 #include <stdlib.h>
 #pragma hdrstop
 #include "peexe.h"

 PE_EXE::PE_EXE( PSTR pszFileName ) : EXE_FILE( pszFileName )
 {
     m_pNtHdr = 0;

     if ( FALSE = = EXE_FILE::IsValid() )
         return;

     // It's an EXE, but is it a *PE* file???  If not, set code and bail
     if ( GetExeType() != exeType_PE )
     {
         m_errorType = errEXE_FILE_INVALID_FORMAT;
         return;
     }

     m_pNtHdr = MakePtr(PIMAGE_NT_HEADERS,GetBase(),GetSecondaryHeaderOffset());
 }

 DWORD PE_EXE::GetDataDirectoryEntryRVA( DWORD id )
 {
     // Given a IMAGE_DIRECTORY_ENTRY_XXX value (see WINNT.H), retrive the
     // RVA stored in the corresponding slot

     if ( id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES )
         return (DWORD)-1;

     return m_pNtHdr->OptionalHeader.DataDirectory[id].VirtualAddress;
 }

 PVOID PE_EXE::GetDataDirectoryEntryPointer( DWORD id )
 {
     // Given a IMAGE_DIRECTORY_ENTRY_XXX value (see WINNT.H), return a pointer
     // to memory that corresponds to the RVA in the specified slot.

     if ( id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES )
         return (PVOID)-1;

     DWORD va = m_pNtHdr->OptionalHeader.DataDirectory[id].VirtualAddress;

     if ( !va )      // Return 0 if the RVA is 0
         return 0;

     return GetReadablePointerFromRVA( va );
 }

 DWORD PE_EXE::GetDataDirectoryEntrySize( DWORD id )
 {
     // Given a IMAGE_DIRECTORY_ENTRY_XXX value (see WINNT.H), retrive the
     // size value stored in the corresponding slot

     if ( id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES )
         return (DWORD)-1;

     return m_pNtHdr->OptionalHeader.DataDirectory[id].Size;
 }

 PVOID PE_EXE::GetReadablePointerFromRVA( DWORD rva )
 {
     // Given an RVA, translate it into a pointer within our linear memory
     // mapping for the executable.

     DWORD fileOffset = RVAToFileOffset( rva );
     if ( (DWORD)-1 = = fileOffset )
         return 0;

     return MakePtr( PVOID, GetBase(), fileOffset );
 }

 DWORD PE_EXE::RVAToFileOffset( DWORD rva )
 {
     // Given an RVA, figure out which section encompasses it.  Next, using
     // the PointerToRawData field for the found section, return an actual
     // file offset that corresponds to the RVA

     PIMAGE_SECTION_HEADER pSectHdr = IMAGE_FIRST_SECTION( m_pNtHdr );

     for ( unsigned i = 0; i < GetNumberOfSections(); i++, pSectHdr++ )
     {
         DWORD cbMaxOnDisk
             = min( pSectHdr->Misc.VirtualSize, pSectHdr->SizeOfRawData );

         DWORD startSectRVA = pSectHdr->VirtualAddress;
         DWORD endSectRVA = startSectRVA + cbMaxOnDisk;

         if ( (rva >= startSectRVA) && (rva < endSectRVA) )
             return pSectHdr->PointerToRawData + (rva - startSectRVA);
     }

     return (DWORD)-1;   // RVA not found in the section table... Ooops!
}

Figure 6   EXE_FILE Class

ExeFile.h


 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: ExeFile.h
 //==========================================
 #ifndef __EXEFILE_H__
 #define __EXEFILE_H__

 #ifndef __MEMMAPFL_H__
 #include "memorymappedfile.h"
 #endif

 // MakePtr is a macro that allows you to easily add to values (including
 // pointers) together without dealing with C's pointer arithmetic.  It
 // essentially treats the last two parameters as DWORDs.  The first
 // parameter is used to typecast the result to the appropriate pointer type.
 #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))

 enum EXE_TYPE { exeType_Invalid, exeType_DOS, exeType_NE, exeType_VXD,
                 exeType_LX, exeType_PE };

 enum errEXE_FILE {  errEXE_FILE_NO_ERROR,
                     errEXE_FILE_FILE_NOT_FOUND,
                     errEXE_FILE_INVALID_FORMAT };

 class EXE_FILE : public MEMORY_MAPPED_FILE
 {
     public:

     EXE_FILE( PSTR pszFileName );
     ~EXE_FILE( ){ ; }

     BOOL    IsValid( void ){ return errMMF_NoError == m_errorType; }

     errEXE_FILE GetErrorType( void ){ return m_errorType; }

     DWORD   GetSecondaryHeaderOffset( void ){ return m_secondaryHeaderOffset; }

     EXE_TYPE GetExeType( void ){ return m_exeType; }

     PSTR    GetFileTypeDescription( void );

     protected:

     errEXE_FILE m_errorType;

     private:

     LONG        m_secondaryHeaderOffset;
     EXE_TYPE    m_exeType;

 };

 #endif
ExeFile.cpp

 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: ExeFile.cpp
 //==========================================
 #include <windows.h>
 #pragma hdrstop
 #include "ExeFile.h"

 EXE_FILE::EXE_FILE( PSTR pszFileName ) : MEMORY_MAPPED_FILE( pszFileName )
 {
     m_errorType = errEXE_FILE_FILE_NOT_FOUND;
     m_secondaryHeaderOffset = -1;   // A bogus value to catch bugs
     m_exeType = exeType_Invalid;

     if ( FALSE == MEMORY_MAPPED_FILE::IsValid() )
         return;     // m_errorType already set to errEXE_FILE_FILE_NOT_FOUND

     // If we get here, the file exists, and was mapped.  We're still not
     // sure that it's a valid EXE though
     m_errorType = errEXE_FILE_INVALID_FORMAT;

     if ( GetFileSize() < sizeof(IMAGE_DOS_HEADER) )
         return;

     PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)GetBase();
     if ( IMAGE_DOS_SIGNATURE != pDosHdr->e_magic )
         return;

     // If we get here, it's at least a DOS 'MZ' file
     m_errorType = errEXE_FILE_NO_ERROR;

     if ( pDosHdr->e_lfarlc < 0x40 ) // Theoretically, this field must be >=
     {                               // 0x40 for it to be a non-DOS executable
         m_exeType = exeType_DOS;
         return;
     }

     // Sanity check.  Make sure the "new header" offset isn't past the end
     // of the file
     if ( pDosHdr->e_lfanew > (LONG)GetFileSize() )
         return;

     // Make a pointer to the secondary header
     m_secondaryHeaderOffset = pDosHdr->e_lfanew;
     PWORD pSecondHdr = MakePtr( PWORD, GetBase(), m_secondaryHeaderOffset );

     // Decide what type of EXE, based on the start of the secondary header
     switch ( *pSecondHdr )
     {
         case IMAGE_OS2_SIGNATURE: m_exeType = exeType_NE; break;
         case IMAGE_VXD_SIGNATURE: m_exeType = exeType_VXD; break;
         case 0x4558: m_exeType = exeType_LX; break;     // OS/2 2.X
     }

     if ( *(PDWORD)pSecondHdr == IMAGE_NT_SIGNATURE )
         m_exeType = exeType_PE;
 }

 PSTR EXE_FILE::GetFileTypeDescription( void )
 {
     // Returns a static string that describes what type this file is
     switch ( m_exeType )
     {
         case exeType_DOS:   return "DOS";
         case exeType_NE:    return "NE";
         case exeType_VXD:   return "VXD";
         case exeType_LX:    return "LX";
         case exeType_PE:    return "PE";
         default:            return "Invalid";
     }
 }

Figure 8   Depends.cpp


 //==========================================
 // Matt Pietrek
 // Microsoft Systems Journal, Feb 1997
 // FILE: Depends.cpp
 //==========================================
 #include <windows.h>
 #include <stdio.h>
 #include "DependencyList.h"
 #include "PeExe.h"

 //============================== Variables ===============================
 char g_szHelpSyntax[] =
 "DEPENDS - Matt Pietrek, 1997, for MSJ\n"
 "Syntax: DEPENDS [args] <executable filename>\n"
 "  /v  show version information\n"
 "  /t  show time & date information\n"
 "  /p  show full path\n"
 "  /l  show link time & date information\n\n";

 char * g_pszPrimaryFile = 0;

 BOOL g_fShowDateTime = FALSE;
 BOOL g_fShowLinkDateTime = FALSE;
 BOOL g_fShowVersion = FALSE;
 BOOL g_fShowFullPath = FALSE;

 //============================== Prototypes ===============================
 void DisplayFileInformation( PMODULE_FILE_INFO pModInfo );
 void ShowVersionInfo( PSTR pszFileName );
 BOOL TimeDateStampToFileTime( DWORD timeDateStamp, LPFILETIME pFileTime );
 BOOL GetFileDateAsString( LPFILETIME pFt, char * pszDate, unsigned cbIn );
 BOOL GetFileTimeAsString( LPFILETIME pFt, char * pszTime, unsigned cbIn,
                           BOOL fSeconds );

 //=================================== Code ================================

 BOOL ProcessCommandLine( int argc, char * argv[] )
 {
     BOOL fSawFileName = FALSE;

     if ( argc < 2 )
         return FALSE;

     for ( int i = 1; i < argc; i++ )
     {
         PSTR pArg = argv[i];

         if ( (*pArg = = '/') || (*pArg = = '-') ) // Is it a switch char?
         {
             pArg++; // Point past switch char

             if ( 0 = = lstrcmpi( pArg, "v" ) )
                 g_fShowVersion = TRUE;
             else if ( 0 = = lstrcmpi( pArg, "t" ) )
                 g_fShowDateTime = TRUE;
             else if ( 0 = = lstrcmpi( pArg, "l" ) )
                 g_fShowLinkDateTime = TRUE;
             else if ( 0 = = lstrcmpi( pArg, "p" ) )
                 g_fShowFullPath = TRUE;
             else
             {
                 printf( "Unrecognized option: \"%s\"\n", pArg );
                 return FALSE;
             }
         }
         else
         {
             if ( fSawFileName )
                 return FALSE;

             g_pszPrimaryFile = pArg;
             fSawFileName = TRUE;
         }
     }

     return fSawFileName;
 }

 int main( int argc, char * argv[] )
 {
     if ( !ProcessCommandLine( argc, argv ) )
     {
         printf( g_szHelpSyntax );
         return 1;
     }

     MODULE_DEPENDENCY_LIST depends( g_pszPrimaryFile );

     if ( !depends.IsValid() )
     {
         printf( "Error: %s %s\n", g_pszPrimaryFile, depends.GetErrorString() );
         return 1;
     }

     PMODULE_FILE_INFO pModInfo = 0;

     while ( pModInfo = depends.GetNextModule( pModInfo ) )
     {
         DisplayFileInformation( pModInfo );

         PMODULE_FILE_INFO pNotFound = 0;

         while ( pNotFound = pModInfo->GetNextNotFoundModule(pNotFound) )
         {
             printf( "  Not found: %s\n", pNotFound->GetBaseName() );
         }
     }

     return 0;
 }

 void DisplayFileInformation( PMODULE_FILE_INFO pModInfo )
 {
     printf( "%-14s", pModInfo->GetBaseName() );

     PSTR pszFullName = pModInfo->GetFullName();

     if ( g_fShowDateTime )
     {
         HFILE hFile = _lopen( pszFullName, OF_READ );
         if ( HFILE_ERROR != hFile )
         {
             FILETIME ft;

             if ( GetFileTime( (HANDLE)hFile, 0, 0, &ft ) )
             {
                 char szFileDate[32] = { 0 };
                 char szFileTime[32] = { 0 };

                 GetFileDateAsString(&ft, szFileDate, sizeof(szFileDate) );
                 GetFileTimeAsString(&ft, szFileTime, sizeof(szFileTime),
                                     TRUE);

                 printf( "%s %s  ", szFileDate, szFileTime );
             }

             _lclose( hFile );
         }
     }

     if ( g_fShowLinkDateTime )
     {
         FILETIME ft;
         char szFileDate[32] = { 0 };
         char szFileTime[32] = { 0 };

         PE_EXE exe( pszFullName );

         TimeDateStampToFileTime( exe.GetTimeDateStamp(), &ft );

         GetFileDateAsString(&ft, szFileDate, sizeof(szFileDate) );
         GetFileTimeAsString(&ft, szFileTime, sizeof(szFileTime),
                             TRUE);

         printf( "%s %s  ", szFileDate, szFileTime );
     }

     if ( g_fShowFullPath )
         printf( "(%s)", pszFullName );

     printf( "\n" );

     if ( g_fShowVersion )
         ShowVersionInfo( pszFullName );
 }

 void ShowVersionInfo( PSTR pszFileName )
 {
     DWORD cbVerInfo, dummy;

     // How big is the version info?
     cbVerInfo = GetFileVersionInfoSize( pszFileName, &dummy );
     if ( !cbVerInfo )
         return;

     // Allocate space to hold the info
     PBYTE pVerInfo = new BYTE[cbVerInfo];
     if ( !pVerInfo )
         return;

     _try
     {
         if ( !GetFileVersionInfo(pszFileName, 0, cbVerInfo, pVerInfo) )
             _leave;

         char * predefResStrings[] =
         {
             "CompanyName",
             "FileDescription",
             "FileVersion",
             "InternalName",
             "LegalCopyright",
             "OriginalFilename",
             "ProductName",
             "ProductVersion",
             0
         };

         for ( unsigned i=0; predefResStrings[i]; i++ )
         {
             char szQueryStr[ 0x100 ];
             char szQueryStr2[0x100 ];

             // Format the string with the 1200 codepage (Unicode)
             wsprintf( szQueryStr, "\\StringFileInfo\\%04X%04X\\%s",
                         GetUserDefaultLangID(), 1200,
                         predefResStrings[i] );

             // Format the string with the 1252 codepage (Windows Multilingual)
             wsprintf( szQueryStr2, "\\StringFileInfo\\%04X%04X\\%s",
                         GetUserDefaultLangID(), 1252,
                         predefResStrings[i] );
             // We may want to format a string with the "0000" codepage

             PSTR pszVerRetVal;
             UINT cbReturn;
             BOOL fFound;

             // Try first with the 1252 codepage
             fFound = VerQueryValue( pVerInfo, szQueryStr,
                                     (LPVOID *)&pszVerRetVal, &cbReturn );
             if ( !fFound )
             {
                 // Hmm... 1252 wasn't found.  Try the 1200 codepage
                 fFound = VerQueryValue( pVerInfo, szQueryStr2,
                                         (LPVOID *)&pszVerRetVal, &cbReturn );
             }

             if ( fFound )
                 printf( "  %s %s\n", predefResStrings[i], pszVerRetVal );
         }
     }
     _finally
     {
         delete []pVerInfo;
     }
 }


 // Convert a TimeDateStamp (i.e., # of seconds since 1/1/1970) into a FILETIME

 BOOL TimeDateStampToFileTime( DWORD timeDateStamp, LPFILETIME pFileTime )
 {
     __int64 t1970 = 0x019DB1DED53E8000; // Magic... GMT...  Don't ask....

     __int64 timeStampIn100nsIncr = (__int64)timeDateStamp * 10000000;

     __int64 finalValue = t1970 + timeStampIn100nsIncr;

     memcpy( pFileTime, &finalValue, sizeof( finalValue ) );

     return TRUE;
 }

 BOOL GetFileDateAsString( LPFILETIME pFt, char * pszDate, unsigned cbIn )
 {
     FILETIME ftLocal;
     SYSTEMTIME st;

     if ( !FileTimeToLocalFileTime( pFt, &ftLocal ) )
         return FALSE;

     if ( !FileTimeToSystemTime( &ftLocal, &st ) )
         return FALSE;

     char szTemp[12];

     wsprintf(   szTemp, "%02u/%02u/%04u",
                 st.wMonth, st.wDay, st.wYear );
     lstrcpyn( pszDate, szTemp, cbIn );

     return TRUE;
 }

 BOOL GetFileTimeAsString(   LPFILETIME pFt, char * pszTime, unsigned cbIn,
                             BOOL fSeconds )
 {
     FILETIME ftLocal;
     SYSTEMTIME st;

     if ( !FileTimeToLocalFileTime( pFt, &ftLocal ) )
         return FALSE;

     if ( !FileTimeToSystemTime( &ftLocal, &st ) )
         return FALSE;

     char szTemp[12];

     if ( fSeconds ) // Want seconds???
     {
         wsprintf( szTemp, "%02u:%02u:%02u", st.wHour, st.wMinute,
                   st.wSecond );
     }
     else    // No thanks..  Just hours and minutes
     {
         wsprintf( szTemp, "%02u:%02u", st.wHour, st.wMinute );
     }

     lstrcpyn( pszTime, szTemp, cbIn );

     return TRUE;
}