Skip to content

Instantly share code, notes, and snippets.

@oblaser
Created May 7, 2022 11:44
Show Gist options
  • Save oblaser/51114171434722177cc33adc7c720183 to your computer and use it in GitHub Desktop.
Save oblaser/51114171434722177cc33adc7c720183 to your computer and use it in GitHub Desktop.
Windows command line tool to get window information from a given window title
/*
author Oliver Blaser
date 07.05.2022
copyright GNU GPLv3 - Copyright (c) 2022 Oliver Blaser
*/
#include <iostream>
#include <string>
#include <vector>
#include <omw/cli.h>
#include <omw/string.h>
#include <omw/windows/windows.h>
#include <Windows.h>
using std::cout;
using std::endl;
namespace
{
#ifdef _DEBUG
LPCWSTR defaultWindowName = L"My Window";
LPCWSTR defaultClassName = L"ApplicationFrameWindow";
#endif
int cliChoice(const std::string& q, int def = 0, char first = 'y', char second = 'n')
{
int r = 0;
const omw::string a(1, first);
const omw::string b(1, second);
omw::string data;
do
{
std::cout << q << " [" << (def == 1 ? a.toUpper_ascii() : a) << "/" << (def == 2 ? b.toUpper_ascii() : b) << "] ";
std::getline(std::cin, data);
if (data.toLower_ascii() == a) r = 1;
else if (data.toLower_ascii() == b) r = 2;
else if (data.length() == 0) r = def;
else r = 0;
}
while (r == 0);
return r;
}
void printHelp()
{
cout << "Usage:\n *.exe [windowName [className]] [-c]" << endl;
cout << endl;
cout << " -c also print child windows" << endl;
cout << endl;
}
std::vector<HWND> getChildWindows(HWND parent, LPCWSTR windowName = nullptr, LPCWSTR className = nullptr)
{
std::vector<HWND> vec;
HWND child = nullptr;
do
{
child = FindWindowExW(parent, child, className, windowName);
if (child) vec.push_back(child);
}
while (child);
return vec;
}
std::string to_string(const POINT& point)
{
return std::to_string(point.x) + ":" + std::to_string(point.y);
}
std::string to_string(const RECT& rect)
{
return std::to_string(rect.left) + ":" + std::to_string(rect.top) + " " + std::to_string(rect.right - rect.left) + "x" + std::to_string(rect.bottom - rect.top);
}
void printWindowInfo(const HWND& hwnd, bool isChild, bool isLastChild = false)
{
// assuming the consoles code page is 850 (default)
const char* indent = (isChild ? (isLastChild ? " \xC3\xC4" : " \xB3 \xC3\xC4") : " ");
const char* lastIndent = (isChild ? (isLastChild ? " \xC0\xC4" : " \xB3 \xC0\xC4") : " ");
constexpr int wndTextSize = 300;
char wndText[wndTextSize];
RECT wndRect;
WINDOWPLACEMENT wndPlacement;
DWORD displayAffinity;
wndText[0] = 0;
wndPlacement.length = sizeof(WINDOWPLACEMENT);
GetWindowTextA(hwnd, wndText, wndTextSize);
GetWindowRect(hwnd, &wndRect);
GetWindowPlacement(hwnd, &wndPlacement);
GetWindowDisplayAffinity(hwnd, &displayAffinity);
// return values should be checked in a "real" application
cout << (isChild ? (isLastChild ? " \xC0\xC4" : " \xC3\xC4") : "");
if (isChild) cout << omw::bold;
else cout << omw::fgBrightCyan;
cout << (int)hwnd << " \"" << wndText << "\"" << endl;
if (isChild) cout << omw::boldOff;
else cout << omw::defaultForeColor;
cout << indent;
if (!isChild) cout << omw::bold;
cout << to_string(wndRect) << " ";
if (wndPlacement.showCmd == SW_SHOWMAXIMIZED) cout << "maximized";
else if (wndPlacement.showCmd == SW_SHOWMINIMIZED) cout << "minimized";
else if (wndPlacement.showCmd == SW_SHOWNORMAL) cout << "normal";
else cout << "?";
if (!isChild) cout << omw::boldOff;
cout << endl;
cout << indent << "display affinity: ";
if (displayAffinity == WDA_NONE) cout << "none";
else if (displayAffinity == WDA_MONITOR) cout << "monitor";
else if (displayAffinity == WDA_EXCLUDEFROMCAPTURE) cout << "excludeFromCapture";
else cout << "?";
cout << endl;
cout << indent << "minimized position" << to_string(wndPlacement.ptMinPosition) << endl;
cout << indent << "maximized position" << to_string(wndPlacement.ptMaxPosition) << endl;
cout << lastIndent << "normal position: " << to_string(wndPlacement.rcNormalPosition) << endl;
}
}
int wmain(int argc, wchar_t** argv, wchar_t** envp)
{
int r = 0;
LPCWSTR windowName = nullptr;
LPCWSTR className = nullptr;
bool printChilds = false;
omw::ansiesc::enable(omw::windows::consoleEnVirtualTermProc());
if (argc > 1)
{
std::wstring lastArg(argv[argc - 1]);
if (lastArg == L"-c")
{
printChilds = true;
--argc;
}
else if ((lastArg == L"--help") || (lastArg == L"-h") || (lastArg == L"/?"))
{
printHelp();
return 0;
}
}
if (!r)
{
if (argc == 2)
{
windowName = argv[1];
className = nullptr;
}
else if (argc == 3)
{
windowName = argv[1];
className = argv[2];
}
#ifdef _DEBUG
else if (argc == 1)
{
windowName = defaultWindowName;
className = defaultClassName;
}
#endif
else
{
printHelp();
r = 1;
}
}
if (!r)
{
while (1)
{
std::wcout << L"searching \"" << windowName << L"\"";
if (className) std::wcout << L" \"" << className << L"\"";
std::wcout << endl;
const auto parents = getChildWindows(nullptr, windowName, className);
if (parents.size() == 0) cout << "no window found" << endl;
else cout << endl;
for (size_t i_parent = 0; i_parent < parents.size(); ++i_parent)
{
printWindowInfo(parents[i_parent], false, (i_parent + 1 == parents.size()));
cout << endl;
if (printChilds)
{
const auto childs = getChildWindows(parents[i_parent]);
for (size_t i_child = 0; i_child < childs.size(); ++i_child)
{
printWindowInfo(childs[i_child], true, (i_child + 1 == childs.size()));
}
cout << endl;
cout << endl;
}
}
if (cliChoice("Run again?", 1) == 2) break;
else cout << endl;
}
}
#if defined(_DEBUG) && 1
cout << omw::foreColor(26) << "===============\nreturn " << r << "\npress enter..." << omw::normal << endl;
int dbg___getc_ = getc(stdin);
#endif
return r;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment