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;
}