madRes - Change properties of executables

delphi package - madRes, madTools, madStrings, ...

madRes - Change properties of executables

Postby Silver Black » Fri Feb 17, 2006 11:57 am

How do I use madRes to change properties of executable files, like Version, Copyright, Author, Description, ecc.?

P.S.
The file is build by my own software, so there are no copyright violations!
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby madshi » Mon Feb 20, 2006 8:47 am

Basically you need to replace the version information resource. madRes allows you to do that, but madRes doesn't know the format of the version information resource. So it's up to you to create a proper data block with the correct format. I think you can find some sources on the net for that purpose.
madshi
Site Admin
 
Posts: 9414
Joined: Sun Mar 21, 2004 5:25 pm

Postby Silver Black » Mon Feb 20, 2006 10:13 am

I can't find any example code on the net... can you help me? :oops:
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby Silver Black » Mon Feb 20, 2006 4:48 pm

That's my preliminary-code (no optimization, just trial):

Code: Select all
procedure TFormMain.btnChangePropsClick(Sender: TObject);
const
   MaxVersionKeys = 9;
   VersionKeyNames: array [0..MaxVersionKeys] of String =
    ('CompanyName', 'FileDescription', 'FileVersion', 'InternalName',
      'LegalCopyright', 'LegalTrademarks', 'OriginalFilename',
      'ProductName', 'ProductVersion', 'Comments');
var
   StandardKeys: array [0..MaxVersionKeys] of String;
  VersionInfo : String;
  LangCharset : String;
  InfoAvailable: Boolean;
   ThisInfo: Integer;
   InfoLength: UINT;
   Len: DWORD;
   Handle: DWORD;
   PCharset: PLongInt;
  strSourceFile: String;
  dwH: dword;
begin
   try
    if (FileExists(Self.labedtSourceFile.Text)) then begin
      strSourceFile := Self.labedtSourceFile.Text;
      // Get size of version info
      Len := GetFileVersionInfoSize(PChar(strSourceFile), Handle);
      // Allocate VersionInfo buffer size
      SetLength(VersionInfo, Len + 1);
      // Get version info
      if GetFileVersionInfo(PChar(strSourceFile), Handle, Len, Pointer(VersionInfo)) then begin
        // Get translation info for Language / CharSet IDs
        if VerQueryValue(Pointer(VersionInfo), '\VarFileInfo\Translation', Pointer(PCharset), InfoLength) then begin
          LangCharset := Format('%.4x%.4x', [LoWord (PCharset^), HiWord (PCharset^)]);
          InfoAvailable := True;
          // Get standard version information
          for ThisInfo := 0 to MaxVersionKeys do begin
            StandardKeys[ThisInfo] :=   'EDITED';
          end;
          dwH := BeginUpdateResourceW(PWideChar(WideString(strSourceFile)), False);
          for ThisInfo := 0 to MaxVersionKeys do begin
            UpdateResourceW(dwH, PWideChar(RT_VERSION), PWideChar(StandardKeys[ThisInfo]), 0, nil, Len);
          end;
          EndUpdateResourceW(dwH, False);
        end;
      end;
    end else begin
      ShowMessage('File eseguibile non selezionato o inesistente.');
    end;
   except
      on E:Exception do
         ShowMessage(E.Message);
   end;


It does nothing... :( I know there must be something wrong (well, more than just "nothing"!) in this line:

Code: Select all
UpdateResourceW(dwH, PWideChar(RT_VERSION), PWideChar(StandardKeys[ThisInfo]), 0, nil, Len);


but I have no idea of the real parameters to pass, mainly "size" and "data". :confused:
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby Silver Black » Tue Feb 21, 2006 5:01 pm

Ok, that's the final version of my code: it does something but properties still seem there...

Code: Select all
procedure TFormMain.btnChangePropsClick(Sender: TObject);
var
  VersionInfo: String;
  LangCharset: String;
  strSubBlock: String;
  InfoLength: UINT;
  Len: DWORD;
  Handle: DWORD;
  PCharset: PLongInt;
  strSourceFile: String;
  dwH: dword;
begin
  try
    if (FileExists(Self.labedtSourceFile.Text)) then begin
      strSourceFile := Self.labedtSourceFile.Text;
      // Get size of version info
      Len := GetFileVersionInfoSize(PChar(strSourceFile), Handle);
      // Allocate VersionInfo buffer size
      SetLength(VersionInfo, Len + 1);
      // Get version info
      if GetFileVersionInfo(PChar(strSourceFile), Handle, Len, Pointer(VersionInfo)) then begin
        // Get translation info for Language / CharSet IDs
        if VerQueryValue(Pointer(VersionInfo), '\VarFileInfo\Translation', Pointer(PCharset), InfoLength) then begin
          LangCharset := Format('%.4x%.4x', [LoWord (PCharset^), HiWord (PCharset^)]);
          // Points to location we are interested in:
          strSubBlock := '\\StringFileInfo\\%04x%04x\\CompanyName';
          VerQueryValue(Pointer(VersionInfo), PChar(strSubBlock), Pointer(PCharset), InfoLength);
          // Modify properties:
          StrCopy(PAnsiChar(PCharset), 'EDITED');
          // Scrive le proprietà:
          dwH := BeginUpdateResourceW(PWideChar(WideString(strSourceFile)), False);
          if UpdateResourceW(dwH,
                             PWideChar(RT_VERSION),
                             PWideChar(VS_VERSION_INFO),
                             0,
                             Pointer(VersionInfo),
                             Len) then begin
            Application.MessageBox('File properties changed succesfully!', PChar(Application.Title), 0);
            EndUpdateResourceW(dwH, False);
          end else begin
            Application.MessageBox('Errors modifying file properties!', PChar(Application.Title), 0)
          end;
        end;
      end;
    end else begin
      ShowMessage('File not exists.');
    end;
   except
      on E:Exception do
         ShowMessage(E.Message);
   end;
end;


I NEED SOME HELP, please!!!... :( :( :( :( :( :(
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby Silver Black » Wed Feb 22, 2006 10:16 am

Update code: nothing chages but the file size (2 bytes more) :(

Code: Select all
var
  sz, lpHandle, tbl: Cardinal;
  lpBuffer: Pointer;
  strTbl: string;
  int: PInteger;
  hiW, loW: Word;
  strSourceFile: String;
  dwH: dword;
  FData: Pointer;
  FSize: Cardinal;
begin
  try
    if (FileExists(Self.labedtSourceFile.Text)) then begin
      strSourceFile := Self.labedtSourceFile.Text;
      // Legge le proprietà del file (struttura VersionInfo):
      FSize := GETFILEVERSIONINFOSize(PChar(strSourceFile), lpHandle);
      FData := AllocMem(FSize);
      GETFILEVERSIONINFO(PChar(strSourceFile), lpHandle, FSize, FData);
      VerQueryValue(FData, '\VarFileInfo\Translation', lpBuffer, sz);
      int := lpBuffer;
      hiW := HiWord(int^);
      loW := LoWord(int^);
      tbl := (loW shl 16) or hiW;
      strTbl := Format('%x', [tbl]);
      if Length(strtbl) < 8 then strTbl := '0' + strTbl;
      // CompanyName:
      VerQueryValue(FData, PChar('\\StringFileInfo\'+ strTbl +'\CompanyName'), lpBuffer, sz);
      StrCopy(lpBuffer, 'SILVERBLACK');
      dwH := BeginUpdateResourceW(PWideChar(WideString(strSourceFile)), False);
      if UpdateResourceW(dwH,
                         PWideChar(RT_VERSION),
                         PWideChar(VS_VERSION_INFO),
                         1,
                         lpBuffer,
                         FSize) then begin
        Application.MessageBox('Proprietà cambiate correttamente!', PChar(Application.Title), 0);
        EndUpdateResourceW(dwH, False);
 ...


Original "CompanyName" value is read correctly, so lpBuffer correctly points to the exact memory location. Thus of course I make a mistake with the UpdateResourceW and the parameters I pass.

I have no more ideas!!! :confused:
I really need a hand! :cry:
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby madshi » Wed Feb 22, 2006 11:36 am

Does UpdateResourceW succeed?

You're giving in lpBuffer as the new version resource, that's not correct. It's the pointer to the company string, not the point to the version resource!
madshi
Site Admin
 
Posts: 9414
Joined: Sun Mar 21, 2004 5:25 pm

Postby Silver Black » Wed Feb 22, 2006 12:16 pm

madshi wrote:Does UpdateResourceW succeed?


Yes, but I'm still not sure about the Language parameter.

You're giving in lpBuffer as the new version resource, that's not correct. It's the pointer to the company string, not the point to the version resource!


Oh... :shock: Right!!!!!!
And so, how do I modify the resource string and, overall, pass my new string to the UpdateResourceW?
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby madshi » Wed Feb 22, 2006 12:31 pm

You should use the same Language code the original version information has. You can check that by using "ResourceHacker".

Use lpBuffer2 for the string manipulation, then lpBuffer should still point to the version information block.
madshi
Site Admin
 
Posts: 9414
Joined: Sun Mar 21, 2004 5:25 pm

Postby Silver Black » Wed Feb 22, 2006 3:04 pm

madshi wrote:Use lpBuffer2 for the string manipulation, then lpBuffer should still point to the version information block.


lpBuffer2? So

Code: Select all
  StrCopy(lpBuffer2, 'mystringhere');


And where I pass it to the UpdateResourceW? How do I use it? It's not clear for me.
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby madshi » Wed Feb 22, 2006 3:12 pm

In that line and also in the line before (VerQueryValue).

Sorry, how much programming experience do you have? I don't have the time to do all the work for you!
madshi
Site Admin
 
Posts: 9414
Joined: Sun Mar 21, 2004 5:25 pm

Postby madshi » Wed Feb 22, 2006 3:13 pm

You can also check out this page:

http://www.wilsonc.demon.co.uk/delphi.htm

Colin also offers some freeware stuff about changing EXE resources. Perhaps he has some version information specific stuff built in that you can use.
madshi
Site Admin
 
Posts: 9414
Joined: Sun Mar 21, 2004 5:25 pm

Postby Silver Black » Wed Feb 22, 2006 3:41 pm

I have some experience (I'm graduating in Computer Science of my country), but knowledge is never enough and I'm always finding out that the things I don't know are soooo many! :wink:

Thanks for your help, it was appreciated. I don't want you to do the job for me, resources and low-level programming is not my main interest but I'd like to be succesful in this challenge on my own.

One last thing I don't understand (I still didn't check the article you linked) is how UpdateResourceW should be warned about lpBuffer2, because either I pass it lpBuffer or lpBuffer2, but not both!

I feel I'm near the solution... :sorry:

See ya and thanks for all!
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy

Postby madshi » Wed Feb 22, 2006 4:03 pm

You don't want to store just the company name characters into the version resource, or do you? You want to give in the whole version resource block, right? So you should give in the address of the whole version resource block. I've not fully studied your code, but it seems to me that you stored the address of the resource block in FData, so you should give that into UpdateResourceW. I think you can do the rest with lpBuffer (I guess you don't need lpBuffer2), as long as you don't give lpBuffer into UpdateResourceW.
madshi
Site Admin
 
Posts: 9414
Joined: Sun Mar 21, 2004 5:25 pm

Postby Silver Black » Wed Feb 22, 2006 4:33 pm

Thank you MadShi! Yes, you're right: I wanna change the whole structure VersionInfo. Your tip is great and enlightening, now I'll check again my code thinking about what you told me.

Bye and thanks!
Silver Black
 
Posts: 29
Joined: Fri Feb 17, 2006 11:47 am
Location: Italy


Return to madBasic

Who is online

Users browsing this forum: No registered users and 3 guests