Page 1 of 1

madRes - Change properties of executables

Posted: Fri Feb 17, 2006 11:57 am
by Silver Black
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!

Posted: Mon Feb 20, 2006 8:47 am
by madshi
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.

Posted: Mon Feb 20, 2006 10:13 am
by Silver Black
I can't find any example code on the net... can you help me? :oops:

Posted: Mon Feb 20, 2006 4:48 pm
by Silver Black
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:

Posted: Tue Feb 21, 2006 5:01 pm
by Silver Black
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!!!... :( :( :( :( :( :(

Posted: Wed Feb 22, 2006 10:16 am
by Silver Black
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:

Posted: Wed Feb 22, 2006 11:36 am
by madshi
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!

Posted: Wed Feb 22, 2006 12:16 pm
by Silver Black
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?

Posted: Wed Feb 22, 2006 12:31 pm
by madshi
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.

Posted: Wed Feb 22, 2006 3:04 pm
by Silver Black
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.

Posted: Wed Feb 22, 2006 3:12 pm
by madshi
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!

Posted: Wed Feb 22, 2006 3:13 pm
by madshi
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.

Posted: Wed Feb 22, 2006 3:41 pm
by Silver Black
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!

Posted: Wed Feb 22, 2006 4:03 pm
by madshi
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.

Posted: Wed Feb 22, 2006 4:33 pm
by Silver Black
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!