Page 1 of 2 1 2 LastLast
Results 1 to 15 of 16

Thread: resource strings ophoesten

  1. #1
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382

    resource strings ophoesten

    Is er een functie waarmee ik (@runtime) alle resourcestrings (en hun nummer) uit mijn programma kan halen?

  2. #2

  3. #3
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    ...en met een TResourceStream kun je ze vervolgens gebruiken.
    TMemoryLeak.Create(Nil);

  4. #4
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    EnumResourceNames(0,RT_STRING,@Callback,0);
    geeft een gastlasterror 998. Ook het inlezen van een extern bestand geeft dezelfde fout.
    (de callback wordt 1x aangeroepen met geen enkele paramater gevuld)

  5. #5
    Mogelijk antwoord hier:
    http://stackoverflow.com/a/23024842/1037511

    Het kan dus zijn dat je een ID terug krijgt en geen string. Je moet dus testen met IS_INTRESOURCE wat je terug krijgt.

  6. #6
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    ik gooi de resources even achter elkaar in een file, maar de volgorde is zeer anarchistisch...
    Er lijken per Callback (er komen er maar een stuk of 20 a 25) een aantal strings achter elkaar geplakt te zijn.
    Uit verschillende units door elkaar heen. En volgens mij niet compleet.
    Ik wil "gewoon" een rijtje ID's en een rijtje strings...
    Code:
    fs := TFileStream.create('rt_string.bin', fmCreate);
    EnumResourceNames(0,RT_STRING,@Callback, long(fs));
    fs.Free;
    callback
    Code:
    function Callback(handle:THandle;ResType:PChar;ResName:Pchar;long:Lparam):bool;stdcall;
    var
      i: Integer;
      R: TResourceStream;
    begin
      if Is_IntResource(restype) then begin
        i := integer(resname);
        log(['int', i]);
        R := TResourceStream.CreateFromID(0, i, restype);
        TFileStream(Long).CopyFrom(R, 0);
        R.free;
      end
     result := true;
    end;
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	rt_string.jpg 
Views:	109 
Size:	103.4 KB 
ID:	6817  

  7. #7
    Je hebt hier ook niet te maken met een enkele string per ID maar met een STRINGTABLE.
    Je zult het resultaat per ID dus een beetje uit elkaar moeten trekken om alle strings goed te kunnen krijgen.
    Zoals dit:

    Delphi Code:
    1. function EnumResNameProc(hModule: THandle; lpszType, lpszName: PChar; lParam: longint): boolean; stdcall;
    2. var
    3.   ID: longint;
    4.   Min: Integer;
    5.   Max: Integer;
    6.   Index: Integer;
    7.   Buffer: PWChar;
    8.   stream: TResourceStream;
    9.   Len: Word;
    10.   S: String;
    11. begin
    12.   if longint(lpszName) < 65535 then
    13.   begin
    14.     ID := longint(lpszName);
    15.     Min := (ID - 1) * 16;
    16.     Max := (ID * 16) - 1;
    17.     stream := TResourceStream.CreateFromID(hModule, ID, RT_STRING);
    18.     try
    19.  
    20.       TStringList(lParam).Add(Format('%d STRINGTABLE', [ID]));
    21.       TStringList(lParam).Add('{');
    22.  
    23.       Buffer := stream.Memory;
    24.       for Index := Min to Max do
    25.       begin
    26.         // determine the length of the string
    27.         Len := Word(Buffer^);
    28.         if Len > 0 then
    29.         begin
    30.           Inc(Buffer, 1);
    31.           S := Copy(WideCharToString(Buffer), 1, Len - 1);
    32.           TStringList(lParam).Add(Format('  %d, "%s"', [Index, S]));
    33.           Inc(Buffer, Len);
    34.         end
    35.         else
    36.             Inc(Buffer);
    37.       end;
    38.       TStringList(lParam).Add('}');
    39.  
    40.     finally
    41.         stream.Free;
    42.     end;
    43.   end
    44.   else
    45.       TStringList(lParam).Add(string(lpszName));
    46.   Result := true;
    47. end;
    48.  
    49. procedure TForm1.Button1Click(Sender: TObject);
    50. var
    51.   sl: TStringList;
    52. begin
    53.   sl := TStringList.Create;
    54.   EnumResourceNames(0, RT_STRING, @EnumResNameProc, longint(sl));
    55.   sl.SaveToFile('c:\temp\rt_string.txt');
    56.   sl.Free;
    57. end;

    Resultaat:
    Code:
    4007 STRINGTABLE
    {
      64096, "WideString index out of bound"
      64097, "No URL was specified for 'GET"
      64098, "Invalid url '%s' - only supports 'http' and 'https' scheme"
      64099, "Method has no RTT"
      64100, "Unsuppported variant type %"
      64101, "varDispatch type not supporte"
      64102, "varError type not supporte"
      64103, "TAggregateStream Error: no internal stream"
      64104, "method not supporte"
      64105, "Method not permitted in TSoapDataLis"
      64106, "Insufficient data for Content-Lengt"
      64107, "Error reading from Mime Request Strea"
      64108, "No access to temporary fil"
      64109, "Unable to load WSDL File/Location: %s.  Error [%s"
      64110, "Unable to generate temporary pat"
      64111, "Rename to %s faile"
    }
    4008 STRINGTABLE
    {
      64112, "Parameter %s on Method %s of Interface %s has no RTT"
      64113, "Invalid date string: %"
      64114, "Invalid time string: %"
    .....
    (Zie ook http://stackoverflow.com/a/6500134/1037511)

  8. #8
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    oooo wat lekker recht allemaal! Thanks.

    Raadselachtig:
    Code:
    Min := (ID - 1) * 16;
    Max := (ID * 16) - 1;

  9. #9
    Quote Originally Posted by EricLang View Post
    Raadselachtig:
    Code:
    Min := (ID - 1) * 16;
    Max := (ID * 16) - 1;
    Dat stond ook hier.
    UPDATE I updated the answer to reflect the strings id inside of the string table, the strings are grouped together in bundles of 16. So the first bundle contains strings 0 through 15, the second bundle contains strings 16 through 31, and so on. so the formula to calculate the strings id can be determined in this way
    Ook hier uitgelegd: The format of string resources

    Bij mij lopen de string nummers door tot 65535 (in ID 4096) terug naar 64096 (in ID 4007). Ze zijn dus gegroepeerd per 16. (4007-1) * 16 = 64096.

    Overigens staat er een klein foutje in mijn code (ik heb de string-code er n.l. zelf ff bij gemaakt want die stond niet in de oorspronkelijke routine):
    Code:
    S := Copy(WideCharToString(Buffer), 1, Len);
    Maar er stond een extra $0D achter de regels maar volgens mij komt dat door de TStringList (omdat de string tussen de "" wel goed is).

  10. #10
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Okidoki. Ja ik had hier en daar volgens mij te snel er doorheen gescand. Too eager for a solution.
    Dat de string 1 te kort was had ik dan weer wel gezien
    Ik zal morgen eens kijken welke resourcestrings er uit komen rollen. Nogmaal bedankt.

  11. #11
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Ok werkend. Da's een goed begin.
    Nu... Slechts wetende de Index van de resourcestring, kan ik deze dan terug vinden?

    Ik wil met de volgende functie resourcestrings in mijn app aanpassen. Maar ik heb de pointer van PResStringRec nodig.
    Code:
    procedure HookResourceString(Res: PResStringRec; const NewStr: string{PChar});
    var
      oldprotect: DWORD;
    begin
      VirtualProtect(Res, SizeOf(Res^), PAGE_EXECUTE_READWRITE, @oldProtect);
      Res^.Identifier := Integer(PChar(NewStr));
      VirtualProtect(Res, SizeOf(Res^), oldProtect, @oldProtect);
    end;

  12. #12
    Je bedoelt zoiets als hier te zien is:
    http://www.delphipraxis.net/1207541-post4.html
    https://gist.github.com/artzub/9064231

    Dit werkt bij mij wel gewoon:
    Code:
      HookResourceString(@SMsgDlgNo, 'Nope');
    De SMsgDlgNo is gedefinieerd in Consts.pas (die ik overigens gewoon heb vervangen door een Nederlandstalige versie).

    In mijn Consts.pas staat dit:
    Code:
    resourcestring
    //...
      SMsgDlgNo = '&Nee'; // '&No';
    //...
    Dus die resourcestring zorgt al voor je ResStringRec structuur.

    Jij wilt deze natuurlijk ook voor onbekende strings aanmaken (zonder dat je de Consts.pas gebruikt) ?
    Hoe ga je de vertaling doen (ik vond het makkelijker gewoon Consts.pas te vervangen door een kopie in mijn eigen source-directory te zetten)?

    Edit: Misschien heb je hier wat aan als je de resoucestrings wilt wijzigen:
    http://stackoverflow.com/a/26089036/1037511
    Maar het is misschien ook even handig als je precies vertelt wat nu de bedoeling is.
    Als ik bijvoorbeeld zeg ID 65100... in wat wil jij die dan wijzigen?
    Of ga je die eerst uitlezen... vertalen... en dan weer terugschrijven?
    Hoe doet je programma dan die vertaling?
    Last edited by rvk; 26-Oct-14 at 17:08.

  13. #13
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Thanks. Ik zal de links bekijken...


    Resourcestrings zitten her en der verstopt in diverse units. soms ook onder de implementation.
    Vandaar dat ik ze wil verzamelen in mijn "eigen" lijst tijdens de ontwikkeling. En dan bewaren in mijn externe bestandje. En daarna een vertalingsbestand maken. Want het gaat hier natuurlijk om taal
    Dus wil ik ze terug kunnen vinden op de index <= 65535.

    --- Edit: HookResourceString(@SMsgDlgNo, 'Nope') werkt inderdaad bij mij ook ---
    Last edited by Anoniem; 26-Oct-14 at 17:29.

  14. #14
    Ik denk dat controleren op ID niet zo handig is. Één wijziging in je source zou de hele volgorde in de war kunnen gooien. (Staat "Nee" altijd op hetzelfde ID-nummer, kan ik me niet voorstellen). Dus je zult sowieso moeten controleren op oude string en nieuwe string (en niet op ID-nummer).

  15. #15
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Klopt... Misschien moet ik ergens in de source een harde array of pointers bewaren of zo. (maar dan nog heb ik die pointers nodig)
    De volgorde is niet echt voorspelbaar, behalve dat wanneer ik een nieuwe toevoeg deze een lager nummer krijgt dan de laagste van de versie voordat ik hem toevoegde.
    Vertaling is altijd een lastig ding... Maar ik ben vastbesloten mijn eigen oplossing erdoor te duwen

Page 1 of 2 1 2 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •