2016-04-19 16 views
0

私はデスクトップウィンドウへのハンドルを返す単一のきちんとした(閉じた、自己完結型の)関数(GetDesktopHandleと呼ぶ)を持っていたいと思います。私は以下のコードを使用します。しかし、それはDeskHandleでのみ動作し、グローバル変数です。EnumWindowsコールバック関数の使用方法は?

このグローバル変数を削除するにはどうすればよいですか?私はそれをローカルにする場合は、私がDeskHandleしようとすると、私はgetDesktopWndでAVを得る:= 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; 

主な質問がある:私は、単一の関数として、このコードを書くことができますあるいは、少なくとも、私は取り除くことができます外部/グローバルvarの?

解決策:
ドキュメントには、2番目のパラメータはINパラメータにすぎないことが記載されています。

lParamに タイプ[IN]:LPARAM コールバック関数に渡されるアプリケーション定義の値。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx

戻って結果を渡すためにそれを使用するために間違っているだろうか?

+1

デスクトップのルートを探しているすべてのトップレベルウィンドウを列挙する代わりに、 'GetShellWindow'を呼び出して直接そのウィンドウに行くことができます。次に、 'FindWindowEx'を2回使用します。 –

+0

も参照してくださいhttp://stackoverflow.com/a/5691808/33732 –

+0

デスクトップウィンドウハンドルを取得する既存の関数があり、[GetDesktopWindow](https://msdn.microsoft.com/en-us/library)と呼ばれています。 /windows/desktop/ms633504(v=vs.85).aspx) – Remko

答えて

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

'Handle'が負ではなく肯定的なことは特別です。より明確なテストは 'If MyData.Handle <> 0 then'です。そして、 '結果:=結果ではない'は、ローカル変数を保存するためにはかなり変です! –

+0

@DavidHeffernan 'THandle = NativeUInt'なので、負であってはいけません。結果varについては、実際にはローカル変数を保存していましたが、コードの可読性に悪影響を与えますので、そこに同意してください。 – Remko

+0

意味的に0はセンチネルです。順序は関係ありません。 –

3

ローカル関数をコールバックとして使用することはできません。 @演算子を使用して関数を渡さなかった場合、コンパイラはそれをあなたに伝えていました。 (演算子を使用すると、引数は通常の型なしポインタに変換されるので、コンパイラはこれ以上チェックできません)。

コールバックをスタンドアロン関数にする必要があります。

コールバックと呼び出し元の間でデータを渡すには、2番目のパラメータ(現在はNotUsed)を使用します。たとえば、ハンドル変数にポインタを渡すと、コールバックはポインタを参照解除して結果を返す可能性があります。

+0

ありがとうRob(と+1)。私は結果バンクをNotUsed変数に渡したいと思いましたが、ドキュメントでは変数がコールバックからコールバックにパラメータを渡すことを言います。 https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx – Ampere

+0

渡すパラメータはアドレスであり、そのアドレスは実際に発信者から送られます受信機に送信する。レシーバが受け取る価値をあなたが担当しています。あなたはその価値を逆参照させることを選択できます。 –

関連する問題