Einzelnen Beitrag anzeigen

Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.116 Beiträge
 
Delphi 11 Alexandria
 
#1

LoadString macht Probleme

  Alt 23. Nov 2002, 16:46
Moin Zusammen,

im Zusammenhang mit dem Auslesen von Resourcen bin ich gerade auf ein Problem gestossen.

Ich erzeuge mir eine Dateiliste (mit Pfaden) die ich dann in einer Schleife durchgehe, um mir die enthaltenen Resourcentypen und Namen herauszusammeln.
Als Ergebnis habe ich dann einen TreeView, in dem auf der obersten Ebene die Nodes als Text den Pfad der Datei haben, in der darunterliegenden Ebene die Resourcentypen, und unter diesen dann die Resourcennamen.
Das klappt auch soweit.
Jetzt wollte ich mir für den Typ RT_STRING auch jeweils gleich die Werte auslesen, und bin da auf ein Problem gestossen.

Durchgehen durch die Dateiliste:

Delphi-Quellcode:
procedure ExtractResourceInfo(const p_slFileList : TStringList;const p_tvRoot : TTreeView);

var
  i : integer;
  hFile : DWORD;
  tnWork : TTreeNode;

begin
  for i := 0 to p_slFileList.Count-1 do
  begin
    Application.ProcessMessages;
    hFile := LoadLibraryEx(PChar(p_slFileList[i]),0,LOAD_LIBRARY_AS_DATAFILE);
    try
      if (hFile <> 0) then
      begin
        tnWork := p_tvRoot.Items.Add(nil,p_slFileList[i]);
        EnumResourceTypes(hFile,@BuildResourceTypeList,integer(tnWork));
      end;
    finally
      if hFile <> 0 then
      begin
        FreeLibrary(hFile);
      end;
    end;
  end;
end;
Callback Funktion EnumResTypeProc

Delphi-Quellcode:
function BuildResourceTypeList(const p_hFile : DWORD;const p_pszType : PChar;p_pLParam : TTreeNode) : Boolean; stdcall;

const
  RT_HTML = MAKEINTRESOURCE(23);
  RT_MANIFEST = MAKEINTRESOURCE(24);

var
  tnWork : TTreeNode;
  sType : string;

begin
  if IS_INTRESOURCE(integer(p_pszType)) then
  begin
    case integer(p_pszType) of
      integer(RT_ACCELERATOR) : sType := 'RT_ACCELERATOR';
      integer(RT_ANICURSOR) : sType := 'RT_ANICURSOR';
      integer(RT_ANIICON) : sType := 'RT_ANIICON';
      integer(RT_BITMAP) : sType := 'RT_BITMAP';
      integer(RT_CURSOR) : sType := 'RT_CURSOR';
      integer(RT_DIALOG) : sType := 'RT_DIALOG';
      integer(RT_DLGINCLUDE) : sType := 'RT_DLGINCLUDE';
      integer(RT_FONT) : sType := 'RT_FONT';
      integer(RT_FONTDIR) : sType := 'RT_FONTDIR';
      integer(RT_GROUP_CURSOR) : sType := 'RT_GROUP_CURSOR';
      integer(RT_GROUP_ICON) : sType := 'RT_GROUP_ICON';
      integer(RT_HTML) : sType := 'RT_HTML';
      integer(RT_ICON) : sType := 'RT_ICON';
      integer(RT_MANIFEST) : sType := 'RT_MANIFEST';
      integer(RT_MENU) : sType := 'RT_MENU';
      integer(RT_MESSAGETABLE) : sType := 'RT_MESSAGETABLE';
      integer(RT_PLUGPLAY) : sType := 'RT_PLUGPLAY';
      integer(RT_RCDATA) : sType := 'RT_RCDATA';
      integer(RT_STRING) : sType := 'RT_STRING';
      integer(RT_VERSION) : sType := 'RT_VERSION';
      integer(RT_VXD) : sType := 'RT_VXD';
      else
        sType := '#'+IntToStr(integer(p_pszType));
    end;
    tnWork := TTreeView(p_pLParam.TreeView).Items.AddChild(p_pLParam,sType);
    EnumResourceNames(p_hFile,p_pszType,@BuildResourceNameTable,integer(tnWork));
  end
  else
  begin
    sType := trim(p_pszType);
    tnWork := TTreeView(p_pLParam.TreeView).Items.AddChild(p_pLParam,sType);
    EnumResourceNames(p_hFile,PChar(sType),@BuildResourceNameTable,integer(tnWork));
  end;
  Result := true;
end;
Callback Funktion EnumResNameProc

Delphi-Quellcode:
function BuildResourceNameTable(const p_hFile : DWORD;const p_pszType : PChar;const p_pszName : PChar;const p_pLParam : TTreeNode) : Boolean; stdcall;

var
  sName : string;
  szBuffer : PChar;

begin
  if IS_INTRESOURCE(integer(p_pszName)) then
  begin
    sName := '#'+IntToStr(integer(p_pszName));
  end
  else
  begin
    sName := trim(p_pszName);
  end;
  if p_pszType = RT_STRING then
  begin
    if p_hFile <> 0 then
    begin
      szBuffer := StrAlloc(65536);
      try
        // [color=red]Hier schlägt's fehl mit der Meldung, dass die angegebene Resource nicht gefunden werden konnte[/color]
        if LoadString(p_hFile,integer(p_pszName),szBuffer,65535) <> 0 then
        begin
          sName := sName + ' / '+trim(szBuffer);
        end
        else
        begin
          sName := sName + ' / '+SysErrorMessage(GetLastError);
        end;
      finally
        StrDispose(szBuffer);
      end;
    end;
  end;
  TTreeView(p_pLParam.TreeView).Items.AddChild(p_pLParam,sName);
  Result := true;
end;

Als Paramter für die Resource habe ich es auch schon mit cardinal und PChar(sName) probiert (auch wenn letzteres ja eigentlich Unsinn ist).
Das Ergebnis war immer das gleiche.
Ausser z.B. bei der Kernel32 bei der die eine oder andere RT_STRING Resource ausgelesen wurde (ob korrekt oder nicht sei mal dahingestellt) kommt immer nur der Fehler, dass die Resource nicht gefunden wurde.
Interessant dabei: Es wurden nicht alle aus der Kernel32 ausgelesen, nur ein paar (vier um genau zu sein, nämlich 1, 2, 1025 und 1089).

Was auch noch auffiel:
Ich hatte es unmittelbar vor dem LoadString auch schon mal mit GetModuleHandle versucht um ein Handle auf die geladene Datei zu bekommen. Dies schlug mit schöner Regelmässigkeit fehl mit der Meldung, dass das Modul nicht gefunden werden konnte. Da es aber über LoadLibraryEx geladen wurde (sonst wären ja die Enum Funktionen gar nicht aufgerufen worden) kann das irgendwie auch nicht sein, ausser LOAD_LIBRARY_AS_DATAFILE verhindert die erfolgreiche Suche von GetModuleHandle.
Wäre denkbar, denn bei Kernel32 schlug's nicht fehl, und die wird ja zu jedem Prozess geladen.

Hat irgendjemand 'ne Idee?

BTW: Getestet unter W2K SP2
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat