2016-04-19 8 views
0

Ich hätte gerne eine einzelne ordentliche (schließen und selbständige) Funktion (nennen wir es GetDesktopHandle), die ein Handle auf das Desktop-Fenster zurückgibt. Ich benutze den folgenden Code. Aber es funktioniert nur in der DeskHandle ist eine globale Var.Wie verwende ich die Rückruffunktion von EnumWindows?

Wie loswerden dieser globalen Variable? Wenn ich es vor Ort machen erhalte ich eine AV in getDesktopWnd wenn ich DeskHandle versuchen: = hChild

VAR DeskHandle : HWND; 

function GetDesktopHandle: HWND; 

    function getDesktopWnd (Handle: HWND; NotUsed: Longint): bool; stdcall; { Callback function } 
    VAR hChild : HWND; 
    begin 
    if handle <> 0 then 
    begin 
     hChild := FindWindowEx(handle, 0, 'SHELLDLL_DefView', nil); 
     if hChild <> 0 then 
     begin 
     hChild := FindWindowEx(hChild, 0, 'SysListView32', nil); 
     if hChild <> 0 
     then DeskHandle := hChild; 
     end; 
    end; 
    Result:= TRUE; 
    end; 

begin 
DeskHandle := 0; 
EnumWindows(@getDesktopWnd, 0); 
Result:= DeskHandle; 
end; 

Die Hauptfrage ist: kann ich diesen Code als eine einzige Funktion schreiben, oder zumindest kann ich loswerden der externen/globalen var?

Mögliche Lösung:
Die Dokumentation besagt, dass der zweite Parameter nur ein IN-Parameter ist.

lParam [in] Typ: LPARAM Eine Anwendung definierten Wert an die Callback-Funktion übergeben werden.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx

wäre es falsch, es zu benutzen, das Ergebnis wieder passieren?

+1

Anstatt alle Top-Level-Fenster auf der Suche nach der Wurzel des Desktops aufzuzählen, können Sie einfach 'GetShellWindow' aufrufen, um direkt darauf zuzugreifen. Verwenden Sie dann 'FindWindowEx' zweimal, wie Sie es bereits tun. –

+0

Siehe auch http://StackOverflow.com/a/5691808/33732 –

+0

Es gibt eine vorhandene Funktion zum Abrufen des Desktop-Fenster-Handle und es heißt [GetDesktopWindow] (https://msdn.microsoft.com/en-us/library /windows/desktop/ms633504(v=vs.85).aspx) – Remko

Antwort

1
type 
    TMyData = record 
    Handle: HWND; 
    Pid: DWORD; 
    Caption: String; 
    ClassName: String; 
    end; 
    PMyData = ^TMyData; 

function GetWindowClass(const Handle: HWND): String; 
begin 
    SetLength(Result, MAX_PATH); 
    SetLength(Result, GetClassName(Handle, PChar(Result), Length(Result))); 
end; 

function GetWindowCaption(const Handle: HWND): String; 
begin 
    SetLength(Result, MAX_PATH); 
    SetLength(Result, GetWindowText(Handle, PChar(Result), Length(Result))); 
end; 

function EnumChildWindowsProc(Handle: THandle; MyData: PMyData): BOOL; stdcall; 
var 
    ClassName: String; 
    Caption: String; 
    Pid: DWORD; 
begin 
    ClassName := GetWindowClass(Handle); 
    Caption := GetWindowCaption(Handle); 

    Result := (ClassName = 'SysListView32') and (Caption = 'FolderView'); 
    if Result then 
    begin 
    MyData.Handle := Handle; 
    GetWindowThreadProcessId(Handle, MyData.Pid); 
    MyData.Caption := Caption; 
    MyData.ClassName := ClassName; 
    end; 

    // To continue enumeration, the callback function must return TRUE; 
    // to stop enumeration, it must return FALSE 
    Result := not Result; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    MyData: TMyData; 
begin 
    ZeroMemory(@MyData, SizeOf(MyData)); 
    EnumChildWindows(GetDesktopWindow, @EnumChildWindowsProc, NativeInt(@MyData)); 
    if MyData.Handle > 0 then 
    begin 
    ShowMessageFmt('Found Window in Pid %d', [MyData.Pid]); 
    end 
    else begin 
    ShowMessage('Window not found!'); 
    end; 
end; 
+0

Das Besondere an 'Handle' ist eher positiv als negativ. Ein übersichtlicherer Test ist 'if MyData.Handle <> 0 then '. Und 'Ergebnis: = nicht Ergebnis' ist ziemlich seltsam, nur um eine lokale Variable zu speichern! –

+0

@DavidHeffernan 'THandle = NativeUInt' also kann es nicht negativ sein.Über das Ergebnis var, ich habe tatsächlich eine lokale Variable gespeichert, aber es wirkt sich negativ auf die Lesbarkeit des Codes aus, also stimme mit Ihnen überein ... – Remko

+0

Semantisch ist 0 ein Sentinel. Bestellung ist nicht relevant. –

3

Lokale Funktionen können nicht als Rückrufe verwendet werden. Wenn Sie den Operator @ nicht verwendet hätten, um Ihre Funktion zu übergeben, hätte Ihnen der Compiler das gesagt. (Mit dem Operator wird das Argument in einen gewöhnlichen untypisierten Zeiger umgewandelt, so dass der Compiler das nicht mehr überprüfen kann.)

Sie müssen Ihren Rückruf als eigenständige Funktion ausführen.

Verwenden Sie zum Übergeben von Daten zwischen dem Rückruf und dem Aufrufer den zweiten Parameter, den Sie derzeit NotUsed nennen. Sie könnten beispielsweise einen Zeiger an eine Handle-Variable übergeben, und dann könnte der Callback den Zeiger dereferenzieren, um ein Ergebnis zurückzugeben.

+0

Danke Rob (und +1). Ich wollte die Ergebnisbank über die NotUsed-Variable übergeben, aber die Dokumentation besagt, dass die Variable Parameter von Caller zu Callback übergeben soll, nicht umgekehrt. https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx – Ampere

+0

Der Parameter, den Sie übergeben, ist eine Adresse, und diese Adresse geht tatsächlich vom Aufrufer zum Empfänger. Sie sind verantwortlich für das, was der Empfänger mit dem Wert tut, den er empfängt. Sie können wählen, dass dieser Wert dereferenziert wird. –