Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Alle resourcestrings der aktuellen Exe auflisten (https://www.delphipraxis.net/95813-alle-resourcestrings-der-aktuellen-exe-auflisten.html)

ImpactMG 13. Jul 2007 14:15


Alle resourcestrings der aktuellen Exe auflisten
 
Hallo,

Ist es irgendwie möglich die Liste aller Resourcestrings die im Sourcecode angeführt sind zu bekommen?

Meine Idee: Alle Fehlermeldungen im Programm werden mittels Resourcestring deklariert (damit schön mit SiSulizer übersetzbar). Der Benutzer bekommt vom Exceptionhandler den Identifier des Resourcestrings als Fehlernummer angezeigt. Ich brauche jetzt ein Mapping von allen Resourcestrings auf die Identifier (und/oder zurück), damit ich von der Fehlernummer aus erkennen kann welcher Resourcestring es war, und welche Stelle im Sourcecode betroffen ist.

Gibt es dafür eine Lösung?

Danke und lg
Marius

negaH 13. Jul 2007 14:31

Re: Alle resourcestrings der aktuellen Exe auflisten
 
Nein geht nicht direkt.

Die einfachste Lösung ist es am Anfang des Strings selber eine Nummer zu speichern. Also so

Delphi-Quellcode:
resourcestring
  sFehler = '123: Fehler bei XYZ aufgetreten';
Bei jedem Zugriff auf einen Resourcestring ist der String ein normaler LongString. Also zum Zeitpunkt wenn die Exception diesen String übergeben bekommt ist es ein LongString und es existiert keine Verbindung mehr zu einer Resource. Das "Laden" der Resourcestrings macht der Laufzeitcode vollständig transparent. Also schon während der Laufzeit wurden die Resourcestring in LongString quasi geladen und konvertiert. Das macht der RTL Code auf Anlass des Compilers zum Zeitpunk der Initialisierung einer Unit, also bevor die Initialization Sektion der Unit aufgerufen wird. Egal ob im Source auch Initialization steht oder nicht, eine Unit hat diese "Initialization Funktion" immer. Und davor werden die Resourcestring real geladen in LongStrings.

Davon abgesehen gilt folgendes: Jeder String der als Resource gespeichert wurde bekommt eine eindeutige ID. Die Vergabe dieser ID macht der Linker vollständig transparent für uns. Dh. jedesmal nach der Deklaration eines neuen Resourcestrings ändern sich ALLE IDs dieser Strings in der Resource. Ein Resourcestring hat also aus Sicht des Programmieres in Delphi keine vorhersagebare und immer gleiche ID in der String-Resource der EXE.

Es gibt einen Weg, definitiv, aber der würde nahe an einem Hack liegen. Der RTL Code der einen Resourcestring lädt muß ja selber wissen welche Resource-ID in der String-Resource der EXE diesem zugeordnet ist. Dazu speichert der Linker eine Tabelle zum Resourcestring ab in der eine Basis-ID drinnensteht. Man kann über Zeigerarithmetik an diese "Tabelle" rankommen und so auch an die IDs der Resourcestrings. Damit weist DU aber eben noch nicht welcher reale String, eg. Text, sich hinter dieser ID verbirgt. Kompiliert man neu so kann es durchaus sein das sich diese ID zum Text ändert.

[edit]
Schau mal in Unit System.pas, da findest du

Delphi-Quellcode:
type
  PResStringRec = ^TResStringRec;
  TResStringRec = packed record
    Module: ^Longint;
    Identifier: Integer;
  end;

procedure Test;
resourcestring
  sTest = 'Test String Resource';
var
  Msg: PResStringRec;
begin
  Msg := @sTest;
 
  ShowMessage(LoadResString(Msg));
end;
Der Resourcestring wird also als Zeiger vom Typ PResStringRec angesprochen, eg. konvertiert. Das Member .Indetifier enthält entwerder die reale Resource ID des zugehörigen Strings aus der Resource der EXE oder den LongString selber. Sollte .Identifier < $10000 sein, sprich das höherwertige Word des Cardinals = 0 sein, so ist es eine Resource ID. Der String muß dann aus der EXE geladen werden. Danach wird .Identifier aber als Zeiger eines LongString abgesprochen. Dh. beim Zugriff auf einen Resourcestring wird nur beim 1. mal der String aus der EXE geladen, danach steht er fertig im Speicher und wird nicht mehr nachgeladen.

Schau dir die Implementierung in Unit System.pas von LoadResString() genauer an.

[/edit]

Gruß Hagen

ImpactMG 14. Jul 2007 23:50

Re: Alle resourcestrings der aktuellen Exe auflisten
 
hallo,

wow, vielen dank für die ausführliche Antwort!

den code in den string einzuspeichern wäre eine idee, aber dann kann er auch lokalisiert werden, das möchte ich nicht dass der dolmetscher da was ändern kann

leider wird meine frage nicht beantwortet wie ich die liste aller Resourcestring-IDs meiner exe bekommen kann. sowas wie GetAllResourceStrings ist glaube ich nicht möglich.

das problem habe ich nun folgendermassen gelöst:
ich habe nun eine eigene Exceptionklasse implementiert die als Parameter einen Pointer auf einen Resourcestring überimmt.

Delphi-Quellcode:
constructor EResException.Create(const ResString: PResStringRec; const Postfix: String = '');
begin
  Message := LoadResString(ResString)+Postfix;
  Identifier := ResString.Identifier;
end;
der Exceptionhandler gibt den Identifier im Messagedialog aus.

inzwischen habe ich herausgefunden dass delphi entsprechend konfiguriert ein .drc file generiert. dort steht alles was ich brauche (Automatisch vergebener Identifier - für mich nun die Fehlernummer, resourcestringname, originalwert):

#define FHaupt_S_FHAUPT_OUTLOOK_KANN_NICHT_GESTARTET_WERDE N 64131
FHaupt_S_FHAUPT_OUTLOOK_KANN_NICHT_GESTARTET_WERDE N, "Outlook kann nicht gestartet werden"

zu einer exe kann ich also aus dem .drc file den zugehörigen resourcestring raussuchen, sowie die original-fehlermeldung

lg
marius

negaH 14. Jul 2007 23:59

Re: Alle resourcestrings der aktuellen Exe auflisten
 
Zitat:

Delphi-Quellcode:
constructor EResException.Create(const ResString: PResStringRec; const Postfix: String = '');
begin
  Message := LoadResString(ResString)+Postfix;
  Identifier := ResString.Identifier;
end;

Das funktioniert so nicht. Dein "Identifier" mal typcasted nach Pointer(Identifier) ist gleich Pointer(Message); Dh. der Identifier eines PResStringRec ist beim allerersten Laden = Aufruf von LoadResString() die Resource-ID zum ResourceString. Sollte das der Fall sein so wird LoadResString() diesen String aus der Resource laden und dann in .Identifier zwischenspeichern.

Schau dir mal ResString.Identifier im Debugger mal VOR und NACH den Aufruf von LoadResString() an.

Gruß Hagen

marabu 15. Jul 2007 07:35

Re: Alle resourcestrings der aktuellen Exe auflisten
 
Guten Morgen Marius,

Zitat:

Zitat von ImpactMG
... Ist es irgendwie möglich die Liste aller Resourcestrings die im Sourcecode angeführt sind zu bekommen? ...

hast du dir schon mal das Projekt $(DELPHI)\Demos\ResXplor angeschaut?

Grüße vom marabu

ImpactMG 15. Jul 2007 19:50

Re: Alle resourcestrings der aktuellen Exe auflisten
 
na bum

negaH: sorry, habe beim ersten Lesen nicht ganz verstanden. jetzt ist es mir klar

ResXplor würde mir helfen die resourcestrings aus der exe zu laden. Seht Ihr aber eine Möglichkeit in meiner Exceptionklasse irgendwie (auch nach dem ersten Zugriff) zu einem übergebenen PResStringRec auf den Identifier ranzukommen und damit die Exceptionklasse funktionsfähig zu machen?

Wenn ich irgendwie die Tabelle aller ResourceStrings hätte, könnte ich beim Programmstart mir die Identifier merken...

Ideen?

negaH 15. Jul 2007 20:20

Re: Alle resourcestrings der aktuellen Exe auflisten
 
Du möchtest deine Strings mit einer immer absoluten ID vergeben, als Fehlernummer. Bau es in den String selber ein, setzte nach der Nummer ein Doppelpunkt, in deiner Exception Klasse entferntst du diese Nummer, wenn du es als unschön empfindest. Eine Zahl aus dem Deutschen ins Russische/Japanische/usw. übersetzt erbigt die gleiche Zahl.
Geschätzter Aufwand: 10 Minuten.

Es gibt für alles eine Lösung, aber bei den ResourceStrings keine einfache. Die IDs verändern sich ständig also muß man die *.DRC Datei parsen. Der Konstanten Name ist immer gleich aber nicht dessen ID.

Gruß Hagen

ImpactMG 16. Jul 2007 09:33

Re: Alle resourcestrings der aktuellen Exe auflisten
 
die fehlernummern selbst zu vergeben möchte ich vermeiden. es geht um die umstellung eines grossen projekts. da ist der aufwand alles umzustellen und die fehlernummern zu verwalten recht gross. die lösung die intern vergebenen IDs der resourcestrings zu verwenden finde ich sehr elegant. dass sich damit die "fehlernummern" bei jeder release ändern stört mich nicht.
das einzige was fehlt ist immer zu einem resourcestring PResStringRec die entsprechende ID herausfinden zu können (auch beim zweiten aufruf des resourcestrings).

Zitat:

Zitat von negaH
Es gibt für alles eine Lösung, aber bei den ResourceStrings keine einfache. Die IDs verändern sich ständig also muß man die *.DRC Datei parsen. Der Konstanten Name ist immer gleich aber nicht dessen ID.

gibt es einen anhaltspunkt für die nicht einfache lösung?

gruss
marius

negaH 16. Jul 2007 09:42

Re: Alle resourcestrings der aktuellen Exe auflisten
 
Ich denk mal drüber nach, denke schon das man eine automatisierte Lösung finden kann.

Gruß Hagen

ImpactMG 16. Jul 2007 21:32

Re: Alle resourcestrings der aktuellen Exe auflisten
 
[quote="negaH"]
Zitat:

Schau dir mal ResString.Identifier im Debugger mal VOR und NACH den Aufruf von LoadResString() an.
das habe ich nun gemacht. es steht jedes mal gleicher wert drinnen! die information dass .identifier überschrieben wird scheint falsch zu sein

gruss
marius


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:53 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz