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!