Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Library: Windows API / MS.NET Framework API (https://www.delphipraxis.net/20-library-windows-api-ms-net-framework-api/)
-   -   Delphi PickIconDialog (https://www.delphipraxis.net/101713-pickicondialog.html)

FAlter 17. Okt 2007 19:30


PickIconDialog
 
Hi,

Bei meinem TIcon-speicern-Problem bin ich auf einen Code mit PickIconDialog gestoßen, der nicht funktionierte - ganz offensichtlich ein Unicode-Problem. Die Suche in der DP hat mir gezeigt, dass auch andere ein PickIconDialog-Unicode-Problem hatten. Dort wurde es mit bedingter Compilierung gelöst. Ich habe das ganze so angepasst, dass zur Laufzeit die richtige Version verwendet wird.

Die Units SysUtils (RaiseLastOSError) Windows (Load und FreeLibrary, GetProcAddress) werden benötigt.

Delphi-Quellcode:
function PickIconDlg(hwndOwner: HWND; var lpstrFile: String;
  var lpdwIconIndex: LongInt): Boolean;
var
  Lib: THandle;
  PickIconDlgA: function(hwndOwner:HWND; lpstrFile: PAnsiChar; nMaxFile: DWORD;
    var lpdwIconIndex: LongInt): Longint; stdcall;
  PickIconDlgW: function(hwndOwner:HWND; lpstrFile: PWideChar; nMaxFile: DWORD;
    var lpdwIconIndex: LongInt): Longint; stdcall;
  WinVersion: DWord;
  WindowsMajorVersion: Byte;
  Unicode: Boolean;
  idx, Size: Integer;
  AnsiBuffer: AnsiString;
  WideBuffer: WideString;
begin
  Lib := LoadLibrary('SHELL32');
  if Lib <> 0 then
  try
    WinVersion := GetVersion;
    WindowsMajorVersion := Lo(WinVersion);

    Unicode := (WinVersion < $80000000) { NT-System } and
    (WindowsMajorVersion >= 5); { ab 2000 }

    idx := Length(lpstrFile);

    //size := Max(idx, MAX_PATH);
    if MAX_PATH > idx then
      size := MAX_PATH
    else
      size := idx;

    if Unicode then
    begin
      @PickIconDlgW := GetProcAddress(Lib, 'PickIconDlg');
      if not Assigned(@PickIconDlgW) then
        @PickIconDlgW := GetProcAddress(Lib, Pointer(62));
      if not Assigned(@PickIconDlgW) then
        RaiseLastOSError;

      WideBuffer := lpstrFile;
      SetLength(WideBuffer, size + 1);
      WideBuffer[idx+1] := #0;

      Result := PickIconDlgW(hwndOwner, PWideChar(WideBuffer), size,
        lpdwIconIndex) <> 0;
      if Result then
        lpstrFile := PWideChar(WideBuffer);
    end
    else
    begin
      @PickIconDlgA := GetProcAddress(Lib, Pointer(62));
      if not Assigned(@PickIconDlgA) then
        RaiseLastOSError;

      AnsiBuffer := lpstrFile;
      SetLength(AnsiBuffer, size + 1);
      AnsiBuffer[idx+1] := #0;

      Result := PickIconDlgA(hwndOwner, PAnsiChar(AnsiBuffer), size,
        lpdwIconIndex) <> 0;
      if Result then
        lpstrFile := PAnsiChar(AnsiBuffer);
    end;
  finally
    if not FreeLibrary(Lib) then
      RaiseLastOSError;
  end
  else
    RaiseLastOSError;
end;
Hintergrund: Ab Windows 2000 (NT 5.0) ist der PickIconDialog Unicode, vorher war er ANSI. Daher wird bei NT-Systemen mit einer Major-Version von 5 oder höher der Code für Unicode ausgeführt, sonst der für ANSI. Des weiteren ist er bei älteren Systemen als nur per Index erreichbar, weshalb auf diesen zugegriffen wird, wenn GetProcAddress mit Namen fehlschlägt.

Mfg
FAlter

Dezipaitor 18. Okt 2007 17:48

Re: PickIconDialog
 
die MSDN (*) schreibt, dass die Funktion erst ab Windows XP existiert.
Übrigens: Der letzte Rückgabewert geschrieben in lpdwIconIndex muss ein Integer sein laut Definition.
Am besten wäre es, wenn die Funktion über LoadLibrary und so geladen wird.

(*)
Die MSDN konnte den Eintrag nicht finden. Ich habe daher im Cache von Google gesucht und gefunden:
http://209.85.135.104/search?q=cache...ient=firefox-a

FAlter 18. Okt 2007 21:34

Re: PickIconDialog
 
Hi,

Zitat:

Zitat von Dezipaitor
die MSDN (*) schreibt, dass die Funktion erst ab Windows XP existiert.

Keine Ahnung, wusste davon nichts. Der Code funktioniert auch z. B. unter Windows 98 (selbst getestet; dort aber eben mit ANSI). Was wohl erst seit XP geht ist:

Delphi-Quellcode:
function ...
external 'SHELL32.DLL' name 'PickIconDlg';
Daher verwendete man zuvor nur index. Natürlich erhält man da - und nicht ohne Grund - ne Meldung von wegen Platformunabhängigkeit. Eventuell sollte man daher die OS-Unterscheidung nur machen, wenn GetProcAdress nil zurückliefert bei 'PickIconDlg'. Dann müsste man LoadLibrary nehmen, damits nicht beim Programmstart ne hübsche Meldung gibt bei altem OS.

Zitat:

Übrigens: Der letzte Rückgabewert geschrieben in lpdwIconIndex muss ein Integer sein laut Definition.
Geändert nach Longint.

Zitat:

Am besten wäre es, wenn die Funktion über LoadLibrary und so geladen wird.
Siehe oben. Heute Abend ist mir das aber zu spät, noch was großes zu ändern.

Gute Nacht
FAlter

Luckie 19. Okt 2007 08:46

Re: PickIconDialog
 
Die Plattformunabhängigkeit bezieht sich auf Linux und Windows und hat nichts mit der Windows Version zu tun.

Dezipaitor 19. Okt 2007 10:34

Re: PickIconDialog
 
Ich schätze, dass die MSDN WinXP als Minimum angibt, weil die Funktion davor als inoffiziel gilt.

FAlter 19. Okt 2007 10:36

Re: PickIconDialog
 
Hi,

Zitat:

Zitat von Luckie
Die Plattformunabhängigkeit bezieht sich auf Linux und Windows und hat nichts mit der Windows Version zu tun.

Und ich kann mich darauf verlassen, dass die 62 auch für alle zukünftigen Windows-Versionen gilt?

Zitat:

Zitat von Dezipaitor
Ich schätze, dass die MSDN WinXP als Minimum angibt, weil die Funktion davor als inoffiziel gilt.

Vermutlich, denn vorher war sie auch nicht über ihren Namen ansprechbar. Und eben das ANSI-oder-Unicode.Problem. Eine offizielle Funktion hätte damals wohl beide Varianten gehabt.

[edit]

Zitat:

Zitat von TurboDelphi-Hilfe
Return Value

Returns 1 if successful, or 0 if it fails.

Was heißt das, if it fails? Kann man gar nicht zwischen Fehler und Abbrechen geklickt unterscheiden?

[/edit]

Mfg
FAlter

Dezipaitor 19. Okt 2007 10:53

Re: PickIconDialog
 
Auf die Nummer 62 kannst du dich nur dann verlassen, wenn es in der MSDN so steht.
Da für ältere Windowsversionen wohl eh kein Update mehr kommt, wird das auch nicht geändert.


Zu Abbrechen - überprüfe mal mit GetLastError, ob abgebrochen wurde. Oder den Parameter mit dem Bildindex - vielleicht ist dieser -1 ?.

FAlter 19. Okt 2007 11:27

Re: PickIconDialog
 
Hi,

habe jetzt den LoadLibrary-Ansatz verfolgt. Bei neuem OS wird der Index nur verwendet, wenn GetProcAddress mit Angabe des Namen fehlschlägt.

Im Gegensatz zu anderen Funktionen steht unter ms-help://borland.bds4/shellcc/platform/shell/reference/functions/pickicondlg.htm (PickIconDialog+F1) nicht da, dass GetLastError einen weiterbringt. Also keine Möglichkeit, einen Fehler zu erkennen. Existiert allerdings z. B. die Datei nicht, gibts ne MessageBox, und danach wird die SYSTEM32.DLL selbst angezeigt (und natürlich der zurückgegebene Dateiname wird zu <System32-Verzeichnis>\System32.dll). Eventuell gibt es ja außer Abbrechen gar keinen "Fehlerfall".

Mfg
FAlter


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:44 Uhr.

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