2014-02-12 29 views
5

我在更改可执行文件的版本信息中的内部版本号(VersionLS的低版本)。因此,我应该阅读VS_VERSIONINFO结构,更改内部版本号,然后将其更新回PE。在可执行文件中更改内部版本号

我使用此代码作为基础工作:https://stackoverflow.com/a/7999813/1970843。此代码非常适用于更改VS_FIXEDFILEINFO数据,但它不会更改(或访问)StringFileInfo信息。

我敢肯定,我应该包括在VERSIONHEADER包装记录添加VS_VERSIONINFO的儿童进入的东西,但我不知道究竟是如何做到这一点。这是我到目前为止有:

type 
    StringStruc = Packed Record 
     wLength: Word; 
     wValueLength: Word; 
     wType: Word; 
     //szKey: ?; 
     //Value: ?; 
    End; 

    StringTable = Packed Record 
     wLength: Word; 
     wValueLength: Word; 
     wType: Word; 
     szKey: Array[0..8] Of WideChar; 
     Children: StringStruc; 
    End; 

    StringFileInfo = Packed Record 
     wLength: Word; 
     wValueLength: Word; 
     wType: Word; 
     szKey: Array[0..14] Of WideChar; // 'STRINGFILEINFO' 
     Children: StringTable; 
    End; 

    VERSIONHEADER = Packed Record 
     wLength: Word; 
     wValueLength: Word; 
     wType: Word; 
     szKey: Array[0..16] Of WideChar; // 'VS_VERSION_INFO' 
     Version: VS_FIXEDFILEINFO; 
     Children: StringFileInfo; 
    End; 

... 

var VersionHandle, VersionRes: THandle; 
    VersionSize: Cardinal; 
    Version: Array Of AnsiChar; 
    Ver: ^VERSIONHEADER; 
Begin 
    VersionSize := GetFileVersionInfoSize(PChar(sExe), VersionHandle); 

    SetLength(Version, VersionSize); 
    Ver := Pointer(Version); 
    GetFileVersionInfo(PChar(sExe), 0, VersionSize, Ver); 

因此,信息似乎是正确上来的第一StringStruc。但由于szKey和Value都不是固定大小,我不知道如何正确定义我的Packed Record(甚至有可能?)来获取这些值。我也遇到了阵列的麻烦......我怎么定义它们?我正在做的方式,我只是得到每个Struc上的第一个孩子。请注意,我忽略了衬垫......这可以吗?

任何帮助表示赞赏。我在这里所做的大部分工作都是通过试验和错误,所以我不太明白发生了什么。

PS:我仍然在做这个,所以我可能会经常更新这个帖子。

+0

也许我应该尝试读取内存作为原始二进制数据?当我找到我想要改变的东西时,我需要更新每个父母的信息和大小,并根据需要重新分配内存......听起来很难。 – GabrielF

+1

对于一个项目,我试图改变StringFileInfo,但它远不是明显的,AFAIR。因此,我坚持改变数字信息(代码已经链接到你的问题:)),并在字符串字段中放置一个通用文本。重要的是“关于”框和启动画面(从数字字段提取)中显示的内容,以及如果文件属性给出确切的(数字)“文件版本”(例如2.1.231),但更通用的是“产品版本“(例如”2“或”2.1“) - 对我来说足够了。 –

+0

你不能用'BeginUpdateResource'等来做吗? –

回答

1

我很感谢您的关注和帮助。我在这里找到了一个现成的解决方案。事实上,这是在我对这个问题的评论中(我对此感到羞耻!)。

它是基于由Colin Wilson库。它使用指针算法来提取和写入信息,所以,很难(也许是唯一)的方式。关于如何使用Jason Penny的图书馆还有一个很好的例子:SetVersion。由于我使用的是D7,我从网上下载here科林·威尔逊的库(下资源工具),但较新的版本,使用的UnicodeString和更好的指针运算,可here

这是实际执行我现在有:

uses ..., unitResourceVersionInfo, unitPEFile; 

... 

var VersionInfo: TVersionInfoResourceDetails; 
    PEResModule: TPEResourceModule; 
    VersionNumber: ULARGE_INTEGER; 
    sVersion: String; 
    I: Integer; 
Begin 
    PEResModule := TPEResourceModule.Create; 
    Try 
     PEResModule.LoadFromFile(sExe); 

     For I := 0 To PEResModule.ResourceCount - 1 Do Begin 
      If PEResModule.ResourceDetails[I] Is TVersionInfoResourceDetails Then Begin 
       VersionInfo := (PEResModule.ResourceDetails[I] As TVersionInfoResourceDetails); 
       Break; 
      End; 
     End; 

     VersionNumber.LowPart := MakeLong(NewBuildNumber, HiWord(VersionInfo.FileVersion.LowPart)); 
     VersionNumber.HighPart := VersionInfo.FileVersion.HighPart; 
     VersionInfo.FileVersion := VersionNumber; 
     VersionInfo.ProductVersion := VersionNumber; 

     VersionInfo.CodePage := $04e4; 

     sVersion := Format('%d.%d.%d.%d', [HiWord(VersionInfo.FileVersion.HighPart), LoWord(VersionInfo.FileVersion.HighPart), HiWord(VersionInfo.FileVersion.LowPart), LoWord(VersionInfo.FileVersion.LowPart)]); 
     VersionInfo.SetKeyValue('FileVersion', sVersion); 

     PEResModule.SaveToFile(ChangeFileExt(sExe, '.exe2')); 

    Finally 
     FreeAndNil(PEResModule); 
    End; 
End; 

代码页行是由于在库中的错误(我相信这是)。它不会读取代码页(自带0),所以,当你救回来,它显示为0。

相关问题