作成動機
- ある条件を満たすウィンドウのハンドル(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
のおかげで、関数オブジェクトをカジュアルに使えるようになりましたね。