Browse Source

* More flexible fileinfo unit (bug 17252)

git-svn-id: trunk@17753 -
michael 14 years ago
parent
commit
9d5e446914
1 changed files with 130 additions and 69 deletions
  1. 130 69
      packages/fcl-base/src/win/fileinfo.pp

+ 130 - 69
packages/fcl-base/src/win/fileinfo.pp

@@ -15,6 +15,12 @@
 
 
  Based on getver by Bernd Juergens - Munich, Germany
  Based on getver by Bernd Juergens - Munich, Germany
  email :[email protected]
  email :[email protected]
+ 
+ reworked by Stoian Ivanov ([email protected])
+     Added ExtraVersionStrings,TryHardcodedTrans.
+     Using VersionCategories.Objects as TransID storage,
+     which is used later by getVersionSetting
+
 
 
  Usage : Drop component on form. Set desired file name using
  Usage : Drop component on form. Set desired file name using
          FileVersionInfo.filename := 'c:\winnt\system32\comctl32.dll'
          FileVersionInfo.filename := 'c:\winnt\system32\comctl32.dll'
@@ -26,7 +32,9 @@
          showMessage(FileVersionInfo1.getVersionSetting('ProductVersion'));
          showMessage(FileVersionInfo1.getVersionSetting('ProductVersion'));
 }
 }
 unit fileinfo;
 unit fileinfo;
+
 {$mode objfpc}
 {$mode objfpc}
+{$h+}
 interface
 interface
 
 
 uses
 uses
@@ -35,28 +43,39 @@ uses
 
 
 { Record to receive charset }
 { Record to receive charset }
 type TTranslation = record
 type TTranslation = record
-   langID  : WORD;
-   charset  : WORD;
+  case byte of 
+   1: (langID,charset  : WORD);
+   2: (transid:Dword);
 end;
 end;
 
 
+PTranslation=^TTranslation;
+
 type
 type
+  { TFileVersionInfo }
+
   TFileVersionInfo = class(TComponent)
   TFileVersionInfo = class(TComponent)
   private
   private
     FFileName : String;
     FFileName : String;
     FmyVersionStrings : TStringList;
     FmyVersionStrings : TStringList;
-    FmyVersionCategories    : TStringList;
+    FmyVersionCategories : TStringList;
 
 
-    procedure SetFileName (inp : string);
+    FmyExtraVersionStrings :TStringList;
+    FmyTryHardcodedTrans :TStringList;
+  
+    procedure SetFileName (Const inp : string);
     procedure readVersionFromFile;
     procedure readVersionFromFile;
-  protected
   public
   public
-     constructor Create(AOwner: TComponent);  override;
-     destructor Destroy; override;
-     function getVersionSetting(inp : string): String;
+    constructor Create(AOwner: TComponent);  override;
+    destructor Destroy; override;
+    procedure AddExtraVersionString (Const extrafield:string);
+    procedure AddTryHardcodedTrans (Const hardtrans:string);
+    function getVersionSetting(Const inp : string; transid:dword=0): String;
   published
   published
     property fileName : string  read FFileName write SetFileName;
     property fileName : string  read FFileName write SetFileName;
     property VersionStrings  : TStringList  read FmyVersionStrings;
     property VersionStrings  : TStringList  read FmyVersionStrings;
     property VersionCategories : TStringList read FmyVersionCategories;
     property VersionCategories : TStringList read FmyVersionCategories;
+    property ExtraVersionStrings : TStringList read FmyExtraVersionStrings;
+    property TryHardcodedTrans :TStringList read FmyTryHardcodedTrans;
   end;
   end;
 
 
 implementation
 implementation
@@ -67,7 +86,13 @@ constructor TFileVersionInfo.Create(AOwner: TComponent);
 begin
 begin
   inherited Create(AOwner);
   inherited Create(AOwner);
   FmyVersionStrings := TStringList.Create;
   FmyVersionStrings := TStringList.Create;
+  FmyVersionStrings.Duplicates:=dupAccept;
   FmyVersionCategories  := TStringList.Create;
   FmyVersionCategories  := TStringList.Create;
+  FmyVersionCategories.Duplicates:=dupAccept;
+  FmyExtraVersionStrings := TStringList.Create;
+  FmyExtraVersionStrings.Duplicates:= dupIgnore;
+  FmyTryHardcodedTrans:=TStringList.Create;
+  FmyTryHardcodedTrans.Duplicates:=dupIgnore;
   FFileName := '';
   FFileName := '';
 end;
 end;
 
 
@@ -75,42 +100,56 @@ destructor TFileVersionInfo.Destroy;
 begin
 begin
   FmyVersionCategories.Free;
   FmyVersionCategories.Free;
   FmyVersionStrings.Free;
   FmyVersionStrings.Free;
+  FmyExtraVersionStrings.Free;
+  FmyTryHardcodedTrans.free;
   inherited;
   inherited;
 end;
 end;
 
 
-{ Get filename, check if file exists and read info from file }
-procedure TFileVersionInfo.SetFileName (inp : string);
+{if you need other version strings extracted you add them here}
+procedure TFileVersionInfo.AddExtraVersionString(Const extrafield: string); 
 begin
 begin
-    FmyVersionStrings.clear;
-    FmyVersionCategories.clear;
+  FmyExtraVersionStrings.add (extrafield);
+end;
 
 
-    if fileexists(inp) then
+{some broken DLLs report wrong translations and you need to try some hardcoded transes
+like NPSWF32.dll reports 040904b0(English/Unicode) but they are actualy 040904E4 (English/Latin1)}
+procedure TFileVersionInfo.AddTryHardcodedTrans(Const hardtrans: string);
+begin
+  FmyTryHardcodedTrans.add(hardtrans);
+end;
+
+{ Get filename, check if file exists and read info from file }
+procedure TFileVersionInfo.SetFileName (Const inp : string);
+begin
+  FmyVersionStrings.clear;
+  FmyVersionCategories.clear;
+  if FileExists(inp) then
     begin
     begin
-         FFileName := inp;
-         readVersionFromFile;
+    FFileName := inp;
+    readVersionFromFile;
     end
     end
-    else
-    begin
-         FFileName := '';
-    end;
+  else
+    FFileName := '';
 end;
 end;
 
 
 { read info from file }
 { read info from file }
 procedure TFileVersionInfo.readVersionFromFile;
 procedure TFileVersionInfo.readVersionFromFile;
-var struSize : Dword;
-    dwBytes,someDummy : Dword;
-    a,txt : array[0..256] of char;
-    p : pchar;
-    i : integer;
-    pp : pointer;
-    theFixedInfo : TVSFixedFileInfo;
-    theTrans : TTranslation;
-    s : string;
-    ts  : TStringList;
+var
+  struSize : Dword;
+  dwBytes : Dword;
+  dwTransBytes:Dword;
+  vi : pointer;
+  ti,i,hti : integer;
+  pp : pointer;
+  theTrans : PTranslation;
+  s : string;
+  ts  : TStringList;
+  transstr:String;
+  //s_w : Widestring; //urf or not really does not matter
 begin
 begin
   ts := TStringList.Create;
   ts := TStringList.Create;
   try
   try
-    ts.add('Comments');
+    ts.Assign(FmyExtraVersionStrings);
     ts.add('CompanyName');
     ts.add('CompanyName');
     ts.add('FileDescription');
     ts.add('FileDescription');
     ts.add('FileVersion');
     ts.add('FileVersion');
@@ -119,58 +158,80 @@ begin
     ts.add('OriginalFilename');
     ts.add('OriginalFilename');
     ts.add('ProductName');
     ts.add('ProductName');
     ts.add('ProductVersion');
     ts.add('ProductVersion');
-
-    strPCopy(a,FFileName);
-    { get size of data }
-    struSize := GetFileVersionInfoSize(a,@someDummy);
+    struSize := GetFileVersionInfoSize(Pchar(FFileName),nil);
     if struSize=0 then exit;
     if struSize=0 then exit;
-    p := NIL;
+    vi := NIL;
+    { get memory }
+    GetMem(vi,struSize+10);
     try
     try
-      { get memory }
-      GetMem(p,struSize+10);
+      if (vi=nil) then
+        exit;
       { get data }
       { get data }
-      if not GetFileVersionInfo(a,0,struSize,p) then exit;
-      { get root info }
-      if not VerQueryValue(p,'\',pp,dwBytes) then exit;
-      move(pp^,theFixedInfo,dwBytes);
-
+      if not GetFileVersionInfo(PChar(FFileName),0,struSize,vi) then
+        exit;
       { get translation info }
       { get translation info }
-      if not VerQueryValue(p,'\VarFileInfo\Translation',pp,dwBytes) then
+      if not VerQueryValue(vi,'\VarFileInfo\Translation',theTrans,dwTransBytes) then 
         exit;
         exit;
-      move(pp^,theTrans,dwBytes);
-
-      { iterate over defined items }
-      for i:=0 to ts.count-1 do
-      begin
-        s := '\StringFileInfo\'+inttohex(theTrans.langID,4)+inttohex(theTrans.charset,4)+'\'+ts[i];
-        StrPCopy(a,s);
-        if not VerQueryValue(p,a,pp,dwBytes) then Continue;
-        if dwBytes>0 then
+      while (dwTransBytes>=sizeof(TTranslation)) do 
         begin
         begin
-         move(pp^,txt,dwBytes);
-         FmyVersionCategories.add(ts[i]);
-         FmyVersionStrings.add(StrPas(txt));
-        end
-      end;
+        transstr:=inttohex(theTrans^.langID,4)+inttohex(theTrans^.charset,4);
+        { iterate over defined items }
+        for i:=0 to ts.count-1 do 
+          begin
+          s:='\StringFileInfo\'+transstr+'\'+ts[i]+#0;
+          if not VerQueryValue(vi,@s[1],pp,dwBytes) then continue;
+          if dwBytes>0 then 
+            begin
+            SetLength(s,dwBytes-1);
+            move(pp^,s[1],dwBytes-1);
+            FmyVersionCategories.AddObject(LowerCase(ts[i]),TObject(pointer(theTrans^.transid)));
+            FmyVersionStrings.add(s);
+            end
+          end;
+        inc (theTrans);
+        dec (dwTransBytes,sizeof(TTranslation));
+        end;
+        
+      {Now with the dirty hardcoded hack}
+      for hti:=0 to FmyTryHardcodedTrans.Count-1 do 
+        begin
+        transstr:=FmyTryHardcodedTrans[hti];
+        for i:=0 to ts.count-1 do 
+          begin
+          s := '\StringFileInfo\'+transstr+'\'+ts[i]+#0;
+          if VerQueryValue(vi,@s[1],pp,dwBytes) and (dwbytes>0) then
+            begin
+            SetLength(s,dwBytes-1);
+            move(pp^,s[1],dwBytes-1);
+            FmyVersionCategories.AddObject(LowerCase(ts[i]),TObject(pointer(theTrans^.transid)));
+            FmyVersionStrings.add(s);
+            end
+          end;
+        end;
     finally
     finally
-      { release memory }
-      FreeMem(p);
-    end;
-  finally ts.Free end;
+      FreeMem(vi);
+    end;  
+  Finally  
+    ts.Free
+  end;  
 end;
 end;
 
 
 { get single version string }
 { get single version string }
-function TFileVersionInfo.getVersionSetting(inp : string): String;
-var i : integer;
+function TFileVersionInfo.getVersionSetting(Const inp : string; transid:dword=0): String;
+var
+  i : integer;
+  s,v : string;
 begin
 begin
-  inp:=LowerCase(inp);
-  for i:= 0 to FmyVersionCategories.Count -1 do
-    if LowerCase(FmyVersionCategories[i])=inp then
+  s:=LowerCase(inp);
+  I:=0;
+  Result:='';
+  While (Result='') and (i<FmyVersionCategories.Count -1) do
     begin
     begin
-      result := FmyVersionStrings[i];
-      Exit;
+    V:=FmyVersionCategories[i];
+    if (V=S) and ((transid=0) or (transid=dword(pointer(FmyVersionCategories.Objects[i])))) then
+      Result:=V;
+    inc(I);
     end;
     end;
-  result := '';
 end;
 end;
 
 
 end.
 end.