質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.60%

起動中のウィンドウのハンドルとタイトル名の取得方法(タスクマネージャーに表示されるものと一致させる)

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 7,255

score 27

前提・実現したいこと

windows7のタスクマネージャーを起動し、アプリケーションのタブを選択した時にタスクの欄に表示されているウィンドウ名と同じウィンドウのハンドルとタイトル名を取得したいのですがうまくできません。

EnumWindows関数を使ってウィンドウを列挙する方法を試してみたのですがタスクマネージャーに表示されていないものまで表示されてしまいました。

私の環境ではタスクマネージャーに3つ表示されている時に、私のプログラムでは6つ表示されました(program Manager,NECWSET_TB_WINDOW,Windows タスクマネージャー,スタートの4つが表示されていて、自分自身のプログラムは表示されません)

余分に表示されるものをif(lstrcmp(szText,TEXT("スタート"))==0){ return TRUE;} という感じで判定すれば表示しないようにはできますが、これだと自分の作った他のプログラムのタイトルがこれらのタイトル名と同じだった場合にそのプログラムのハンドルまで表示されなくなってしまいます。
どうすればタスクマネージャーに表示されているものと同じものだけを表示させることができますか?

該当のソースコード 表示する項目の判定部分

BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam){
LVITEM item;
TCHAR szText[256];//ウィンドウのキャプションの保存用
TCHAR szhwnd[256];//ウィンドウハンドル表示用
TCHAR szClassName[256];//取得したクラス名保存用

wsprintf(szhwnd,TEXT("%X"),hwnd);
if(!IsWindowVisible(hwnd)) return TRUE;
GetWindowText(hwnd,szText,256);
if (szText[0] == 0) return TRUE;
    GetClassName(hwnd,
        szClassName,
        sizeof(szClassName) / sizeof(TCHAR));

 item.mask = LVIF_TEXT;
 item.pszText = szhwnd;
 item.iItem = 0;
 item.iSubItem = 0;

 ListView_InsertItem((HWND)lParam, &item);

 item.pszText = szClassName;
 item.iItem = 0;
 item.iSubItem = 1;
 ListView_SetItem((HWND)lParam, &item);

 item.pszText = szText;
 item.iItem = 0;
 item.iSubItem = 2;
 ListView_SetItem((HWND)lParam, &item);

 return TRUE;
}

補足情報(FW/ツールのバージョンなど)

Microsoft Visual C++ 2010 Express C言語
WIN32 ユニコードビルド Windows7

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

Visual Studio に付属のウィンドウ解析用ツール Spy++ を使って軽く確認した限りですが、タスクマネージャーでは

  • EnumWindowsAPIで列挙できるトップレベルウィンドウの内、
  • 現在Visibleのもので、
  • ウィンドウスタイルが WS_POPUP ではないもの

を表示しているようです。例としてEnumWindowProcの以下のコードで、タスクマネージャーでの表示に一致しました。(Windows 7 Ultimate 64ビット、Windows 10 Professional 64ビット で確認)

static BOOL CALLBACK EnumWindowsProc(
    _In_ HWND   hwnd,
    _In_ LPARAM lParam
)
{
    if (IsWindowVisible(hwnd)) {

        LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
        if ((style & WS_POPUP) == 0) {
            // 確認の為デバッグ端末へ出力
            TCHAR sz[256 + 2];
            GetWindowText(hwnd, sz, 256);
            lstrcat(sz, _T("\n"));
            OutputDebugString(sz);
        }
    }

    return TRUE;
}

以下の件ですが、

これだと自分の作った他のプログラムのタイトルがこれらのタイトル名と同じだった場合にそのプログラムのハンドルまで表示されなくなってしまいます。

ウィンドウのタイトルバーに表示されているタイトル文字列は、SetWindowTextを使って動的に変えることもでき、それで考えるとタイトルだけで判断するのは不十分とも言えます。厳密にするのであれば、タイトルだけでなく、ウィンドウクラス名や必要に応じてウィンドウの付帯情報(ウィンドウスタイルや親子関係)まで対象にすれば判別は可能だと思います。(質問者さんのコードでは、GetClassNameでクラス名を取得していますね)

なお、ウィンドウの解析に便利なツール Spy++は Visual Studio 2010 Professional版には付属していますが、質問者さんご利用のExpress版に付属しているかは分かりません。


追記しました:(2019/04/20 14:28)

ReactOSと言うWindows互換を目指しクローンOSがあります。
Wikipedia - ReactOS

そのタスクマネージャーのソースが参考になるかもしれません。
github - reactos / taskmgr

このソース中のEnumWindowsProc関数の中で、
/* Check and see if this is a top-level app window */と言うコメント部分があり、ここでタスクマネージャーに表示しないものを選り分けています。Windows 7やWindows 10と同じ挙動とは限りませんが、先の私のコード例より、親ウィンドウやオーナーウィンドウ、拡張ウィンドウスタイルを意識するなど、選別条件が増えています。こちらのコードを参考にすること、お望みの挙動になるかもしれません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/20 15:15

    atata0319さん、フォローありがとうございます。取り急ぎ手持ちのWindows 7 のtaskmgr.exe を"dumpbin /imports"してインポートしている一連のWindows APIを眺めてみたところ、
    GetAltTabInfo はありませんでしたが、(<もちろん、直接インポートしているとは限りませんけど)  代わりに、EnumDesktopWindows OpenDesktopその他がありました。EnumWindows は使っていませんでした。EnumWindowsは現デスクトップ用のラッパー関数な気もするので、EnumWindowsの使用をEnumDesktopWindowsに変えても挙動は同じな気もしますが。タスクマネージャーと言うことで、ご指摘のように同一プロセスを意識するなど複雑な選別をしていることはありそうです。

    キャンセル

  • 2019/04/20 17:02

    atata0319さん、dodox86さん回答ありがとうございました。
    dodox86さんに教えて頂いたReactOSのソースを参考にしてプログラムしたら解決できました。
    ウィンドウスタイルが WS_POPUP ではないものを調べるところを削除して、代わりに拡張ウィンドウスタイルのWS_EX_TOOLWINDOWの有無で判断するようにしたら「NECWSET_TB_WINDOW」の表示も消えました。これだけだとメディアプレイヤーを起動している時に「Windows Media Player 」というタイトルが4回表示されてしまうのでGetParent(hWnd)で判別することも必要のようです。

    キャンセル

  • 2019/04/21 22:43

    解決したようでよかったです。
    ReactOS のソースも読みましたが、意外と単純な仕組みなっているんですね。EnumDesktopWindows と EnumWindows の差についてはちょっと調べて、以下のスタックオーバーフローの記事を見つけました。Windows 10 ではクラシックアプリやストアアプリ等の列挙のされ方に差があるような感じですかね。
    https://stackoverflow.com/questions/38205375/enumwindows-function-in-win10-enumerates-only-desktop-apps

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.60%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • Cに関する質問
  • 起動中のウィンドウのハンドルとタイトル名の取得方法(タスクマネージャーに表示されるものと一致させる)