Created
May 7, 2022 11:44
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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