「タスクバーに載っているアプリ一覧を取得する」方法を調べていたところ stackoverflow の List all running Taskbar applications with .NET に「UI Automation」を使った回答があったので試してみました。
UI Autimation (以降、UIA) の使い方については、C# での情報が多く、C++ での情報は殆ど見つかりません。C++ で UIA でアプリ一覧を取得できたので、C++ で UIA を扱いたい人の参考になればと思います。
実行結果
この後に書いてあるコードを実行すると次のような一覧が取得できます。
> .\Project1.exe
No. hWnd exename caption
--- ---------- -------------------------------- --------------------------------------------- - -
1 0x00870b36 WindowsTerminal.exe Windows PowerShell
2 0x00161786 WindowsTerminal.exe C:\WINDOWS\system32\cmd.exe
3 0x00520ad0 bds.exe Project1 - C++Builder 12 Community Edition - File1.cpp [ビルド完了]
4 0x000e0e98 Q-Dir.exe Q-Dir 6.41
5 0x001d170a Notepad.exe タイトルなし - メモ帳
6 0x002413b2 EXCEL.EXE 新規 Microsoft Excel ワークシート.xlsx - Excel
7 0x0001056c LogiOverlay.exe MainWindow
8 0x0012023c AFX.EXE あふ
9 0x00041542 ApplicationFrameHost.exe 電卓
--- ---------- -------------------------------- --------------------------------------------- - -
起動したアプリがほぼ取れています。ただし、タスクバーのアプリ一覧とは異なった内容です。
タスクバーのアプリ一覧とは異なる
上記の UIA で取得した一覧はタスクバーに載っているアプリ一覧とは異なっています。
上記のコマンド実行時、アプリは10個立ち上げていました。

1. C++ Builder 2. VSCode 3. Q-Dir 4. あふ 5. 電卓 6. Chrome 7. Excel 8. メモ帳 9. コマンドプロンプト 10. PowerShell
コマンド実行結果は、この実際のタスクバーの内容と異なっています。差異は3つあり、1) VSCode が無い、 2) Chorome が無い、3) LogiOverlay.exe がある、です。
このように UIA で取得した一覧 と タスクバーの一覧 とは違うものになります。タスクバーに載っているアプリ一覧を取得したい場合は、別の方法を探す必要があります。
UIA でアプリ一覧を取得するコード
C++ 版
C++ でのコードは次の通りです。デスクトップの子要素を対象にウィンドウコントール要素を取得しています。
#include <vector>
#include <uiautomationclient.h>
HRESULT _InitializeUIAutomation(IUIAutomation **ppAutomation);
void _BuildAppList(IUIAutomation *iUiAutomation, std::vector<HWND>& hWnds);
#include <iostream>
void _PrintList(std::vector<HWND>& hWnds);
UnicodeString _GetExePath(HWND hWnd);
UnicodeString _GetCaption(HWND hWnd);
//--------------------------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
// COM ライブラリを初期化する。
// C++ では CoInitialize() をしないと CoCreateInstance() が CLASS_E_NOAGGREGATION で失敗する。
CoInitialize(NULL);
// UIA の開始手続き。CUIAutomation オブジェクトのインスタンスを取得する。
IUIAutomation *iUiAutomation;
HRESULT hResult = _InitializeUIAutomation(&iUiAutomation);
if (hResult != S_OK) {
return -1;
}
// アプリ一覧を取得して vector<HWND> に格納する。
std::vector<HWND> hWnds = std::vector<HWND>();
_BuildAppList(iUiAutomation, hWnds);
// CUIAutomation を開放する。
iUiAutomation->Release();
// 取得した一覧をコンソールに出力する。
_PrintList(hWnds);
return 0;
}
//--------------------------------------------------------------------------------------------------
// CUIAutomation オブジェクトのインスタンスを取得する。
HRESULT _InitializeUIAutomation(IUIAutomation **ppAutomation)
{
return CoCreateInstance(CLSID_CUIAutomation, NULL,
CLSCTX_INPROC_SERVER, IID_IUIAutomation,
reinterpret_cast<void**>(ppAutomation));
}
// アプリ一覧を取得して vector<HWND> に格納する。
void _BuildAppList(IUIAutomation *iUiAutomation, std::vector<HWND>& hWnds)
{
// FindAll() での検索条件を持つプロパティを作成する。
tagVARIANT variant;
variant.vt = VT_I4;
variant.lVal = UIA_WindowControlTypeId;
IUIAutomationCondition *iUiAutomationCondition;
iUiAutomation->CreatePropertyCondition(
UIA_ControlTypePropertyId, variant, &iUiAutomationCondition);
// FindAll() で検索する階層に デスクトップを表す UIA 要素を取得する。
IUIAutomationElement *iUiRootElement;
iUiAutomation->GetRootElement(&iUiRootElement);
// FindAll() を実行する。
// デスクトップ(RootElement)の子要素(TreeScope_Children)から、検索条件プロパティに一致する要素を取得する。
IUIAutomationElementArray *iUiAutomationElmentArray;
iUiRootElement->FindAll(TreeScope_Children, iUiAutomationCondition, &iUiAutomationElmentArray);
// 条件に一致した要素数を取得する。
int nElements;
iUiAutomationElmentArray->get_Length(&nElements);
// 条件に一致した要素をループしながら、ウィンドウハンドルを取得し、vector<HWND> へ格納する。
for (int i = 0; i < nElements; i++) {
IUIAutomationElement *element;
iUiAutomationElmentArray->GetElement(i, &element);
// ウィンドウハンドルを取得する。
UIA_HWND UiaHwnd;
HRESULT hResultGetHwnd = element->get_CurrentNativeWindowHandle(&UiaHwnd);
// vector<HWND> へ格納する。
hWnds.push_back((HWND)UiaHwnd);
}
return;
}
//--------------------------------------------------------------------------------------------------
// 取得した一覧をコンソールに出力する。
void _PrintList(std::vector<HWND>& hWnds)
{
std::cout << "No. hWnd exename caption" << std::endl;
std::cout << "--- ---------- -------------------------------- --------------------------------------------- - -" << std::endl;
int i = 1;
std::vector<HWND>::iterator it;
for(it = hWnds.begin(); it != hWnds.end(); it++) {
HWND hWnd = *it;
UnicodeString s = String().sprintf(L"%3d 0x%08x %-32s %s",
i, hWnd,
ExtractFileName(_GetExePath(hWnd)).c_str(),
_GetCaption(hWnd).c_str());
std::cout << AnsiString(s).c_str() << std::endl;
i++;
}
std::cout << "--- ---------- -------------------------------- --------------------------------------------- - -" << std::endl;
}
UnicodeString _GetExePath(HWND hWnd)
{
UnicodeString result;
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, -1, pid);
if (hProcess == NULL)
return "";
const int BUFSIZE = MAX_PATH;
wchar_t exePath[BUFSIZE];
unsigned long len = BUFSIZE;
BOOL succeeded = QueryFullProcessImageName(hProcess, 0, exePath, &len);
result = (succeeded)? UnicodeString(exePath) : "";
CloseHandle(hProcess);
return result;
}
UnicodeString _GetCaption(HWND hWnd)
{
const int BUFSIZE = 256;
wchar_t Caption[BUFSIZE];
GetWindowText(hWnd, Caption, BUFSIZE);
return Caption;
}
C# 版
最後に同じ一覧取得を C# で書いた場合のコードも記載しておきます。C# で使うと簡単に書けます。
// UIA で一覧を取得する。
var desktopWindows =
AutomationElement.RootElement.FindAll(
TreeScope.Children,
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
// 取得した一覧を List に変換する。
List<AutomationElement> list = desktopWindows.Cast<AutomationElement>().ToList();
// List の内容をコンソールに出力する。
// 出力内容は C++ より簡素にしてあります。
foreach (AutomationElement element in list)
{
string msg =
string.Format("0x{0,8:x8} {1}",
element.Current.NativeWindowHandle, element.Current.Name);
Console.WriteLine(msg);
}
参考
- CUIAutomation オブジェクトの作成 – Win32 apps | Microsoft Learn
- IUIAutomation::CreatePropertyCondition (uiautomationclient.h) – Win32 apps | Microsoft Learn
- IUIAutomation::GetRootElement (uiautomationclient.h) – Win32 apps | Microsoft Learn
- IUIAutomationElement::FindAll (uiautomationclient.h) – Win32 apps | Microsoft Learn
- List all running Taskbar applications with .NET – Stack Overflow
コメント