Entwickler-Ecke

Windows API - Ordnerauswahl-Dialogbox


schitho - Sa 05.06.04 23:06
Titel: Ordnerauswahl-Dialogbox
Hi,

ich verwende folgenden Code aus SwissDelphiCenter [http://www.swissdelphicenter.ch/de/showcode.php?id=1802], um eine Dialogbox zur Auswahl von Ordnern anzeigen zu lassen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
{....}

uses
  ShlObj, ActiveX;

{....}


{
  This code shows the SelectDirectory dialog with additional expansions:
  - an edit box, where the user can type the path name,
  - also files can appear in the list,
  - a button to create new directories.


  Dieser Code zeigt den SelectDirectory-Dialog mit zusätzlichen Erweiterungen:
  - eine Edit-Box, wo der Benutzer den Verzeichnisnamen eingeben kann,
  - auch Dateien können in der Liste angezeigt werden,
  - eine Schaltfläche zum Erstellen neuer Verzeichnisse.
}


function AdvSelectDirectory(const Caption: stringconst Root: WideString;
  var Directory: string; EditBox: Boolean = False; ShowFiles: Boolean = False;
  AllowCreateDirs: Boolean = True): Boolean;
  // callback function that is called when the dialog has been initialized
  //or a new directory has been selected

  // Callback-Funktion, die aufgerufen wird, wenn der Dialog initialisiert oder
  //ein neues Verzeichnis selektiert wurde
  function SelectDirCB(Wnd: HWND; uMsg: UINT; lParam, lpData: lParam): Integer;
    stdcall;
  var
    PathName: array[0..MAX_PATH] of Char;
  begin
    case uMsg of
      BFFM_INITIALIZED: SendMessage(Wnd, BFFM_SETSELECTION, Ord(True), Integer(lpData));
      // include the following comment into your code if you want to react on the
      //event that is called when a new directory has been selected
      // binde den folgenden Kommentar in deinen Code ein, wenn du auf das Ereignis
      //reagieren willst, das aufgerufen wird, wenn ein neues Verzeichnis selektiert wurde
      {BFFM_SELCHANGED:
      begin
        SHGetPathFromIDList(PItemIDList(lParam), @PathName);
        // the directory "PathName" has been selected
        // das Verzeichnis "PathName" wurde selektiert
      end;}

    end;
    Result := 0;
  end;
var
  WindowList: Pointer;
  BrowseInfo: TBrowseInfo;
  Buffer: PChar;
  RootItemIDList, ItemIDList: PItemIDList;
  ShellMalloc: IMalloc;
  IDesktopFolder: IShellFolder;
  Eaten, Flags: LongWord;
const
  // necessary for some of the additional expansions
  // notwendig für einige der zusätzlichen Erweiterungen
  BIF_USENEWUI = $0040;
  BIF_NOCREATEDIRS = $0200;
begin
  Result := False;
  if not DirectoryExists(Directory) then
    Directory := '';
  FillChar(BrowseInfo, SizeOf(BrowseInfo), 0);
  if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nilthen
  begin
    Buffer := ShellMalloc.Alloc(MAX_PATH);
    try
      RootItemIDList := nil;
      if Root <> '' then
      begin
        SHGetDesktopFolder(IDesktopFolder);
        IDesktopFolder.ParseDisplayName(Application.Handle, nil,
          POleStr(Root), Eaten, RootItemIDList, Flags);
      end;
      OleInitialize(nil);
      with BrowseInfo do
      begin
        hwndOwner := Application.Handle;
        pidlRoot := RootItemIDList;
        pszDisplayName := Buffer;
        lpszTitle := PChar(Caption);
        // defines how the dialog will appear:
        // legt fest, wie der Dialog erscheint:
        ulFlags := BIF_RETURNONLYFSDIRS or BIF_USENEWUI or
          BIF_EDITBOX * Ord(EditBox) or BIF_BROWSEINCLUDEFILES * Ord(ShowFiles) or
          BIF_NOCREATEDIRS * Ord(not AllowCreateDirs);
        lpfn    := @SelectDirCB;
        if Directory <> '' then
          lParam := Integer(PChar(Directory));
      end;
      WindowList := DisableTaskWindows(0);
      try
        ItemIDList := ShBrowseForFolder(BrowseInfo);
      finally
        EnableTaskWindows(WindowList);
      end;
      Result := ItemIDList <> nil;
      if Result then
      begin
        ShGetPathFromIDList(ItemIDList, Buffer);
        ShellMalloc.Free(ItemIDList);
        Directory := Buffer;
      end;
    finally
      ShellMalloc.Free(Buffer);
    end;
  end;
end;


// Example:
procedure TForm1.Button1Click(Sender: TObject);
var
  dir: string;
begin
  AdvSelectDirectory('Caption''c:\', dir, False, False, True);
  Label1.Caption := dir;
end;


Wie muss ich den Code verändern, damit das Fenster zentriert angezeigt wird?

Gruß
Thomas


Delete - So 06.06.04 14:53

Zentrier das Fenster in der Callback-Funktion mit SetWindowPos.


schitho - So 06.06.04 20:30

Hi,

versteh ich das richtig:

Zuerst mit Screen.Width bzw. Screen.Hight die Bildschirmgröße, dann mit GetWindowRect die Fenstergröße ermitteln. Daraus die neuen Koordinaten errechnen. Dann diese neuen Koordinaten mit SetWindowPos festlegen.

Geht das so?

Gruß
Thomas


Delete - Mo 07.06.04 12:48

Ich an deiner Stelle hätte da smalö eben schnell ausprobiert, anstatt 24 Stunden auf eine Antwort zu warten. ;)


schitho - Mo 07.06.04 17:56

Luckie hat folgendes geschrieben:
Ich an deiner Stelle hätte da smalö eben schnell ausprobiert, anstatt 24 Stunden auf eine Antwort zu warten. ;)


Hätte ich eh gemacht, wenn ich dafür die Zeit gehabt hätte. Außerdem dachte ich mir, dass es vielleicht auch einen Windows-Befehl gibt, der für die Zentrierung sorgt.

Muss man denn alles selber machen :wink:

Gruß
Thomas


Delete - Mo 07.06.04 18:01

schitho hat folgendes geschrieben:
Muss man denn alles selber machen :wink:

Arbeitest du mit Windows?
Ist der Papst katholisch?

:mrgreen:


schitho - Mo 07.06.04 18:08

MathiasSimmack hat folgendes geschrieben:

Arbeitest du mit Windows?
:mrgreen:


Manchmal - ja leider :nut:


schitho - Mo 07.06.04 23:12

Nun zurück zu meinem ursprünglichen Problem:

Ich hab probeweise in der Callback Funktion am Ende folgende Zeile angefügt:


Delphi-Quelltext
1:
SetWindowPos(wnd,wnd,20,20,100,500,0);                    


Doch leider bewirkt diese Zeile gar nichts. Das Fenster öffnet sich noch immer an der ursprünglichen Stelle.

Was ist daran falsch?

Die Callback-Funktion sieht nun so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
 function SelectDirCB(Wnd: HWND; uMsg: UINT; lParam, lpData: lParam): Integer;
    stdcall;
  var
    PathName: array[0..MAX_PATH] of Char;
    FRect : TRect; // ***** Hab ich ergänzt *****

  begin
    case uMsg of
      BFFM_INITIALIZED: SendMessage(Wnd, BFFM_SETSELECTION, Ord(True), Integer(lpData));
      // include the following comment into your code if you want to react on the
      //event that is called when a new directory has been selected
      // binde den folgenden Kommentar in deinen Code ein, wenn du auf das Ereignis
      //reagieren willst, das aufgerufen wird, wenn ein neues Verzeichnis selektiert wurde
      {BFFM_SELCHANGED:
      begin
        SHGetPathFromIDList(PItemIDList(lParam), @PathName);
        // the directory "PathName" has been selected
        // das Verzeichnis "PathName" wurde selektiert
      end;}

    end;
    SetWindowPos(wnd,wnd,20,20,100,500,0); // ***** Hab ich auch ergänzt ***** 
    Result := 0;
  end;


Danke für Eure Hilfe

Gruß
Thomas


Delete - Mo 07.06.04 23:31


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
function SelectDirCB(Wnd: HWND; uMsg: UINT; lParam, lpData: lParam): Integer; 
    stdcall
  var 
    PathName: array[0..MAX_PATH] of Char; 
    FRect : TRect; // ***** Hab ich ergänzt ***** 

  begin 
    case uMsg of 
      BFFM_INITIALIZED: 
      begin
        SendMessage(Wnd, BFFM_SETSELECTION, Ord(True), Integer(lpData)); 
        SetWindowPos(wnd,wnd,20,20,100,500,0); // ***** Hab ich auch ergänzt *****
      end;
      {BFFM_SELCHANGED: 
      begin 
        SHGetPathFromIDList(PItemIDList(lParam), @PathName); 
        // the directory "PathName" has been selected 
        // das Verzeichnis "PathName" wurde selektiert 
      end;}
 
    end
    Result := 0
  end;


schitho - Di 08.06.04 00:03

Hallo Luckie!

Danke für Deine prompte Antwort.

Doch leider funktioniert das auch nicht. Das Fenster befindet sich nicht an der angegebenen Position. :cry:

Hast Du noch eine Idee, woran das liegen könnte?

Gruß
Thomas


Delete - Di 08.06.04 00:14


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
// Callback-Funktion, die aufgerufen wird, wenn der Dialog initialisiert oder
  //ein neues Verzeichnis selektiert wurde
  function SelectDirCB(Wnd: HWND; uMsg: UINT; lParam, lpData: lParam): Integer;
    stdcall;
  var
    PathName: array[0..MAX_PATH] of Char;
  begin
    case uMsg of
      BFFM_INITIALIZED:
      begin
        SendMessage(Wnd, BFFM_SETSELECTION, Ord(True), Integer(lpData));
        SetWindowPos(Wnd, 0202000, SWP_NOSIZE or SWP_SHOWWINDOW);
      end;
    end;
    Result := 0;
  end;

Geht. :roll:


schitho - Di 08.06.04 00:33

Danke für Deine Hilfe

Gruß
Thomas