How to detect Delphi compiler version in which exe was compiled?
You can use this source to give you the Assembly information. In the main assembly, you can see the Name and Version, which will give you the Compiler's name and version. It is a console application where param 1 is the exe file.
The version can be checked here:
http://wiki.delphi-jedi.org/wiki/JEDI_Help:CompilerVersions
to see which version it was vbuild with; i.e.,
12.xxxx - Delphi 2009 and 15.xxxx - Delphi XE
However, this only works up to XE. With XE2, things have changed in the exe.
program versionchk;
{$APPTYPE CONSOLE}
uses
ActiveX,
Classes,
Windows,
Variants,
ComObj,
StrUtils,
SysUtils;
type
TAssemblyIdentity=record
&type : string;
name : string;
language: string;
processorArchitecture : string;
version : string;
publicKeyToken: string;
end;
TRequestedExecutionLevel=record
level : string;
uiAccess : string;
end;
TManifiestReader=class
private
FFileName: string;
FManifest: AnsiString;
FMainAssemblyIdentity: TAssemblyIdentity;
FHasManifest: Boolean;
FDependentAssembly: TAssemblyIdentity;
FManifestVersion: string;
FRequestedExecutionLevel: TRequestedExecutionLevel;
procedure GetManifest;
procedure LoadManifestData;
function VarNullToStr(Value:OleVariant):string;
public
property FileName : string read FFileName;
property Manifest : AnsiString read FManifest;
property ManifestVersion : string read FManifestVersion;
property MainAssemblyIdentity : TAssemblyIdentity read FMainAssemblyIdentity;
property DependentAssembly : TAssemblyIdentity read FDependentAssembly;
property HasManifest : Boolean read FHasManifest;
property RequestedExecutionLevel : TRequestedExecutionLevel read FRequestedExecutionLevel;
constructor Create(const AFileName:string);
end;
{ TReadManifiest }
constructor TManifiestReader.Create(const AFileName: string);
begin
FFileName:=AFileName;
FHasManifest:=False;
GetManifest;
LoadManifestData;
end;
procedure TManifiestReader.GetManifest;
var
hModule : THandle;
Resource : TResourceStream;
begin
FManifest:='';
hModule:=LoadLibraryEx(PChar(FileName),0,LOAD_LIBRARY_AS_DATAFILE);
try
if hModule=0 then RaiseLastOSError;
if FindResource(hModule, MakeIntResource(1), RT_MANIFEST)<>0 then
begin
Resource:=TResourceStream.CreateFromID(hModule,1,RT_MANIFEST);
try
SetString(FManifest, PAnsiChar(Resource.Memory),Resource.Size);
FHasManifest:=True;
finally
Resource.Free;
end;
end;
finally
FreeLibrary(hModule);
end;
end;
procedure TManifiestReader.LoadManifestData;
const
assembly_namespace_V1='urn:schemas-microsoft-com:asm.v1';
assembly_namespace_V2='urn:schemas-microsoft-com:asm.v2';
assembly_namespace_V3='urn:schemas-microsoft-com:asm.v3';
var
XmlDoc : OleVariant;
ns : string;
Node : OleVariant;
begin
if Trim(FManifest)='' then exit;
XmlDoc := CreateOleObject('Msxml2.DOMDocument.6.0');
XmlDoc.Async := False;
try
XmlDoc.LoadXML(FManifest);
XmlDoc.SetProperty('SelectionLanguage','XPath');
if (XmlDoc.parseError.errorCode <> 0) then
raise Exception.CreateFmt('Error in Xml Data %s',[XmlDoc.parseError]);
//set the namespaces alias
ns := Format('xmlns:a=%s xmlns:b=%s xmlns:c=%s',[QuotedStr(assembly_namespace_V1),QuotedStr(assembly_namespace_V2),QuotedStr(assembly_namespace_V3)]);
XmlDoc.setProperty('SelectionNamespaces', ns);
//get the version of the manifest
Node:=XmlDoc.selectSingleNode('/a:assembly/@manifestVersion');
if not VarIsNull(Node) and not VarIsClear(Node) then
FManifestVersion:=Node.text;
Node:=XmlDoc.selectSingleNode('/a:assembly/a:assemblyIdentity');
if not VarIsNull(Node) and not VarIsClear(Node) then
begin
FMainAssemblyIdentity.&type :=Node.getAttribute('type');
FMainAssemblyIdentity.name :=Node.getAttribute('name');
FMainAssemblyIdentity.language:=VarNullToStr(Node.getAttribute('language'));
FMainAssemblyIdentity.version :=Node.getAttribute('version');
FMainAssemblyIdentity.processorArchitecture:=VarNullToStr(Node.getAttribute('processorArchitecture'));
FMainAssemblyIdentity.publicKeyToken :=VarNullToStr(Node.getAttribute('publicKeyToken'));
end;
Node:=XmlDoc.selectSingleNode('/a:assembly/a:dependency/a:dependentAssembly/a:assemblyIdentity');
if not VarIsNull(Node) and not VarIsClear(Node) then
begin
FDependentAssembly.&type :=Node.getAttribute('type');
FDependentAssembly.name :=Node.getAttribute('name');
FDependentAssembly.language:=VarNullToStr(Node.getAttribute('language'));
FDependentAssembly.version :=Node.getAttribute('version');
FDependentAssembly.processorArchitecture:=VarNullToStr(Node.getAttribute('processorArchitecture'));
FDependentAssembly.publicKeyToken :=VarNullToStr(Node.getAttribute('publicKeyToken'));
end;
Node:=XmlDoc.selectSingleNode('/a:assembly/b:trustInfo/b:security/b:requestedPrivileges/b:requestedExecutionLevel');
if VarIsNull(Node) or VarIsClear(Node) then
Node:=XmlDoc.selectSingleNode('/a:assembly/c:trustInfo/c:security/c:requestedPrivileges/c:requestedExecutionLevel');
if not VarIsNull(Node) and not VarIsClear(Node) then
begin
FRequestedExecutionLevel.level :=Node.getAttribute('level');
FRequestedExecutionLevel.uiAccess:=VarNullToStr(Node.getAttribute('uiAccess'));
end;
finally
XmlDoc:=Unassigned;
end;
end;
function TManifiestReader.VarNullToStr(Value: OleVariant): string;
begin
if VarIsNull(Value) then
Result:=''
else
Result:=VarToStr(Value);
end;
Var
ManifestReader : TManifiestReader;
begin
try
CoInitialize(nil);
try
ManifestReader:=TManifiestReader.Create(ParamStr(1));
try
//Writeln(ManifestReader.Manifest);
Writeln('Manifest version '+ManifestReader.ManifestVersion);
Writeln('Main Assembly Identity');
Writeln('----------------------');
Writeln('type '+ManifestReader.MainAssemblyIdentity.&type);
Writeln('name '+ManifestReader.MainAssemblyIdentity.name);
Writeln('language '+ManifestReader.MainAssemblyIdentity.language);
Writeln('version '+ManifestReader.MainAssemblyIdentity.version);
Writeln('processorArchitecture '+ManifestReader.MainAssemblyIdentity.processorArchitecture);
Writeln('publicKeyToken '+ManifestReader.MainAssemblyIdentity.publicKeyToken);
Writeln('');
Writeln('Dependent Assembly Identity');
Writeln('---------------------------');
Writeln('type '+ManifestReader.DependentAssembly.&type);
Writeln('name '+ManifestReader.DependentAssembly.name);
Writeln('language '+ManifestReader.DependentAssembly.language);
Writeln('version '+ManifestReader.DependentAssembly.version);
Writeln('processorArchitecture '+ManifestReader.DependentAssembly.processorArchitecture);
Writeln('publicKeyToken '+ManifestReader.DependentAssembly.publicKeyToken);
Writeln('');
Writeln('Requested Execution Level');
Writeln('---------------------------');
Writeln('level '+ManifestReader.RequestedExecutionLevel.level);
Writeln('uiAccess '+ManifestReader.RequestedExecutionLevel.uiAccess);
finally
ManifestReader.Free;
end;
finally
CoUninitialize;
end;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Readln;
end.
Download the various files for the IDR (Interactive Delphi Reconstructor), extract them to a folder and run it. Load your compiled executable inside IDR and it'll tell you what version the executable was compiled in (has proven accurate for me).
Alternative solution:
Open your compiled executable in XN Resource Editor. Under "RC Data" in the tree you will find DVCLAL. Expand it and select "Language Neutral". You will now see a nonsense string with an equally meaningless HEX equivalent.
This HEX actually identifies the compiler version on which the executable was built. You can Google this HEX with the word Delphi, and you should be quite quickly able to determine what compiler the HEX came from.
Enjoy!