Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
Member Area
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Become a Member
-Why sign up!
-Chat Online!
-Indexes NEW!!
-Build your resume
-Find a job
-Post a job
-Resume Search
-Link to us
Visit Embarcadero
Embarcadero Community
How to check for exe files and DLLs Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
Files Operation
Delphi 3.x
User Rating
No Votes
# Votes
DSP, Administrator
Reference URL:
			Author: Peter Johnson

This article looks at how we examine a file to check if it is a DOS or Windows 
executable and, if so, whether it is a program file or a DLL.



In article "Getting an exe file type", Lutfi Baran showed us how to find out if a 
file is a 16 or 32 bit Windows or a DOS executable. But what if we need to know if 
the file is an application or a DLL?

This articles adds to Lutfi's work by adding the ability to check for DLLs. Since 
this code was developed independently of the earlier article, any errors are mine!

Thanks to to Flurin Honegger (see comment below) for suggesting some of the 
"reasonableness" checks on the DOS header to verify a valid MS-DOS file that are 
included in this revised article.

This is an abbreviated version of the original 
article, published on my 

Outline Design

Before we start coding, let's look at how we're going to accomplish this task. Our 
approach will be to scan through the file, looking for markers to indicate its file 
type. We use the following information:

All DOS program files (and therefore Windows executables) begin with a header 
record whose first element is a "magic number"; the word value $5A4D ("MZ" in 

The DOS header defines the expected length of the file and the offset of a 
"relocation table". We can check the length of the file being checked is greater 
than or equal to the expected length and that the offset of the DOS relocation 
table lies within the file. 

Windows executables have a header record whose offset in the file is given by the 
LongWord at offset $3C. 

The Windows header begins with the "magic number" $454E (NE file format - 16bit) or 
$4550 (PE file format - 32bit). 

PE executables have an "image header" immediately following the $4550 magic number. 
This header structure has a Characteristics field which is a bit mask If the bit 
mask contains the flag IMAGE_FILE_DLL then the file is a DLL. 

NE executables have a byte sized field at offset $0D from the start of the header 
which is a bit mask that contains the flag $80 when the file is a DLL. 

Coding the Function

Our function will return a value that indicates the type of file whose name is 
passed to it as a parameter. The type of the return value is defined as:

1   type
2     TExeFileKind = (
3       fkUnknown, // unknown file kind: not an executable
4       fkError, // error file kind: used for files that don't exist
5       fkDOS, // DOS executable
6       fkExe32, // 32 bit executable
7       fkExe16, // 16 bit executable
8       fkDLL32, // 32 bit DLL
9       fkDLL16 // 16 bit DLL
10      );

The implementation of the function requires structures for the PE and DOS file 
headers. The PE file header (type IMAGE_FILE_HEADER) is defined in the Windows 
unit. The DOS file header is not defined there, so we need to defined it as follows 
(copied from the Delphi Resxplor demo program):

11  type
12    IMAGE_DOS_HEADER = packed record // DOS .exe header
13      e_magic: Word; // Magic number ("MZ")
14      e_cblp: Word; // Bytes on last page of file
15      e_cp: Word; // Pages in file
16      e_crlc: Word; // Relocations
17      e_cparhdr: Word; // Size of header in paragraphs
18      e_minalloc: Word; // Minimum extra paragraphs needed
19      e_maxalloc: Word; // Maximum extra paragraphs needed
20      e_ss: Word; // Initial (relative) SS value
21      e_sp: Word; // Initial SP value
22      e_csum: Word; // Checksum
23      e_ip: Word; // Initial IP value
24      e_cs: Word; // Initial (relative) CS value
25      e_lfarlc: Word; // Address of relocation table
26      e_ovno: Word; // Overlay number
27      e_res: packed array[0..3] of Word; // Reserved words
28      e_oemid: Word; // OEM identifier (for e_oeminfo)
29      e_oeminfo: Word; // OEM info; e_oemid specific
30      e_res2: packed array[0..9] of Word; // Reserved words
31      e_lfanew: Longint; // File address of new exe header
32    end;

We are now ready to code the function:
34  function ExeType(const FileName: string): TExeFileKind;
35  {Examines given file and returns a code that indicates the type of executable
36  file it is (or if it isn't an executable)}
37  const
38    cDOSRelocOffset = $18; // offset of "pointer" to DOS relocation table
39    cWinHeaderOffset = $3C; // offset of "pointer" to windows header in file
40    cNEAppTypeOffset = $0D; // offset in NE windows header of app type field
41    cDOSMagic = $5A4D; // magic number identifying a DOS executable
42    cNEMagic = $454E; // magic number identifying a NE executable (Win 16)
43    cPEMagic = $4550; // magic nunber identifying a PE executable (Win 32)
44    cNEDLLFlag = $80 // flag in NE app type field indicating a DLL
45  var
46    FS: TFileStream; // stream to executable file
47    WinMagic: Word; // word that contains PE or NE magic numbers
48    HdrOffset: LongInt; // offset of windows header in exec file
49    ImgHdrPE: IMAGE_FILE_HEADER; // PE file header record
50    DOSHeader: IMAGE_DOS_HEADER; // DOS header
51    AppFlagsNE: Byte; // byte defining DLLs in NE format
52    DOSFileSize: Integer; // size of DOS file
53  begin
54    try
55      // Open stream onto file: raises exception if can't be read
56      FS := TFileStream.Create(FileName, fmOpenRead + fmShareDenyNone);
57      try
58        // Assume unkown file
59        Result := fkUnknown;
60        // Any exec file is at least size of DOS header long
61        if FS.Size < SizeOf(DOSHeader) then
62          Exit;
63        FS.ReadBuffer(DOSHeader, SizeOf(DOSHeader));
64        // DOS files begin with "MZ"
65        if DOSHeader.e_magic <> cDOSMagic then
66          Exit;
67        // DOS files have length >= size indicated at offset $02 and $04
68        // (offset $02 indicates length of file mod 512 and offset $04 indicates
69        // no. of 512 pages in file)
70        if (DOSHeader.e_cblp = 0) then
71          DOSFileSize := DOSHeader.e_cp * 512
72        else
73          DOSFileSize := (DOSHeader.e_cp - 1) * 512 + DOSHeader.e_cblp;
74        DOSFileSize := (DOSHeader.e_cp - 1) * 512 + DOSHeader.e_cblp;
75        if FS.Size < DOSFileSize then
76          Exit;
77        // DOS file relocation offset must be within DOS file size.
78        if DOSHeader.e_lfarlc > DOSFileSize then
79          Exit;
80        // We assume we have an executable file: assume its a DOS program
81        Result := fkDOS;
82        // Try to find offset of Windows program header
83        if FS.Size <= cWinHeaderOffset + SizeOf(LongInt) then
84          // file too small for windows header "pointer": it's a DOS file
85          Exit;
86        // read it
87        FS.Position := cWinHeaderOffset;
88        FS.ReadBuffer(HdrOffset, SizeOf(LongInt));
89        // Now try to read first word of Windows program header
90        if FS.Size <= HdrOffset + SizeOf(Word) then
91          // file too small to contain header: it's a DOS file
92          Exit;
93        FS.Position := HdrOffset;
94        // This word should identify either a NE or PE format file: check which
95        FS.ReadBuffer(WinMagic, SizeOf(Word));
96        case WinMagic of
97          cPEMagic:
98            begin
99              // 32 bit Windows application: now check whether app or DLL
100             if FS.Size < HdrOffset + SizeOf(LongWord) + SizeOf(ImgHdrPE) then
101               // file not large enough for image header: assume DOS
102               Exit;
103             // read Windows image header
104             FS.Position := HdrOffset + SizeOf(LongWord);
105             FS.ReadBuffer(ImgHdrPE, SizeOf(ImgHdrPE));
106             if (ImgHdrPE.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then
107               // characteristics indicate a 32 bit DLL
108               Result := fkDLL32
109             else
110               // characteristics indicate a 32 bit application
111               Result := fkExe32;
112           end;
113         cNEMagic:
114           begin
115             // We have 16 bit Windows executable: check whether app or DLL
116             if FS.Size <= HdrOffset + cNEAppTypeOffset + SizeOf(AppFlagsNE) then
117               // app flags field would be beyond EOF: assume DOS
118               Exit;
119             // read app flags byte
120             FS.Position := HdrOffset + cNEAppTypeOffset;
121             FS.ReadBuffer(AppFlagsNE, SizeOf(AppFlagsNE));
122             if (AppFlagsNE and cNEDLLFlag) = cNEDLLFlag then
123               // app flags indicate DLL
124               Result := fkDLL16
125             else
126               // app flags indicate program
127               Result := fkExe16;
128           end;
129       else
130         // DOS application
131         {Do nothing - DOS result already set};
132       end;
133     finally
134       FS.Free;
135     end;
136   except
137     // Exception raised in function => error result
138     Result := fkError;
139   end;
140 end;


So there we have it -- a function to return the file type of an executable file. If 
you have any suggestions then please contact 

Worked Example

A worked example is available for download from my website. This example includes the ExeType function, along with a Delphi 4 project that exercises it.

Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10


Share this page
Download from Google

Copyright © Mendozi Enterprises LLC