[ looping @ 15.07.2014. 07:32 ] @
Pozdrav svima,
pokisavam da u DELPHI-ju u runtime-u procitam sve resourcestring-ove iz exe ili bpl file-a i da po potrebi promenim njihove vrednosti. Znam da je to moguce ali ne uspevam da pronadjem kako.
Mogu da izmenim pojedinacni resurs, kao sto je prikazano u kodu ispod, ali ne mogu da dobijem grupu resursa i da petljom prolazim kroz svaki resurs.
Kako da iteriram kroz sve resoursestring-ove?

Code:

procedure HookResourceString(rs: PResStringRec; newStr: PChar);
 var
    oldprotect: DWORD;
 begin
    VirtualProtect(rs, SizeOf(rs^), PAGE_EXECUTE_READWRITE, @oldProtect);
    rs^.Identifier := Integer(newStr);
    VirtualProtect(rs, SizeOf(rs^), oldProtect, @oldProtect);
 end;

initialization
  HookResourceString(@resourceLabela, 'Nova vrednost');
end.


[ reiser @ 15.07.2014. 08:48 ] @
Zanimljiv problem. Evo ovako nesto ce ti enumerisati sve resurse koje zelis za odredjeni modul:

Code:

function EnumResourceNamesCallback(hModule: HMODULE; lpszType: LPCTSTR; lpszName: LPTSTR; lParam: LONG_PTR): BOOL; stdcall;
var
  id: LongInt;
  min, max: Integer;
  C1: Integer;
  buffer: PChar;
  len: Word;
  resource_stream: TResourceStream;
  list: TStrings;
  rstr: String;
begin
  list := TStrings(lParam);

  // special handling for RT_STRING resource type
  // RT_STRING resource IDs are always in 1-$FFFF range
  if LongInt(lpszName) <= $FFFF then
  begin
    id := LongInt(lpszName); // RT_STRING ID: %d [id]
    min := (id - 1) * 16;
    max := (id * 16) - 1;
    resource_stream := TResourceStream.CreateFromID(hModule, id, RT_STRING);
    try
      buffer := resource_stream.Memory;
      for C1 := min to max do
      begin
        len := Word(buffer^);
        if len > 0 then
        begin
          SetString(rstr, buffer + 1, len);
          // String ID %d: %s [C1, rstr]
          list.Add(rstr);
          Inc(buffer, len + 1);
        end
        else
          Inc(buffer);
      end;
    finally
      resource_stream.Free;
    end;
  end
  else
    list.Add(String(lpszName));

  result := TRUE;
end;

procedure EnumResources(const AModule: HMODULE; const AList: TStrings);
begin
  EnumResourceNames(AModule, RT_STRING, @EnumResourceNamesCallback, NativeInt(AList));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  resource_list: TStringList;
begin
  resource_list := TStringList.Create;
  try
    EnumResources(HInstance, resource_list);
    ShowMessage(resource_list.Text);
  finally
    resource_list.Free;
  end;
end;
[ looping @ 15.07.2014. 12:44 ] @
Hvala na odgovoru, primer koji si dao radi upravo ono sto sam i zeleo, daje listu resursa.
A da li postoji nacin da pored vrednosti resursa dobijem i ime labele kako je definisana u *.pas fileu,
na pr. da dobijem prvi= 'Ovo je prvi string', drugi = 'Ovo je drugi string'?

Code:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

resourcestring
  prvi = 'Ovo je prvi string';
  drugi = 'Ovo je drugi string';

[ reiser @ 15.07.2014. 14:27 ] @
99% sam siguran da to nije moguce. Jedino sto mozes da probasj e da ih deklarises kao var (nisam siguran da li ti je resourcestring bas potreban?), deklarises ID svakog stringa i onda koristis LoadStr().
[ looping @ 15.07.2014. 15:04 ] @
Pa ono sto treba da uradim je da u vec postojecem projektu, prilikom startovanja aplikacije dinamiski izmenim resourcestring-ove.
Zahtev je da se sve vrednosti resourcestring-ova smete u bazi i da se prilikom startovanja aplikacije, vrednosti resourcestring-ova koje su definisane prilikom dizajniranja, zamene sa vrednostima iz baze
[ reiser @ 15.07.2014. 15:05 ] @
Ti resource stringovi imaju staticki ID, tako da ces morati da ih uporedjujes po ID-ju i menjas.
[ looping @ 16.07.2014. 10:30 ] @
Hvala na ideji, mislim da ce mi to resiti problem.
[ looping @ 24.07.2014. 12:28 ] @
Na nesrecu, ponovo sam primoran da konsultujem bolje od mene u DELPHI-ju

Kako je Reiser objasnio, mogu da dobijem spisak svih resourcestringova u TStringList objektu,
ali ja nikako nisam pronasao nacin da te resourcestringove i izmenim kasnije prolazeci kroz perlju.
Da li postoji nacin i to da se uradi kroz petlju ili cu ipak morati svaki resource string posebno, kao sto je prikazano ispod:
Code:

resourcestring
   resourceLabela_1 = 'Inicijalna vrednost_1';
   resourceLabela_2 = 'Inicijalna vrednost_2';
   .
   .
   resourceLabela_n = 'Inicijalna vrednost_n';


procedure HookResourceString(rs: PResStringRec; newStr: PChar);
  var
     oldprotect: DWORD;
  begin
     VirtualProtect(rs, SizeOf(rs^), PAGE_EXECUTE_READWRITE, @oldProtect);
     rs^.Identifier := Integer(newStr);
     VirtualProtect(rs, SizeOf(rs^), oldProtect, @oldProtect);
  end;

 initialization
   HookResourceString(@resourceLabela_1, 'Nova vrednost_1');
   HookResourceString(@resourceLabela_2, 'Nova vrednost_1');
   .
   .
   HookResourceString(@resourceLabela_n, 'Nova vrednost_1');
 end.
[ reiser @ 24.07.2014. 13:39 ] @
Pre linije len := Word(buffer^);, ako taj buffer castujes u PResStringRec, dobijas pointer ka tom string resursu:

Code:

var
  prsr: PResStringRec;
begin
  ...
      for C1 := min to max do
      begin
        prsr := @buffer;
        // ChangeResource(prsr, 'bla');
        len := Word(buffer^);
        if len > 0 then
  ....
[ looping @ 24.07.2014. 15:30 ] @
Stavio sam kao sto si rekao ali na ovaj nacin ne menja resourcestring-ove, tj. ostaju onakvi kakvi su definisani u *.pas fileu
Izgleda da gresim negde
Stavio sam ovko
Code:

var
   id: LongInt;
   min, max: Integer;
   C1: Integer;
   buffer: PChar;
   len: Word;
   resource_stream: TResourceStream;
   list: TStrings;
   rstr: String;
   prsr: PResStringRec;
 begin
   list := TStrings(lParam);

   // special handling for RT_STRING resource type
   // RT_STRING resource IDs are always in 1-$FFFF range
   if LongInt(lpszName) <= $FFFF then
   begin
     id := LongInt(lpszName); // RT_STRING ID: %d [id]
     min := (id - 1) * 16;
     max := (id * 16) - 1;
     resource_stream := TResourceStream.CreateFromID(hModule, id, RT_STRING);
     try
       buffer := resource_stream.Memory;
       for C1 := min to max do
       begin
         prsr := @buffer;
         HookResourceString(prsr, 'bla');
         len := Word(buffer^);
         if len > 0 then
         begin
           SetString(rstr, buffer + 1, len);
           // String ID %d: %s [C1, rstr]

           list.Add(rstr);
           Inc(buffer, len + 1);
         end
         else
           Inc(buffer);
       end;
     finally
       resource_stream.Free;
     end;
   end
   else
     list.Add(String(lpszName));

   result := TRUE;
[ savkic @ 24.07.2014. 22:03 ] @
Resursi se menjaju preko odgovarajućih WinApi funkcija, međutim to i ne funkcioniše uvek kako treba. Moj ti je savet da koristiš madRes za tu svrhu jer lepo radi a i besplatan je.

http://help.madshi.net/madResUnit.htm