Edited at

条件後入れでウィンドウハンドルを取得できる「WindowExplorerクラス」をつくった

More than 3 years have passed since last update.


作成動機


  • ある条件を満たすウィンドウのハンドル(HWND)を取得したい


  • FindWindowでいいじゃん!

  • ターゲットとなるWindowが複数個あったらダメ


  • EnumWindowがあるじゃん!

  • コールバックEnumWindowsProcが融通きかない!条件かわると使いまわせない!

  • じゃあ内部でEnumWindowしつつ、検索条件をstd::<function>で受け取るクラス作るわ

という経緯です。


使いかた


タイトルが”hello”をさがす

const auto title_is_hello = [](HWND hwnd) -> bool {

TCHAR buffer[MAX_PATH] = {0};
::GetWindowText( hwnd,buffer,MAX_PATH );
return _tcscmp(_T("hello"), buffer) == 0;
};

const HWND hwnd = WindowExplorer::Search(title_is_hello);



クラス名が”hoge”で子ウィンドウのクラス名が”fuga”

const auto class_is_hoge = [](HWND hwnd) -> bool {

TCHAR buffer[MAX_PATH] = {0};
::GetClassName( hwnd,buffer,MAX_PATH );
return _tcscmp(_T("hoge"), buffer) == 0;
};

const auto class_is_fuga = [](HWND hwnd) -> HWND {
return ::FindWindowEx(hwnd, nullptr, _T("fuga"), nullptr);
};
const HWND hwnd = WindowExplorer::Search(class_is_hoge, class_is_fuga);



実装コード

#include <functional>

typedef std::function<bool(HWND)> IsMatchedWindow;
typedef std::function<HWND(HWND)> GetMatchedWindow;

class WindowExplorer
{
public:
static HWND Search(IsMatchedWindow _condition, GetMatchedWindow _getter = nullptr)
{
WindowCondition Condition(_condition, _getter);
::EnumWindows( EnumWindowsProc, (LPARAM)&Condition );
return Condition.GetHandle();
}

private:

class WindowCondition
{
private:
HWND hFoundWnd;
IsMatchedWindow IsMatchedWindow_;
GetMatchedWindow GetMatchedWindow_;

public:
WindowCondition(IsMatchedWindow cond, GetMatchedWindow getter=nullptr)
: IsMatchedWindow_(cond)
, GetMatchedWindow_(getter)
, hFoundWnd(nullptr)
{}

inline HWND GetHandle()const { return hFoundWnd; }
bool found(HWND hwnd)
{
if ( IsMatchedWindow_(hwnd))
{
hFoundWnd = ( GetMatchedWindow_ )? GetMatchedWindow_(hwnd) : hwnd;
return hFoundWnd != nullptr;
}
return false;
}
};

static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam )
{
WindowCondition* condition = reinterpret_cast<WindowCondition*>(lParam);

if ( !condition )
return FALSE;

if ( condition->found(hwnd) )
return FALSE;

return TRUE;
}
};

C++11の、ラムダ式とstd::functionのおかげで、関数オブジェクトをカジュアルに使えるようになりましたね。