views:

547

answers:

4

How do I modify buffer in following code then save the changes in resource of the executable? I'm looking for something like SetString(handle,index,buffer,size).

var
  hExe : Cardinal;
  buffer : array [0..4097] of ansichar;
begin
  hExe:=LoadLibraryEx(PAnsiChar(Edit2.Text),0,LOAD_LIBRARY_AS_DATAFILE);
  LoadString(hExe,65300,buffer,SizeOf(buffer));
  ShowMessage(buffer);
  //need to modify buffer here then I'll unload the resources..
end;

Update: Here's my attempt on UpdateResource

var
  hEXE: DWORD;
  pData: PAnsiChar;
begin
  pData := PAnsiChar(Edit1.Text);
  hEXE := BeginUpdateResource(pchar(edit2.text), FALSE);
  if hEXE <> 0 then
  begin
    UpdateResource(hEXE, RT_string, MAKEINTRESOURCE(4082), LANG_NEUTRAL,
      @pData, Length(pData)); //if i change 4082 to 65300 it creates another key like 4082
    EndUpdateResource(hEXE, FALSE);
  end;

This code messes up the whole 4082 content. The problem is item named 4082 in RT_STRING is group of strings. When I open the exe in a resource editor, click string table then 4082 the result is:

STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
{
65296,  "Unicode"
65297,  "Big Endian Unicode"
65298,  "UTF-8"
65299,  "UTF-7"
65300,  "ABCDE12345"
}

So I either need to parse the string group or I need an API to set modify string with the index 65300 in the group. Any ideas?

+3  A: 

You can see the source code (Delphi 2006) of the XN Resource Editor (is a free, powerful, fully featured resource editor and PE module explorer for Windows 98, Windows 2000 and Windows XP).

besides you should check the following functions

Bye.

RRUZ
Requirements of XN Resource Editor doesn't compile with D2009 (gives left side unable to assign error - pngimage.pas ln 1845). I've tried with UpdateResource but I kept messing up other strings in same category.
Ertugrul Tamer Kara
you not need to compile your project, you can analyze the code directly.
RRUZ
RRUZ
True, but the code depends on requirements (a package called resourceutils from same person). I don't mean to be `give me the codes so I can copy-paste and use them`, but it's kind of overkill to analyze package that big for a simple use.
Ertugrul Tamer Kara
+1  A: 

There's an article talk about this on Delphi3000:

Resources inside .exe files

Mohammed Nasman
Thanks but it doesn't show how to modify RT_STRING content.
Ertugrul Tamer Kara
+1  A: 

I believe you need to replace the entire group with a version that contains your modifications. This isn't that difficult to parse, and you can take a few shortcuts. Load everything into a tStringlist and then loop down the list until the string starts with '65300,'. Perform your replacement and save the text portion of the stringlist as the replacement resource.

skamradt
+2  A: 

I've found the answer using Google. (English translation from Chinese) Thanks anyways everyone!

procedure UpdateResString(AFileName, ANewString: string; AStringIdent: Integer);
  procedure WriteToArray(AArray: TByteDynArray; AData: Word; var APos: Integer);
  begin
    AArray[APos] := Lo(AData);
    AArray[APos + 1] := Hi(AData);
    Inc(APos, 2);
  end;

  function ReadFromArray(AArray: TByteDynArray; APos: Integer): Word;
  begin
    Result := AArray[APos] + AArray[APos + 1] * 16;
  end;

var
  hModule, hResInfo, hUpdate: THandle;
  ResData, TempData: TByteDynArray;
  wsNewString: WideString;
  iSection, iIndexInSection: Integer;
  i, iLen, iSkip, iPos: Integer;
begin
  hModule := LoadLibrary(PChar(AFileName));
  if hModule = 0 then
    raise Exception.CreateFmt('file %s failed to load.', [AFileName]);

  // Calculate the resource string area and the string index in that area
  iSection := AStringIdent div 16 + 1;
  iIndexInSection := AStringIdent mod 16;

  // If the resource already exists, then read it out of the original data
  hResInfo := FindResource(hModule, MakeIntResource(iSection), RT_STRING);
  if hResInfo <> 0 then
  begin
    iLen := SizeOfResource(hModule, hResInfo);
    SetLength(ResData, iLen);
    CopyMemory(ResData, LockResource(LoadResource(hModule, hResInfo)), iLen);
  end;
  // Should first close the file, and then update
  FreeLibrary(hModule);
  // Calculate the new data is written to location
  wsNewString := WideString(ANewString);
  iLen := Length(wsNewString);
  iPos := 0;
  for i := 0 to iIndexInSection do
  begin
    if iPos > High(ResData) then
      SetLength(ResData, iPos + 2);
    if i <> iIndexInSection then
    begin
      iSkip := (ReadFromArray(ResData, iPos) + 1) * 2;
      Inc(iPos, iSkip);
    end;
  end;

  // Delete the original data and the data behind the temporary
  // storage of data to be added
  iSkip := (ReadFromArray(ResData, iPos) + 1) * 2;
  TempData := Copy(ResData, iPos + iSkip, Length(ResData) - iSkip);
  SetLength(ResData, iPos);
  SetLength(ResData, iPos + (iLen + 1) * 2 + Length(TempData));

  // Write new data
  WriteToArray(ResData, iLen, iPos);
  for i := 1 to iLen do
    WriteToArray(ResData, Ord(wsNewString[i]), iPos);
  // Write back to the original data
  for i := 0 to High(TempData) do
    ResData[iPos + i] := TempData[i];

  // Write the data back to file
  hUpdate := BeginUpdateResource(PChar(AFileName), False);
  if hUpdate = 0 then
    raise Exception.CreateFmt(
      'cannot write file %s. Please check whether it is open or set read-only.',
      [AFileName]);

  UpdateResource(hUpdate, RT_STRING, MakeIntResource(iSection), LANG_NEUTRAL,
    ResData, Length(ResData));
  EndUpdateResource(hUpdate, False);
end;
Ertugrul Tamer Kara