Create new Version Info resource at runtime

I need to create a version info resource, I know how to update resources, just not how the Version info type should look.

Does any one have an example or the Version info records.
LVL 2
heretoreadAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mark BradyPrincipal Data EngineerCommented:
Can you explain more about what you want ?  Do you want your program to read an inf file and take the version information from this file and use it somewhere in your program ?  If so then this is simple.
I assume you have an inf text file somewhere on your PC.  Just have the program load it on formcreate proc and read the version number to a string then assing the string value to a tlabel or something similar...ie:  the form title.

Elvin
heretoreadAuthor Commented:
Show the Properties of an exe file in explorer, Click on the version tab (If the exe has one) and notice version information.

i want to create and add a version resource to an exe.
Mark BradyPrincipal Data EngineerCommented:
ok
You need to add a version resource to your project. Basically, this is a file with the ending .rc that contains

///////////////////////////////////////////////////////////////////////
//
// Version
//

VS_VERSION_INFO VERSIONINFO
 FILEVERSION 1,0,0,1
 PRODUCTVERSION 1,0,0,1
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x4L
 FILETYPE 0x1L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "Comments", "Sample Application\0"
            VALUE "CompanyName", "Microsoft Corp.\0"
            VALUE "FileDescription", "MyProject MFC Application\0"
            VALUE "FileVersion", "1, 0, 0, 1\0"
            VALUE "InternalName", "MyProject\0"
            VALUE "LegalCopyright", "Copyright (C) 1999\0"
            VALUE "OriginalFilename", "MyProject.EXE\0"
            VALUE "ProductName", "MyProject Application\0"
            VALUE "ProductVersion", "1, 0, 0, 1\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END
     
(edit the above to reflect your situation)
OWASP: Threats Fundamentals

Learn the top ten threats that are present in modern web-application development and how to protect your business from them.

heretoreadAuthor Commented:
I'm trying todo it without the aid of a resource compiler, I'm want to add this functionality to a small setup program i made.

So a user can choose there own parameters which then gets appended to the stub.
Slick812Commented:
hello heretoread , , I have done some file building, and I really beleive that to create a Compiled Res file would take some serious hard work, with file analysis, block DWord alignment,  just look at a  .RES file for a program Version in your Hex Editor. It seems like a difficult thing, , especially for 90 points. Do you have any experience at building complex files data block by data block? Maybe you may can use the brcc32.exe for this.
heretoreadAuthor Commented:
i have tried to analyse it, I'm able to get some info,  But iv'e never done block dword alignment etc.

90 was all the points i had at time of posting, are you able to help me, i can increase them if you can.
Slick812Commented:
??
Not sure I have the time to do this kind of thing ? Even if I did take the time, I doubt you could understand the code and be able to modify it to your uses since you do not have any file building experience. I have spent a few days already, looking for info on how a Resource file structure is arranged, and something about how and why the "VERSIONINFO" resource is stuctured, here is some info for you

the Resource  .RES  file uses this data Block Header -

type

  TResDataHeader = packed record
    DataSize, HeaderSize, ResType, ResID, DataVersion: Cardinal;
    MemoryFlags, LanguageId: Word;
    Version, Characteristics: Cardinal;
    end;



and  the "VERSIONINFO" resource has a definition stucture as this -


type

  PVSFixedFileInfo = ^TVSFixedFileInfo;
  {$EXTERNALSYM tagVS_FIXEDFILEINFO}
  tagVS_FIXEDFILEINFO = packed record
    dwSignature: DWORD;        { e.g. $feef04bd }
    dwStrucVersion: DWORD;     { e.g. $00000042 = "0.42" }
    dwFileVersionMS: DWORD;    { e.g. $00030075 = "3.75" }
    dwFileVersionLS: DWORD;    { e.g. $00000031 = "0.31" }
    dwProductVersionMS: DWORD; { e.g. $00030010 = "3.10" }
    dwProductVersionLS: DWORD; { e.g. $00000031 = "0.31" }
    dwFileFlagsMask: DWORD;    { = $3F for version "0.42" }
    dwFileFlags: DWORD;        { e.g. VFF_DEBUG | VFF_PRERELEASE }
    dwFileOS: DWORD;           { e.g. VOS_DOS_WINDOWS16 }
    dwFileType: DWORD;         { e.g. VFT_DRIVER }
    dwFileSubtype: DWORD;      { e.g. VFT2_DRV_KEYBOARD }
    dwFileDateMS: DWORD;       { e.g. 0 }
    dwFileDateLS: DWORD;       { e.g. 0 }
  end;
  TVSFixedFileInfo = tagVS_FIXEDFILEINFO;
  VS_FIXEDFILEINFO = tagVS_FIXEDFILEINFO;


maybe these can help you
heretoreadAuthor Commented:
I managed to analyse the version info resource using PE Explorer and HexWorkshop.

I'm now able to create a Version Resource header and add strings.
Slick812Commented:
I have been been working on this for 5 or 6 days in what time I have available, I have looked at a Hex Editor and counted and compared byte values until I am blubbering. . . I have a makeshift file builder, but There are several aspects (the rules for info strings to be single or double null terminated, with the data block DWord aligned) that still escape me, , Either the brcc32.exe is inconsistent in it's res file string analysis, or there is some factor I am to dumb to determine. . . . This is probally the most difficult and frustrating thing I have ever tried to do here at EE
heretoreadAuthor Commented:
i know how you feel, Took me 2 days to figre it out, Every change i thought was right took me back.

The single or null terminated strings had me going nuts, I might have got this wrong but it works.

if (Length(Key) + 1) * 2 mod 4 <> 0 then
  //Double null.
Slick812Commented:
no, that's not what I'm talking about.  I have no trouble with that. . .
The brcc32.exe will sometimes use -
 'OriginalFilename'#0#0

and other times use -
 'OriginalFilename'#0

and it seems to NOT depend only on the "VALUE" string length, which I have set at an even number of charaters, and an odd number of charaters, , it seems to be inconsistant, sometimes it will double null terminate BOTH strings, and sometimes it will not, , makes no sense to me
Slick812Commented:
Here is some code for .RES file creation that is in a button click, , , that seems to work, at least most of the time. I have no more left in me to try and figure out the inconsistancies of the brcc32.exe and version res compiling, I now feel that the double null termination of both strings is not nessary, , but what do I know.
I hope this is enough for you.


type

  TResDataHeader = packed record
    DataSize, HeaderSize, ResType, ResID, DataVersion: Cardinal;
    MemoryFlags, LanguageId: Word;
    Version, Characteristics: Cardinal;
    end;

  TVersionW = packed record
    Minor, Major, Build, Release: Word;
    end;

  TFileVerInfo = packed record
    Zero1: Word;
    cID1: Cardinal;
    cID2: Cardinal;
    FileVer: TVersionW;
    ProductVer: TVersionW;
    FileFlagsMask, FileFlags, FileOS, FileType,
    FileSubtype, FileDateMS, FileDateLS: Cardinal;
    end;

  TBlockLen = packed record
    Length, StrLen, wID: Word;
    end;

  TStrWide = record
    pText: PWideChar;
    Len: Cardinal;
    end;

  TStrInfo = (siComment, siCompName, siFileDesc, siFileVer, siIntName, siLegalCopy,
              siLegalTrade, siOrFileName, siProdName, siProdVer);

  TStrBlock = (sbVerInfo, sbStrFlInfo, sbLangID, sbVarInfo, sbTrans);

  TAryUserStr = Array[TStrInfo] of WideString;

  TAryInfoStr = Array[TStrInfo] of TStrWide;

  TAryBlockStr = Array[TStrBlock] of TStrWide;



procedure TForm1.sbut_MakeResFileClick(Sender: TObject);
const
ZeroNull: Word = 0;

aryInfo: TAryInfoStr = ((pText: 'Comment'#0; Len: 18),
             (pText: 'CompanyName'#0; Len: 26),
             (pText: 'FileDescription'#0; Len: 34),
             (pText: 'FileVersion'#0; Len: 26),
             (pText: 'InternalName'; Len: 26),
             (pText: 'LegalCopyright'; Len: 30),
             (pText: 'LegalTrademarks'#0; Len: 34),
             (pText: 'OriginalFilename'; Len: 34),
             (pText: 'ProductName'#0; Len: 26),
             (pText: 'ProductVersion'; Len: 30));

aryBlock: TAryBlockStr = ((pText: 'VS_VERSION_INFO'; Len: 32),
             (pText: 'StringFileInfo'; Len: 30),
             (pText: '040904E4'; Len: 18),// US English Unicode, should be consistant in all Lang values of RES
             (pText: 'VarFileInfo'#0; Len: 26),
             (pText: 'Translation'#0; Len: 26));


var
ResFile: TFileStream;
aFilename: String;
DataHeader: TResDataHeader;
FlVerInfo: TFileVerInfo;
aCard: Cardinal;
SizeT, StrSize, LangSize: Word;
BlkLen: TBlockLen;
aryUser: TAryUserStr;
si: TStrInfo;


begin
aryUser[siComment] := 'Program to View';
aryUser[siCompName] := 'Bottom Feeder';
aryUser[siFileDesc] := 'Barely Working';
aryUser[siFileVer] := '4.5.6.7';
aryUser[siIntName] := 'DUMP.EXE';
aryUser[siLegalCopy] := 'Bottom Feeder 2006';
//aryUser[siLegalTrade] := 'the Mark';
aryUser[siOrFileName] := 'Bottom.EXE';
aryUser[siProdName] := 'Tested and Released Bottom Program March 2006';
aryUser[siProdVer] := '4.9';


aFileName := 'E:\Borland\Delphi5\Mine\LookBut\zzTest3.rest';
ResFile := TFileStream.Create(aFileName, fmCreate);
try
ZeroMemory(@DataHeader, SizeOf(DataHeader));
DataHeader.HeaderSize := SizeOf(DataHeader);
DataHeader.ResType := MaxWord;
DataHeader.ResId := MaxWord;
ResFile.WriteBuffer(DataHeader, SizeOf(DataHeader));

DataHeader.DataSize := 10;
DataHeader.ResType := $10FFFF;
DataHeader.ResId := $1FFFF;
DataHeader.MemoryFlags := $1030;
DataHeader.LanguageId := $0409;// US English, should be consistant in all Lang values of RES
ResFile.WriteBuffer(DataHeader, SizeOf(DataHeader));



BlkLen.Length := 1;
BlkLen.StrLen := $34;
BlkLen.wID := 0;
ResFile.WriteBuffer(BlkLen, SizeOf(BlkLen));
SizeT := SizeOf(BlkLen);

ResFile.WriteBuffer(aryBlock[sbVerInfo].pText^, aryBlock[sbVerInfo].Len);
Inc(SizeT, aryBlock[sbVerInfo].Len);

with FlVerInfo do
  begin
  Zero1 := 0;
  cID1 := $FEEF04BD; // US English Unicode, should be consistant in all Lang values of RES
  cID2 := $10000;

  FileVer.Minor := 5;
  FileVer.Major := 4;
  FileVer.Build := 7;
  FileVer.Release := 6;

  ProductVer.Minor := 9;
  ProductVer.Major := 4;
  ProductVer.Build := 0;
  ProductVer.Release := 0;

  FileFlagsMask := $3F;
  FileFlags := 0;
  FileOS := 4;
  FileType := 1;
  FileSubtype := 0;
  FileDateMS := 0;
  FileDateLS := 0;
  end;
ResFile.WriteBuffer(FlVerInfo, SizeOf(FlVerInfo));
Inc(SizeT, SizeOf(FlVerInfo));
StrSize := SizeT;

BlkLen.StrLen := 0;
ResFile.WriteBuffer(BlkLen, SizeOf(BlkLen));
Inc(SizeT, SizeOf(BlkLen));
ResFile.WriteBuffer(aryBlock[sbStrFlInfo].pText^, aryBlock[sbStrFlInfo].Len);
Inc(SizeT, aryBlock[sbStrFlInfo].Len);

LangSize := SizeT;

ResFile.WriteBuffer(BlkLen, SizeOf(BlkLen));
Inc(SizeT, SizeOf(BlkLen));
ResFile.WriteBuffer(aryBlock[sbLangID].pText^, aryBlock[sbLangID].Len);
Inc(SizeT, aryBlock[sbLangID].Len);

BlkLen.wID := 1;

for si := siComment to siProdVer do
  begin
  BlkLen.StrLen := Length(aryUser[si])+1;
  if (si in [siLegalCopy, siLegalTrade, siComment]) and
     (BlkLen.StrLen = 1) then Continue;

  BlkLen.Length := SizeOf(BlkLen) + aryInfo[si].Len + (BlkLen.StrLen*2);

  ResFile.WriteBuffer(BlkLen, SizeOf(BlkLen));
  Inc(SizeT, BlkLen.Length);

  ResFile.WriteBuffer(aryInfo[si].pText^, aryInfo[si].Len);
  if BlkLen.StrLen = 1 then
    ResFile.WriteBuffer(ZeroNull, SizeOf(ZeroNull))
    else
    ResFile.WriteBuffer(aryUser[si][1], BlkLen.StrLen * 2);
   
  if BlkLen.Length mod 4 <> 0 then
    begin
    ResFile.WriteBuffer(ZeroNull, SizeOf(ZeroNull));
    Inc(SizeT, 2);

    if (si = siProdVer) then
      begin
      Inc(StrSize, 2);
      Inc(LangSize, 2);
      end;
    end;
  end;

StrSize := SizeT-StrSize;
LangSize := SizeT-LangSize;

BlkLen.Length := $44;
BlkLen.StrLen := 0;
BlkLen.wID := 0;
ResFile.WriteBuffer(BlkLen, SizeOf(BlkLen));
Inc(SizeT, SizeOf(BlkLen));
ResFile.WriteBuffer(aryBlock[sbVarInfo].pText^, aryBlock[sbVarInfo].Len);
Inc(SizeT, aryBlock[sbVarInfo].Len);

BlkLen.Length := $24;
BlkLen.StrLen := 4;

ResFile.WriteBuffer(BlkLen, SizeOf(BlkLen));
Inc(SizeT, SizeOf(BlkLen));
ResFile.WriteBuffer(aryBlock[sbTrans].pText^, aryBlock[sbTrans].Len);
Inc(SizeT, aryBlock[sbTrans].Len);

aCard := $4E40409;// US English Unicode, should be consistant in all Lang values of RES
ResFile.WriteBuffer(aCard, SizeOf(aCard));
Inc(SizeT, SizeOf(aCard));

ResFile.Position := 32;
ResFile.WriteBuffer(SizeT, SizeOf(SizeT));

ResFile.Position := 64;
ResFile.WriteBuffer(SizeT, SizeOf(SizeT));

ResFile.Position := 156;
ResFile.WriteBuffer(StrSize, SizeOf(StrSize));

ResFile.Position := 192;
ResFile.WriteBuffer(LangSize, SizeOf(LangSize));

finally
FreeAndNil(ResFile);
end;
end;

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Slick812Commented:
the above tested and compared against this .RC  code -



1 VERSIONINFO DISCARDABLE
 FILEVERSION 4,5,6,7
 PRODUCTVERSION 4,9,0,0
 FILEFLAGSMASK 0x3F
 FILEFLAGS 0
 FILEOS VOS__WINDOWS32
 FILETYPE VFT_APP
 FILESUBTYPE 0
BEGIN
BLOCK "StringFileInfo"
  BEGIN
  BLOCK "040904E4" // language ID for US English
    BEGIN
    VALUE "Comment", "Program to View\0" // optional
    VALUE "CompanyName", "Bottom Feeder\0"
    VALUE "FileDescription", "Barely Working\0"
    VALUE "FileVersion", "4.5.6.7\0"
    VALUE "InternalName", "DUMP.EXE\0"
    VALUE "LegalCopyright", "Bottom Feeder 2006\0" // optional
    //VALUE "LegalTrademarks", "the Mark\0" // optional
    VALUE "OriginalFilename", "Bottom.EXE\0"
    VALUE "ProductName", "Tested and Released Bottom Program March 2006\0"
    VALUE "ProductVersion", "4.9\0"
    END
  END
BLOCK "VarFileInfo"
  BEGIN
  VALUE "Translation", 0x0409, 0x04E4 // should match Language ID Block
  END
END
heretoreadAuthor Commented:
i found the first WORD (header size), was the complete size of the resource, not just of the first few types.

I managed to get my own Version resource code working yesturday, but as you have worked hard on yours i will accept the answer.
Slick812Commented:
I really wish I would not have wasted my time on this
Slick812Commented:
I reallly really really wish I would NOT have wasted my time on this
heretoreadAuthor Commented:
I hope that wasn't aimed at me, i did say on the 30th i had got my own code working and i increased the points.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.