uses System.SysUtils, System.Classes, Winapi.Windows; type TExeType = ( etUnknown, // unknown file kind: not an executable etError, // error file kind: used for files that don't exist etDOS, // DOS executable etExe32, // 32 bit executable etExe16, // 16 bit executable etDLL32, // 32 bit DLL etDLL16, // 16 bit DLL etVXD, // virtual device driver etExe64, // 64 bit executable etDLL64, // 64 bit DLL etROM // ROM image (PE format) ); function ExeType(const FileName: string): TExeType; function ExeType(const FileName: string): TExeType; const cWinHeaderOffset = $3C; // offset of "pointer" to windows header in file cNEAppTypeOffset = $0D; // offset in NE windows header app type field cDOSMagic = $5A4D; // magic number identifying a DOS executable cNEMagic = $454E; // magic number identifying a NE executable (Win 16) cPEMagic = $4550; // magic nunber identifying a PE executable (Win 32) cLEMagic = $454C; // magic number identifying a Virtual Device Driver cNEDLLFlag = $80; // flag in NE app type field indicating a DLL cPEDLLFlag = $2000; // flag in PE Characteristics field indicating s DLL cPE32Magic = $10B; // magic number identifying 32 bit PE executable cPE64Magic = $20B; // magic number identifying 64 bit executable cPEROMMagic = $107; // magic number identifying ROM image var FS: TFileStream; // stream onto executable file WinMagic: Word; // word that contains PE/NE/LE magic #s HdrOffset: LongInt; // offset of windows header in exec file DOSHeader: IMAGE_DOS_HEADER; // DOS header record PEFileHdr: IMAGE_FILE_HEADER; // PE file header record PEOptHdrMagic: Word; // PE "optional" header magic # AppFlagsNE: Byte; // byte defining DLLs in NE format DOSFileSize: Integer; // size of DOS file IsPEDLL: Boolean; // whether PE file is DLL begin try // Open stream onto file: raises exception if can't be read FS := TFileStream.Create( FileName, fmOpenRead + fmShareDenyNone ); try // Assume unkown file Result := etUnknown; // Any exec file is at least size of DOS header long if FS.Size < SizeOf(DOSHeader) then Exit; FS.ReadBuffer(DOSHeader, SizeOf(DOSHeader)); // DOS files begin with "MZ" if DOSHeader.e_magic <> cDOSMagic then Exit; // DOS files have length >= size indicated at offset $02 and $04 // (offset $02 indicates length of file mod 512 and offset $04 indicates // no. of 512 pages in file) if (DOSHeader.e_cblp = 0) then DOSFileSize := DOSHeader.e_cp * 512 else DOSFileSize := (DOSHeader.e_cp - 1) * 512 + DOSHeader.e_cblp; if FS.Size < DOSFileSize then Exit; // DOS file relocation offset must be within DOS file size. if DOSHeader.e_lfarlc > DOSFileSize then Exit; // We know we have an executable file: assume its a DOS program Result := etDOS; // Try to find offset of Windows program header if FS.Size <= cWinHeaderOffset + SizeOf(LongInt) then // file too small for windows header "pointer": it's a DOS file Exit; // read it FS.Position := cWinHeaderOffset; FS.ReadBuffer(HdrOffset, SizeOf(LongInt)); // Now try to read first word of Windows program header if FS.Size <= HdrOffset + SizeOf(Word) then // file too small to contain header: it's a DOS file Exit; FS.Position := HdrOffset; // This word should be NE, PE or LE per file type: check which FS.ReadBuffer(WinMagic, SizeOf(Word)); case WinMagic of cPEMagic: begin // 'PE' signature followed by to 0 bytes FS.ReadBuffer(WinMagic, SizeOf(Word)); if WinMagic <> 0 then Exit; // 32 or 64 bit Windows application: now check whether app or DLL // by reading file header record and checking Characteristics field if FS.Size < HdrOffset + SizeOf(LongWord) + SizeOf(PEFileHdr) + SizeOf(PEOptHdrMagic) then Exit; FS.Position := HdrOffset + SizeOf(LongWord); FS.ReadBuffer(PEFileHdr, SizeOf(PEFileHdr)); IsPEDLL := (PEFileHdr.Characteristics and cPEDLLFlag) = cPEDLLFlag; // check if 32 bit, 64 bit (or ROM) by reading Word value following // file header (actually this is first field of "optional" PE header) // read magic number at start of "optional" PE header that follows FS.ReadBuffer(PEOptHdrMagic, SizeOf(PEOptHdrMagic)); case PEOptHdrMagic of cPE32Magic: if IsPEDLL then Result := etDLL32 else Result := etExe32; cPE64Magic: if IsPEDLL then Result := etDLL64 else Result := etExe64; cPEROMMagic: Result := etROM; else Result := etUnknown; // unknown PE magic number end; end; cNEMagic: begin // We have 16 bit Windows executable: check whether app or DLL if FS.Size <= HdrOffset + cNEAppTypeOffset + SizeOf(AppFlagsNE) then // app flags field would be beyond EOF: assume DOS Exit; // read app flags byte FS.Position := HdrOffset + cNEAppTypeOffset; FS.ReadBuffer(AppFlagsNE, SizeOf(AppFlagsNE)); if (AppFlagsNE and cNEDLLFlag) = cNEDLLFlag then // app flags indicate DLL Result := etDLL16 else // app flags indicate program Result := etExe16; end; cLEMagic: // We have a Virtual Device Driver Result := etVXD; else // DOS application {Do nothing - DOS result already set}; end; finally FS.Free; end; except // Exception raised in function => error result Result := etError; end; end;
Formda Kullanımı
System.Rtti
procedure TfrmMain.btnGetExeTypeClick(Sender: TObject); var OpenDialog:TOpenDialog; begin OpenDialog := TOpenDialog.Create(Self); try if OpenDialog.Execute then begin ShowMessage(TRttiEnumerationType.GetName(ExeType(OpenDialog.FileName))); end; finally OpenDialog.Free; end; end;