[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- Backup*.rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"WTLHelper\"]\n\tpath = WTLHelper\n\turl = https://github.com/zodiacon/WTLHelper.git\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Pavel Yosifovich\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# WinSpy\n\nEnhanced version of the classic Spy++ tool (WIP)\n"
  },
  {
    "path": "WinSpy/AboutDlg.cpp",
    "content": "// aboutdlg.cpp : implementation of the CAboutDlg class\n//\n/////////////////////////////////////////////////////////////////////////////\n\n#include \"pch.h\"\n#include \"resource.h\"\n\n#include \"aboutdlg.h\"\n\nLRESULT CAboutDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tCenterWindow(GetParent());\n\treturn TRUE;\n}\n\nLRESULT CAboutDlg::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tEndDialog(wID);\n\treturn 0;\n}\n"
  },
  {
    "path": "WinSpy/AboutDlg.h",
    "content": "// aboutdlg.h : interface of the CAboutDlg class\n//\n/////////////////////////////////////////////////////////////////////////////\n\n#pragma once\n\nclass CAboutDlg : public CDialogImpl<CAboutDlg> {\npublic:\n\tenum { IDD = IDD_ABOUTBOX };\n\n\tBEGIN_MSG_MAP(CAboutDlg)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_ID_HANDLER(IDOK, OnCloseCmd)\n\t\tCOMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)\n\tEND_MSG_MAP()\n\n\t// Handler prototypes (uncomment arguments if needed):\n\t//\tLRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t//\tLRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t//\tLRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n};\n"
  },
  {
    "path": "WinSpy/AutomationTreeView.cpp",
    "content": "#include \"pch.h\"\n#include \"AutomationTreeView.h\"\n#include \"WindowHelper.h\"\n\n#pragma comment(lib, \"oleacc\")\n\nLRESULT CAutomationTreeView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tm_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);\n\n\tm_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |\n\t\tTVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS, 0, IDC_TREE);\n\tm_List.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |\n\t\tLVS_REPORT | LVS_OWNERDATA | LVS_SINGLESEL);\n\tm_List.SetExtendedListViewStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT);\n\n\tm_List.InsertColumn(0, L\"Property\", 0, 180);\n\tm_List.InsertColumn(1, L\"Value\", 0, 350);\n\n\tm_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER);\n\n\tm_Tree.SetImageList(WindowHelper::GetImageList(), TVSIL_NORMAL);\n\n\tm_Splitter.SetSplitterPanes(m_Tree, m_List);\n\tm_Splitter.SetSplitterPosPct(35);\n\n\tInitTree();\n\n\treturn 0;\n}\n\nLRESULT CAutomationTreeView::OnNodeExpanding(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tif (tv->action != TVE_EXPAND)\n\t\treturn FALSE;\n\n\tauto hItem = tv->itemNew.hItem;\n\tif (m_Tree.GetChildItem(hItem))\n\t\treturn FALSE;\n\n\tauto elem = (IUIAutomationElement*)m_Tree.GetItemData(hItem);\n\tif (elem) {\n\t\tEnumChildElements(m_spUIWalker, elem, hItem);\n\t\treturn FALSE;\n\t}\n\treturn TRUE;\n}\n\nLRESULT CAutomationTreeView::OnNodeExpanded(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tif (tv->action != TVE_COLLAPSE)\n\t\treturn FALSE;\n\n\t//\n\t// delete child nodes\n\t//\n\tauto hItem = tv->itemNew.hItem;\n\tHTREEITEM hChild;\n\twhile (hChild = m_Tree.GetChildItem(hItem))\n\t\tm_Tree.DeleteItem(hChild);\n\n\tTVITEM tvi{ sizeof(tvi) };\n\ttvi.cChildren = 1;\n\ttvi.mask = TVIF_CHILDREN;\n\ttvi.hItem = hItem;\n\tm_Tree.SetItem(&tvi);\n\n\treturn FALSE;\n}\n\nLRESULT CAutomationTreeView::OnNodeSelected(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tauto hItem = tv->itemNew.hItem;\n\tauto data = (IUIAutomationElement*)m_Tree.GetItemData(tv->itemNew.hItem);\n\tUpdateProperties(data);\n\treturn 0;\n}\n\nLRESULT CAutomationTreeView::OnNodeDeleted(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tauto data = (IUIAutomationElement*)m_Tree.GetItemData(tv->itemOld.hItem);\n\tif (data)\n\t\tdata->Release();\n\n\treturn 0;\n}\n\nvoid CAutomationTreeView::OnActivate(bool active) {\n\tif (active) {\n\t\tUpdateUI();\n\t}\n}\n\nCString CAutomationTreeView::GetColumnText(HWND, int row, int col) const {\n\tauto& p = m_Properties[row];\n\tswitch (col) {\n\t\tcase 0: return p.Name;\n\t\tcase 1: return p.Value.c_str();\n\t}\n\treturn L\"\";\n}\n\nHTREEITEM CAutomationTreeView::AddElement(IUIAutomationElement* e, HTREEITEM hParent, HTREEITEM hAfter) {\n\tCComBSTR name, cls, id;\n\te->get_CurrentName(&name);\n\te->get_CurrentClassName(&cls);\n\tCString text;\n\ttext.Format(L\"%s [%s]\", name.m_str, cls.m_str);\n\n\tauto hItem = m_Tree.InsertItem(text, hParent, hAfter);\n\te->AddRef();\n\tm_Tree.SetItemData(hItem, (DWORD_PTR)e);\n\treturn hItem;\n}\n\nvoid CAutomationTreeView::EnumChildElements(IUIAutomationTreeWalker* pWalker, IUIAutomationElement* root, HTREEITEM hParent, HTREEITEM hAfter) {\n\tCComPtr<IUIAutomationElement> spElem;\n\tpWalker->GetFirstChildElement(root, &spElem);\n\tint pid = 0;\n\twhile (spElem) {\n\t\tspElem->get_CurrentProcessId(&pid);\n\t\tif (pid != ::GetCurrentProcessId()) {\n\t\t\tauto node = AddElement(spElem, hParent, hAfter);\n\t\t\tCComPtr<IUIAutomationElement> spChild;\n\t\t\tpWalker->GetFirstChildElement(spElem, &spChild);\n\t\t\tif (spChild) {\n\t\t\t\tTVITEM tvi{ sizeof(tvi) };\n\t\t\t\ttvi.cChildren = 1;\n\t\t\t\ttvi.mask = TVIF_CHILDREN;\n\t\t\t\ttvi.hItem = node;\n\t\t\t\tm_Tree.SetItem(&tvi);\n\t\t\t}\n\t\t}\n\t\tCComPtr<IUIAutomationElement> spNext;\n\t\tpWalker->GetNextSiblingElement(spElem, &spNext);\n\t\tspElem = spNext;\n\t}\n}\n\nvoid CAutomationTreeView::InitTree() {\n\tCWaitCursor wait;\n\tif (m_spUI == nullptr) {\n\t\tm_spUI.CoCreateInstance(__uuidof(CUIAutomation));\n\t\tif (m_spUI == nullptr)\n\t\t\treturn;\n\t}\n\tm_Tree.SetRedraw(FALSE);\n\tm_Tree.DeleteAllItems();\n\tCComPtr<IUIAutomationTreeWalker> spWalker;\n\tm_spUI->get_RawViewWalker(&spWalker);\n\tATLASSERT(spWalker);\n\tm_spUIWalker = spWalker;\n\n\tCComPtr<IUIAutomationElement> spRoot;\n\tm_spUI->GetRootElement(&spRoot);\n\tauto node = AddElement(spRoot);\n\n\tEnumChildElements(spWalker, spRoot, node);\n\tm_Tree.Expand(node, TVE_EXPAND);\n\tm_Tree.SetRedraw(TRUE);\n}\n\nvoid CAutomationTreeView::UpdateUI() {\n}\n\nvoid CAutomationTreeView::UpdateProperties(IUIAutomationElement* elem) {\n\tm_Properties.clear();\n\tif (elem) {\n\t\tstatic const struct {\n\t\t\tPROPERTYID id;\n\t\t\tPCWSTR text;\n\t\t} props[] = {\n\t\t\t{ UIA_NamePropertyId, L\"Name\" },\n\t\t\t{ UIA_RuntimeIdPropertyId, L\"Runtime ID\" },\n\t\t\t{ UIA_ClassNamePropertyId, L\"Class Name\" },\n\t\t\t{ UIA_ControlTypePropertyId, L\"Control Type\" },\n\t\t\t{ UIA_LocalizedControlTypePropertyId, L\"Localized Control Type\" },\n\t\t\t{ UIA_FullDescriptionPropertyId, L\"Full Description\" },\n\t\t\t{ UIA_AcceleratorKeyPropertyId, L\"Accelerator Key\" },\n\t\t\t{ UIA_AccessKeyPropertyId, L\"Access Key\" },\n\t\t\t{ UIA_AutomationIdPropertyId, L\"Automation ID\" },\n\t\t\t{ UIA_BoundingRectanglePropertyId, L\"Bounding Rectangle\" },\n\t\t\t{ UIA_CenterPointPropertyId, L\"Center Point\" },\n\t\t\t{ UIA_HasKeyboardFocusPropertyId, L\"Has Focus\" },\n\t\t\t{ UIA_HelpTextPropertyId, L\"Help Text\" },\n\t\t\t{ UIA_ItemStatusPropertyId, L\"Item Status\" },\n\t\t\t{ UIA_NativeWindowHandlePropertyId, L\"Window Handle\" },\n\t\t\t{ UIA_ProcessIdPropertyId, L\"Process ID\" },\n\t\t\t{ UIA_SizePropertyId, L\"Size\" },\n\t\t\t{ UIA_OrientationPropertyId, L\"Orientation\" },\n\t\t\t{ UIA_OutlineColorPropertyId, L\"Outline Color\" },\n\t\t\t{ UIA_FillColorPropertyId, L\"Fill Color\" },\n\t\t\t{ UIA_PositionInSetPropertyId, L\"Position in Set\" },\n\t\t\t{ UIA_OutlineThicknessPropertyId, L\"Outline Thickness\" },\n\t\t\t{ UIA_IsEnabledPropertyId, L\"Enabled\" },\n\t\t\t{ UIA_IsOffscreenPropertyId, L\"Off Screen\" },\n\t\t\t{ UIA_IsPasswordPropertyId, L\"Password\" },\n\t\t\t{ UIA_IsEnabledPropertyId, L\"Editable\" },\n\t\t\t{ UIA_ItemTypePropertyId, L\"Item Type\" },\n\t\t\t{ UIA_SizeOfSetPropertyId, L\"Size of Set\" },\n\t\t\t{ UIA_VisualEffectsPropertyId, L\"Visual Effects\" },\n\t\t\t{ UIA_LiveSettingPropertyId, L\"Live Setting\" },\n\t\t\t{ UIA_LevelPropertyId, L\"Level\" },\n\t\t\t{ UIA_IsPeripheralPropertyId, L\"Peripheral\" },\n\t\t\t{ UIA_IsKeyboardFocusablePropertyId, L\"Keyboard Focusable\" },\n\t\t\t{ UIA_IsDialogPropertyId, L\"Dialog\" },\n\t\t\t{ UIA_IsControlElementPropertyId, L\"Control Element\" },\n\t\t\t{ UIA_FrameworkIdPropertyId, L\"Framework ID\" },\n\t\t};\n\n\t\tfor (auto& p : props) {\n\t\t\tCComVariant value;\n\t\t\tif (S_OK == elem->GetCurrentPropertyValue(p.id, &value)) {\n\t\t\t\tItemData data;\n\t\t\t\tdata.Value = FormatValue(m_spUI, value);\n\t\t\t\tif (data.Value.empty() && S_OK == value.ChangeType(VT_BSTR)) {\n\t\t\t\t\tdata.Value = value.bstrVal;\n\t\t\t\t}\n\t\t\t\tif (!data.Value.empty()) {\n\t\t\t\t\tdata.Name = p.text;\n\t\t\t\t\tm_Properties.push_back(std::move(data));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tm_List.SetItemCount((int)m_Properties.size());\n}\n\nstd::wstring CAutomationTreeView::FormatValue(IUIAutomation* pUI, VARIANT const& value) {\n\tswitch (value.vt) {\n\t\tcase VT_I4:\treturn std::format(L\"{} (0x{:X})\", value.intVal, value.intVal);\n\t\tcase VT_UI4: return std::format(L\"{} (0x{:X})\", value.uintVal, value.uintVal);\n\t\tcase VT_BOOL: return value.boolVal ? L\"True\" : L\"False\";\n\t\tcase VT_I4 | VT_ARRAY:\n\t\t{\n\t\t\tint* data, count;\n\t\t\tif (S_OK == pUI->IntSafeArrayToNativeArray(value.parray, &data, &count)) {\n\t\t\t\tstd::wstring result(L\"(\");\n\t\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\t\tresult += std::format(L\"{}\", data[i]);\n\t\t\t\t\tif (i < count - 1)\n\t\t\t\t\t\tresult += L\", \";\n\t\t\t\t}\n\t\t\t\tresult += L\")\";\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase VT_R8 | VT_ARRAY:\n\t\t{\n\t\t\tRECT* rc;\n\t\t\tint count;\n\t\t\tif (S_OK == pUI->SafeArrayToRectNativeArray(value.parray, &rc, &count) && count > 0) {\n\t\t\t\tstd::wstring result(L\"(\");\n\t\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\t\tresult += std::format(L\"[{},{}-{},{}]\", rc[i].left, rc[i].top, rc[i].right, rc[i].bottom);\n\t\t\t\t\tif (i < count - 1)\n\t\t\t\t\t\tresult += L\", \";\n\t\t\t\t}\n\t\t\t\tresult += L\")\";\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdouble* data;\n\t\t\t\tcount = value.parray->rgsabound[0].cElements;\n\t\t\t\tif (S_OK == ::SafeArrayAccessData(value.parray, (void**)&data)) {\n\t\t\t\t\tstd::wstring result(L\"(\");\n\t\t\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\t\t\tresult += std::format(L\"{}\", data[i]);\n\t\t\t\t\t\tif (i < count - 1)\n\t\t\t\t\t\t\tresult += L\", \";\n\t\t\t\t\t}\n\t\t\t\t\t::SafeArrayUnaccessData(value.parray);\n\t\t\t\t\tresult += L\")\";\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn L\"\";\n}\n"
  },
  {
    "path": "WinSpy/AutomationTreeView.h",
    "content": "#pragma once\n\n#include \"ViewBase.h\"\n#include <TreeViewHelper.h>\n#include <VirtualListView.h>\n#include <CustomSplitterWindow.h>\n#include <UIAutomation.h>\n\nstruct IUIAutomationElement;\nstruct IUIAutomationTreeWalker;\n\nclass CAutomationTreeView :\n\tpublic CViewBase<CAutomationTreeView>,\n\tpublic CVirtualListView<CAutomationTreeView>,\n\tpublic CTreeViewHelper<CAutomationTreeView> {\npublic:\n\texplicit CAutomationTreeView(IMainFrame* frame) : CViewBase(frame) {}\n\n\tvoid OnActivate(bool active);\n\n\tCString GetColumnText(HWND, int row, int col) const;\n\nprotected:\n\tenum { IDC_TREE = 123 };\n\n\tBEGIN_MSG_MAP(CAutomationTreeView)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tNOTIFY_CODE_HANDLER(TVN_ITEMEXPANDING, OnNodeExpanding)\n\t\tNOTIFY_CODE_HANDLER(TVN_ITEMEXPANDED, OnNodeExpanded)\n\t\tNOTIFY_CODE_HANDLER(TVN_SELCHANGED, OnNodeSelected)\n\t\tNOTIFY_CODE_HANDLER(TVN_DELETEITEM, OnNodeDeleted)\n\t\tCHAIN_MSG_MAP(CTreeViewHelper<CAutomationTreeView>)\n\t\tCHAIN_MSG_MAP(CVirtualListView<CAutomationTreeView>)\n\t\tCHAIN_MSG_MAP(CViewBase<CAutomationTreeView>)\n\tEND_MSG_MAP()\n\n\tLRESULT OnTreeNodeRightClick(HTREEITEM hItem, CPoint const& pt);\n\tLRESULT OnTreeNodeDoubleClick(HTREEITEM hItem, CPoint const& pt);\n\nprivate:\n\tHTREEITEM AddElement(IUIAutomationElement* element, HTREEITEM hParent = TVI_ROOT, HTREEITEM hAfter = TVI_SORT);\n\tvoid EnumChildElements(IUIAutomationTreeWalker* pWalker, IUIAutomationElement* root, HTREEITEM hParent = TVI_ROOT, HTREEITEM hAfter = TVI_SORT);\n\n\tvoid InitTree();\n\tvoid UpdateUI();\n\tvoid UpdateProperties(IUIAutomationElement* elem);\n\tstatic std::wstring FormatValue(IUIAutomation* pUI, VARIANT const& value);\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeExpanding(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeExpanded(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeSelected(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeDeleted(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\n\tstruct ItemData {\n\t\tPCWSTR Name;\n\t\tstd::wstring Value;\n\t};\n\n\tCCustomSplitterWindow m_Splitter;\n\tCTreeViewCtrl m_Tree;\n\tCListViewCtrl m_List;\n\tCComPtr<IUIAutomationTreeWalker> m_spUIWalker;\n\tCComPtr<IUIAutomation> m_spUI;\n\tstd::vector<ItemData> m_Properties;\n};\n"
  },
  {
    "path": "WinSpy/DialogHelper.h",
    "content": "#pragma once\n\ntemplate<typename T>\nclass CDialogHelper {\npublic:\n#ifdef IDI_OK\n\tvoid AdjustOKCancelButtons() {\n\t\tauto dlg = static_cast<T*>(this);\n\t\tCButton ok(dlg->GetDlgItem(IDOK));\n\t\tif (ok) {\n\t\t\tCString text;\n\t\t\tok.GetWindowText(text);\n\t\t\tok.SetWindowText(L\"  \" + text);\n\t\t\tok.SetIcon(AtlLoadIconImage(IDI_OK, 0, 16, 16));\n\t\t}\n\n\t\tCButton cancel(dlg->GetDlgItem(IDCANCEL));\n\t\tif (cancel) {\n\t\t\tcancel.SetWindowText(L\"  Cancel\");\n\t\t\tcancel.SetIcon(AtlLoadIconImage(IDI_CANCEL, 0, 16, 16));\n\t\t}\n\t}\n#endif\n\n\tbool AddIconToButton(WORD id, WORD icon, int size = 16) {\n\t\tauto dlg = static_cast<T*>(this);\n\t\tCButton button(dlg->GetDlgItem(id));\n\t\tif (button) {\n\t\t\tbutton.SetIcon(AtlLoadIconImage(icon, 0, size, size));\n\t\t\tCString text;\n\t\t\tbutton.GetWindowText(text);\n\t\t\tbutton.SetWindowText(L\"  \" + text);\n\t\t}\n\t\treturn (bool)button;\n\t}\n\n\tvoid SetDialogIcon(UINT icon) {\n\t\tauto dlg = static_cast<T*>(this);\n\t\tdlg->SetIcon(AtlLoadIconImage(icon, 0, 16, 16), FALSE);\n\t\tdlg->SetIcon(AtlLoadIconImage(icon, 0, 32, 32), TRUE);\n\t}\n\tvoid SetDialogIcon(HICON icon) {\n\t\tauto dlg = static_cast<T*>(this);\n\t\tdlg->SetIcon(icon, FALSE);\n\t\tdlg->SetIcon(icon, TRUE);\n\t}\n};\n\n"
  },
  {
    "path": "WinSpy/FindWindowDlg.cpp",
    "content": "#include \"pch.h\"\n#include \"resource.h\"\n#include \"FindWindowDlg.h\"\n#include \"WindowHelper.h\"\n#include \"ProcessHelper.h\"\n#include \"FormatHelper.h\"\n\nHWND CFindWindowDlg::GetSelectedHwnd() const {\n\treturn m_SelectedHwnd;\n}\n\nvoid CFindWindowDlg::ClearWindowDetails() {\n\tSetDlgItemText(IDC_HANDLE, L\"\");\n\tSetDlgItemText(IDC_TEXT, L\"\");\n\tSetDlgItemText(IDC_CLASSNAME, L\"\");\n\tSetDlgItemText(IDC_THREAD, L\"\");\n\tSetDlgItemText(IDC_PROCESS, L\"\");\n\tif (m_hCursorWnd)\n\t\tWindowHelper::HighlightBorder(m_hCursorWnd, false);\n\tm_WinDrag.ShowWindow(SW_SHOW);\n\tif (IsDlgButtonChecked(IDC_HIDE) == BST_CHECKED) {\n\t\t::ShowWindow(m_pFrame->GetHwnd(), SW_SHOW);\n\t}\n}\n\nvoid CFindWindowDlg::SelectWindow(HWND hWnd) {\n\tCString text;\n\ttext.Format(L\"0x%zX\", DWORD_PTR(hWnd));\n\tSetDlgItemText(IDC_HANDLE, text);\n\tWCHAR clsName[128];\n\tm_SelectedHwnd = hWnd;\n\tif (::GetClassName(hWnd, clsName, _countof(clsName)))\n\t\tSetDlgItemText(IDC_CLASSNAME, clsName);\n\tCWindow win(hWnd);\n\twin.GetWindowText(text);\n\tSetDlgItemText(IDC_TEXT, text);\n\tDWORD pid;\n\tauto tid = ::GetWindowThreadProcessId(hWnd, &pid);\n\tSetDlgItemInt(IDC_THREAD, tid, FALSE);\n\ttext.Format(L\"%s (%d)\", (PCWSTR)ProcessHelper::GetProcessImageName(pid), pid);\n\tSetDlgItemText(IDC_PROCESS, text);\n}\n\nLRESULT CFindWindowDlg::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) {\n\tInitDynamicLayout();\n\tSetDialogIcon(IDI_WINDOWSEARCH);\n\tm_WinDrag.SubclassWindow(GetDlgItem(IDC_TARGET));\n\tm_WinDrag.SetIcon(AtlLoadIconImage(IDI_TARGET, 0, 32, 32));\n\tm_DragCursor = AtlLoadIconImage(IDI_TARGET, 0, ::GetSystemMetrics(SM_CXCURSOR), ::GetSystemMetrics(SM_CYCURSOR));\n\n\treturn 0;\n}\n\nLRESULT CFindWindowDlg::OnCloseCmd(WORD, WORD id, HWND, BOOL&) {\n\tif (id == IDCANCEL && m_Capture) {\n\t\tReleaseCapture();\n\t\tm_Capture = false;\n\t\tClearWindowDetails();\n\t\treturn 0;\n\t}\n\tif (id == IDOK) {\n\t\tCString text;\n\t\tGetDlgItemText(IDC_HANDLE, text);\n\t\tm_SelectedHwnd = (HWND)FormatHelper::ParseHex(text);\n\t}\n\n\tEndDialog(id);\n\treturn 0;\n}\n\nLRESULT CFindWindowDlg::OnSearch(WORD, WORD id, HWND, BOOL&) {\n\tCString handle;\n\tGetDlgItemText(IDC_HANDLE, handle);\n\tif (!handle.IsEmpty()) {\n\t\tauto hWnd = (HWND)FormatHelper::ParseHex(handle);\n\t\tif (::IsWindow(hWnd)) {\n\t\t\tSelectWindow(hWnd);\n\t\t}\n\t\telse {\n\t\t\tAtlMessageBox(m_hWnd, (PCWSTR)(L\"Cannot locate window with handle \" + handle), L\"Window Finder\", MB_ICONERROR);\n\t\t}\n\t\treturn 0;\n\t}\n\tCString text, cls;\n\tGetDlgItemText(IDC_TEXT, text);\n\tGetDlgItemText(IDC_CLASSNAME, cls);\n\tif (text.IsEmpty() && cls.IsEmpty()) {\n\t\tAtlMessageBox(m_hWnd, L\"Specify handle, class and/or text to search\", L\"Window Finder\", MB_ICONWARNING);\n\t\treturn 0;\n\t}\n\n\tauto hWnd = ::FindWindowEx(nullptr, nullptr, cls, text);\n\tif (hWnd)\n\t\tSelectWindow(hWnd);\n\telse\n\t\tAtlMessageBox(m_hWnd, L\"Cannot locate window with this class/text\", L\"Window Finder\", MB_ICONERROR);\n\treturn 0;\n}\n\nLRESULT CFindWindowDlg::OnMouseDown(UINT, WPARAM, LPARAM, BOOL&) {\n\tm_WinDrag.SetCapture();\n\tm_Capture = true;\n\tm_WinDrag.ShowWindow(SW_HIDE);\n\tif (IsDlgButtonChecked(IDC_HIDE) == BST_CHECKED) {\n\t\t::ShowWindow(m_pFrame->GetHwnd(), SW_HIDE);\n\t}\n\treturn 0;\n}\n\nLRESULT CFindWindowDlg::OnMouseUp(UINT, WPARAM, LPARAM, BOOL&) {\n\tReleaseCapture();\n\tm_Capture = false;\n\tm_WinDrag.ShowWindow(SW_SHOW);\n\tSetCursor(AtlLoadSysCursor(IDC_ARROW));\n\tif(m_hCursorWnd)\n\t\tWindowHelper::HighlightBorder(m_hCursorWnd, false);\n\tif (IsDlgButtonChecked(IDC_HIDE) == BST_CHECKED) {\n\t\t::ShowWindow(m_pFrame->GetHwnd(), SW_SHOW);\n\t}\n\treturn 0;\n}\n\nLRESULT CFindWindowDlg::OnMouseMove(UINT, WPARAM, LPARAM lp, BOOL&) {\n\tif (m_Capture) {\n\t\t::SetCursor(m_DragCursor);\n\t\tCPoint pt{ GET_X_LPARAM(lp), GET_Y_LPARAM(lp) };\n\t\tm_WinDrag.ClientToScreen(&pt);\n\t\tauto hWnd = ::WindowFromPoint(pt);\n\t\tDWORD pid, tid;\n\t\tif ((tid = ::GetWindowThreadProcessId(hWnd, &pid)) && pid == ::GetCurrentProcessId())\n\t\t\treturn 0;\n\n\t\tif (m_hCursorWnd && m_hCursorWnd != hWnd)\n\t\t\tWindowHelper::HighlightBorder(m_hCursorWnd, false);\n\t\tif (hWnd != m_hCursorWnd) {\n\t\t\tWindowHelper::HighlightBorder(hWnd);\n\t\t\tm_hCursorWnd.Detach();\n\t\t\tm_hCursorWnd.Attach(hWnd);\n\t\t\tSelectWindow(hWnd);\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "WinSpy/FindWindowDlg.h",
    "content": "#pragma once\n\n#include \"Interfaces.h\"\n#include \"DialogHelper.h\"\n\nclass CFindWindowDlg : \n\tpublic CDialogImpl<CFindWindowDlg>,\n\tpublic CDynamicDialogLayout<CFindWindowDlg>,\n\tpublic CDialogHelper<CFindWindowDlg> {\npublic:\n\tenum { IDD = IDD_FINDWINDOW };\n\n\tCFindWindowDlg(IMainFrame* frame) : m_pFrame(frame), m_WinDrag(this, 1) {}\n\n\tHWND GetSelectedHwnd() const;\n\nprotected:\n\tBEGIN_MSG_MAP(CFindWindowDlg)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_ID_HANDLER(IDC_SEARCH, OnSearch)\n\t\tCOMMAND_ID_HANDLER(IDOK, OnCloseCmd)\n\t\tCOMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)\n\t\tCHAIN_MSG_MAP(CDynamicDialogLayout<CFindWindowDlg>)\n\tALT_MSG_MAP(1)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnMouseUp)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnMouseDown)\n\tEND_MSG_MAP()\n\n\t// Handler prototypes (uncomment arguments if needed):\n//\tLRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n//\tLRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n//\tLRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\nprivate:\n\tvoid ClearWindowDetails();\n\tvoid SelectWindow(HWND hWnd);\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD id, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnSearch(WORD /*wNotifyCode*/, WORD id, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\n\tLRESULT OnMouseDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnMouseUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\n\tCContainedWindowT<CStatic> m_WinDrag;\n\tCIcon m_DragCursor;\n\tCWindow m_hCursorWnd;\n\tIMainFrame* m_pFrame;\n\tHWND m_SelectedHwnd{ nullptr };\n\tbool m_Capture{ false };\n};\n\n"
  },
  {
    "path": "WinSpy/FormatHelper.cpp",
    "content": "#include \"pch.h\"\n#include \"FormatHelper.h\"\n#include <sstream>\n\nCString FormatHelper::FormatHWndOrNone(HWND hWnd) {\n\tCString text;\n\tif (hWnd)\n\t\ttext.Format(L\"0x%zX\", (DWORD_PTR)hWnd);\n\telse\n\t\ttext = L\"(None)\";\n\treturn text;\n}\n\nCString FormatHelper::RectToString(CRect const& rc) {\n\tCString text;\n\ttext.Format(L\"(%d,%d)-(%d,%d) [%d x %d]\", rc.left, rc.top, rc.right, rc.bottom, rc.Width(), rc.Height());\n\treturn text;\n}\n\nDWORD_PTR FormatHelper::ParseHex(CString const& text) {\n\tstd::wstringstream ss;\n\tss << std::hex;\n\tif (text.Left(2).CompareNoCase(L\"0x\") == 0)\n\t\tss << (PCWSTR)text.Mid(2);\n\telse\n\t\tss << (PCWSTR)text;\n\tDWORD_PTR value;\n\tss >> value;\n\treturn value;\n}\n\nCString FormatHelper::FormatPoint(POINT const& pt) {\n\tCString text;\n\ttext.Format(L\"(%d,%d)\", pt.x, pt.y);\n\treturn text;\n}\n"
  },
  {
    "path": "WinSpy/FormatHelper.h",
    "content": "#pragma once\n\nstruct FormatHelper {\n\tstatic CString FormatHWndOrNone(HWND hWnd);\n\tstatic CString RectToString(CRect const& rc);\n\tstatic DWORD_PTR ParseHex(CString const& text);\n\tstatic CString FormatPoint(POINT const& pt);\n};\n\n"
  },
  {
    "path": "WinSpy/FrameWindowHelper.h",
    "content": "#pragma once\n\n#include \"Interfaces.h\"\n\ntemplate<typename T>\nstruct CFrameWindowHelper : CIdleHandler {\n\tHWND CreateAndInitToolBar(const ToolBarButtonInfo* buttons, int count) {\n\t\tauto pT = static_cast<T*>(this);\n\t\tCToolBarCtrl tb;\n\t\tauto hWndToolBar = tb.Create(pT->m_hWnd, CWindow::rcDefault, nullptr, ATL_SIMPLE_TOOLBAR_PANE_STYLE | TBSTYLE_LIST, 0, ATL_IDW_TOOLBAR);\n\t\ttb.SetExtendedStyle(TBSTYLE_EX_MIXEDBUTTONS);\n\n\t\tCImageList tbImages;\n\t\ttbImages.Create(24, 24, ILC_COLOR32 | ILC_COLOR | ILC_MASK, 4, 4);\n\t\ttb.SetImageList(tbImages);\n\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tauto& b = buttons[i];\n\t\t\tif (b.id == 0)\n\t\t\t\ttb.AddSeparator(0);\n\t\t\telse {\n\t\t\t\tint image = b.image == 0 ? I_IMAGENONE : tbImages.AddIcon(AtlLoadIconImage(b.image, 0, 24, 24));\n\t\t\t\ttb.AddButton(b.id, b.style | (b.text ? BTNS_SHOWTEXT : 0), TBSTATE_ENABLED, image, b.text, 0);\n\t\t\t}\n\t\t}\n\n\t\tpT->CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);\n\t\tpT->AddSimpleReBarBand(tb);\n\n\t\tpT->UIAddToolBar(hWndToolBar);\n\t\t_Module.GetMessageLoop()->AddIdleHandler(this);\n\n\t\treturn hWndToolBar;\n\t}\n\n\tBOOL OnIdle() override {\n\t\tauto pT = static_cast<T*>(this);\n\t\tpT->UIUpdateToolBar();\n\t\treturn FALSE;\n\t}\n};\n"
  },
  {
    "path": "WinSpy/HookHelper.cpp",
    "content": "#include \"pch.h\"\n#include \"HookHelper.h\"\n\ndecltype(AddHook)* pAddHook;\ndecltype(RemoveHook)* pRemoveHook;\n\nbool HookHelper::InitHookLib() {\n    if (!pAddHook) {\n        auto hLib = ::LoadLibrary(L\"WinSpyHook.dll\");\n        if (hLib) {\n            pAddHook = (decltype(pAddHook))::GetProcAddress(hLib, \"AddHook\");\n            pRemoveHook = (decltype(pRemoveHook))::GetProcAddress(hLib, \"RemoveHook\");\n        }\n    }\n    return pAddHook != nullptr;\n}\n\nbool __stdcall HookHelper::AddHook(DWORD hookType, HookConfig const& config) {\n    if (!InitHookLib())\n        return false;\n\n    return pAddHook(hookType, config);\n}\n\nbool __stdcall HookHelper::RemoveHook(DWORD tid) {\n    if (!InitHookLib())\n        return false;\n\n    return pRemoveHook(tid);\n}\n"
  },
  {
    "path": "WinSpy/HookHelper.h",
    "content": "#pragma once\n\n#include \"hooks.h\"\n\nstruct HookHelper abstract final {\n\tstatic bool InitHookLib();\n\tstatic bool WINAPI AddHook(DWORD hookType, HookConfig const& config);\n\tstatic bool WINAPI RemoveHook(DWORD tid);\n\n};\n\n"
  },
  {
    "path": "WinSpy/IconHelper.cpp",
    "content": "#include \"pch.h\"\n#include \"IconHelper.h\"\n\nHICON IconHelper::GetShieldIcon() {\n\treturn GetStockIcon(SIID_SHIELD);\n}\n\nHICON IconHelper::GetStockIcon(SHSTOCKICONID id, bool big) {\n\tSHSTOCKICONINFO ssii = { sizeof(ssii) };\n\tif (FAILED(::SHGetStockIconInfo(id, (big ? 0 : SHGSI_SMALLICON) | SHGSI_ICON, &ssii)))\n\t\treturn nullptr;\n\n\treturn ssii.hIcon;\n}\n"
  },
  {
    "path": "WinSpy/IconHelper.h",
    "content": "#pragma once\n\nstruct IconHelper {\n\tstatic HICON GetStockIcon(SHSTOCKICONID id, bool big = false);\n\tstatic HICON GetShieldIcon();\n};\n"
  },
  {
    "path": "WinSpy/ImageIconCache.cpp",
    "content": "#include \"pch.h\"\n#include \"ImageIconCache.h\"\n#include \"resource.h\"\n\nint ImageIconCache::GetIcon(const CString& path, HICON* phIcon) const {\n\tif (path.IsEmpty() || path.Find(L'\\\\') < 0)\n\t\treturn _defIcon;\n\n\tstd::wstring wspath(path);\n\t{\n\t\tauto it = _icons.find(wspath);\n\t\tif (it != _icons.end()) {\n\t\t\tint index = it->second;\n\t\t\tif (phIcon)\n\t\t\t\t*phIcon = _images.GetIcon(index);\n\t\t\treturn index;\n\t\t}\n\t}\n\tWORD index = 0;\n\tCString spath(path);\n\tauto hIcon = ::ExtractAssociatedIcon(_Module.GetModuleInstance(), spath.GetBufferSetLength(MAX_PATH), &index);\n\n\tif (hIcon) {\n\t\tint index = _images.AddIcon(hIcon);\n\t\tif (phIcon)\n\t\t\t*phIcon = hIcon;\n\t\t_icons.insert({ wspath, index });\n\t\treturn index;\n\t}\n\treturn _defIcon;\n}\n\nImageIconCache::Map::const_iterator ImageIconCache::begin() const {\n\treturn _icons.begin();\n}\n\nImageIconCache::Map::const_iterator ImageIconCache::end() const {\n\treturn _icons.end();\n}\n\nImageIconCache::ImageIconCache() {\n}\n\nvoid ImageIconCache::SetImageList(HIMAGELIST hil) {\n\t_images.Attach(hil);\n\t_defIcon = _images.AddIcon(AtlLoadSysIcon(IDI_APPLICATION));\n}\n\nHIMAGELIST ImageIconCache::GetImageList() const {\n\treturn _images;\n}\n\nImageIconCache& ImageIconCache::Get() {\n\tstatic ImageIconCache cache;\n\treturn cache;\n}\n\n"
  },
  {
    "path": "WinSpy/ImageIconCache.h",
    "content": "#pragma once\n\nstruct ImageIconCache {\n\tstatic ImageIconCache& Get();\n\n\tHIMAGELIST GetImageList() const;\n\tvoid SetImageList(HIMAGELIST hil);\n\tint GetIcon(const CString& path, HICON* phIcon = nullptr) const;\n\n\tusing Map = std::unordered_map<std::wstring, int>;\n\tMap::const_iterator begin() const;\n\tMap::const_iterator end() const;\n\nprivate:\n\tImageIconCache();\n\tImageIconCache(const ImageIconCache&) = delete;\n\tImageIconCache& operator=(const ImageIconCache&) = delete;\n\nprivate:\n\tmutable CImageList _images;\n\tmutable Map _icons;\n\tint _defIcon;\n};\n"
  },
  {
    "path": "WinSpy/Interfaces.h",
    "content": "#pragma once\n\nstruct CMessagesView;\n\nstruct IMainFrame {\n\tvirtual CUpdateUIBase& GetUIUpdate() = 0;\n\tvirtual UINT ShowPopupMenu(HMENU hMenu, const POINT& pt, DWORD flags = 0) = 0;\n\tvirtual HWND GetHwnd() const = 0;\n\tvirtual CMessagesView* CreateMessagesView() = 0;\n\tvirtual void CloseTab(CWindow* win) = 0;\n};\n\nstruct ToolBarButtonInfo {\n\tUINT id;\n\tint image;\n\tBYTE style = BTNS_BUTTON;\n\tPCWSTR text = nullptr;\n};\n"
  },
  {
    "path": "WinSpy/MainFrm.cpp",
    "content": "// MainFrm.cpp : implmentation of the CMainFrame class\n//\n/////////////////////////////////////////////////////////////////////////////\n\n#include \"pch.h\"\n#include \"resource.h\"\n#include \"aboutdlg.h\"\n#include \"WindowsView.h\"\n#include \"MainFrm.h\"\n#include \"FindWindowDlg.h\"\n#include \"IconHelper.h\"\n#include \"ImageIconCache.h\"\n#include \"ProcessesView.h\"\n#include \"SecurityHelper.h\"\n#include \"MessagesView.h\"\n#include \"AutomationTreeView.h\"\n\nconst int WINDOW_MENU_POSITION = 5;\n\nBOOL CMainFrame::PreTranslateMessage(MSG* pMsg) {\n\tif (CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))\n\t\treturn TRUE;\n\n\treturn m_view.PreTranslateMessage(pMsg);\n}\n\nBOOL CMainFrame::OnIdle() {\n\tUIUpdateToolBar();\n\treturn FALSE;\n}\n\nLRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tif (SecurityHelper::IsRunningElevated()) {\n\t\tCMenuHandle menu = GetMenu();\n\t\tmenu.GetSubMenu(0).DeleteMenu(0, MF_BYPOSITION);\n\t\tmenu.GetSubMenu(0).DeleteMenu(0, MF_BYPOSITION);\n\t}\n\tInitMenu();\n\n\tCToolBarCtrl tb;\n\tauto hWndToolBar = tb.Create(m_hWnd, nullptr, nullptr, ATL_SIMPLE_TOOLBAR_PANE_STYLE | TBSTYLE_LIST, 0, ATL_IDW_TOOLBAR);\n\ttb.SetExtendedStyle(TBSTYLE_EX_MIXEDBUTTONS);\n\tInitToolBar(tb);\n\n\tCreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);\n\tAddSimpleReBarBand(hWndToolBar, nullptr, TRUE);\n\n\tCReBarCtrl rb(m_hWndToolBar);\n\trb.LockBands(true);\n\n\tCreateSimpleStatusBar();\n\n\t//m_view.m_bTabCloseButton = false;\n\tm_hWndClient = m_view.Create(m_hWnd, rcDefault, nullptr,\n\t\tWS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);\n\n\tUIAddToolBar(hWndToolBar);\n\tUISetCheck(ID_VIEW_TOOLBAR, 1);\n\tUISetCheck(ID_VIEW_STATUS_BAR, 1);\n\n\tImageIconCache::Get().SetImageList(WindowHelper::GetImageList());\n\n\t// register object for message filtering and idle updates\n\tCMessageLoop* pLoop = _Module.GetMessageLoop();\n\tATLASSERT(pLoop != NULL);\n\tpLoop->AddMessageFilter(this);\n\tpLoop->AddIdleHandler(this);\n\n\tCImageList images;\n\timages.Create(16, 16, ILC_COLOR32, 4, 4);\n\tUINT icons[] = { IDI_WINDOWS, IDI_PROCESSES, IDI_MESSAGES, IDI_AUTOMATION };\n\tfor (auto icon : icons) {\n\t\timages.AddIcon(AtlLoadIconImage(icon, 0, 16, 16));\n\t}\n\tm_view.SetImageList(images);\n\tm_view.SetWindowMenu(((CMenuHandle)GetMenu()).GetSubMenu(WINDOW_MENU_POSITION));\n\n\tPostMessage(WM_COMMAND, ID_VIEW_ALLWINDOWS);\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) {\n\t// unregister message filtering and idle updates\n\tCMessageLoop* pLoop = _Module.GetMessageLoop();\n\tATLASSERT(pLoop != NULL);\n\tpLoop->RemoveMessageFilter(this);\n\tpLoop->RemoveIdleHandler(this);\n\n\tbHandled = FALSE;\n\treturn 1;\n}\n\nLRESULT CMainFrame::OnMenuSelect(UINT, WPARAM, LPARAM, BOOL&) {\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tPostMessage(WM_CLOSE);\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnViewAllWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tauto pView = new CWindowsView(this);\n\t{\n\t\tCWaitCursor wait;\n\t\tpView->Create(m_view, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);\n\t\tm_view.AddPage(pView->m_hWnd, _T(\"Windows Tree\"), 0, pView);\n\t}\n\tpView->OnActivate(true);\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnViewAllProcesses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tauto pView = new CProcessesView(this);\n\t{\n\t\tCWaitCursor wait;\n\t\tpView->Create(m_view, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);\n\t\tm_view.AddPage(pView->m_hWnd, _T(\"Processes\"), 1, pView);\n\t}\n\tpView->OnActivate(true);\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tstatic BOOL bVisible = TRUE;\t// initially visible\n\tbVisible = !bVisible;\n\tCReBarCtrl rebar = m_hWndToolBar;\n\tint nBandIndex = rebar.IdToIndex(ATL_IDW_BAND_FIRST + 1);\t// toolbar is 2nd added band\n\trebar.ShowBand(nBandIndex, bVisible);\n\tUISetCheck(ID_VIEW_TOOLBAR, bVisible);\n\tUpdateLayout();\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tBOOL bVisible = !::IsWindowVisible(m_hWndStatusBar);\n\t::ShowWindow(m_hWndStatusBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);\n\tUISetCheck(ID_VIEW_STATUS_BAR, bVisible);\n\tUpdateLayout();\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tCAboutDlg dlg;\n\tdlg.DoModal();\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnWindowClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tint nActivePage = m_view.GetActivePage();\n\tif (nActivePage != -1)\n\t\tm_view.RemovePage(nActivePage);\n\telse\n\t\t::MessageBeep((UINT)-1);\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnWindowCloseAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tm_view.RemoveAllPages();\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnWindowActivate(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tint nPage = wID - ID_WINDOW_TABFIRST;\n\tm_view.SetActivePage(nPage);\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnCommandToActiveView(WORD code, WORD id, HWND h, BOOL&) {\n\tauto page = m_view.GetActivePage();\n\tif (page < 0)\n\t\treturn 0;\n\n\treturn ::SendMessage(m_view.GetPageHWND(page), WM_COMMAND, MAKELONG(id, code), reinterpret_cast<LPARAM>(h));\n}\n\nLRESULT CMainFrame::OnFindWindow(WORD, WORD, HWND, BOOL&) {\n\tCFindWindowDlg dlg(this);\n\tif (IDOK == dlg.DoModal()) {\n\t\tWindowHelper::ShowWindowProperties(dlg.GetSelectedHwnd());\n\t}\n\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnRunAsAdmin(WORD, WORD, HWND, BOOL&) {\n\tif (SecurityHelper::RunElevated()) {\n\t\tSendMessage(WM_CLOSE);\n\t}\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnTabCloseButton(int, LPNMHDR, BOOL&) {\n\treturn 0;\n}\n\nLRESULT CMainFrame::OnViewAutomationTree(WORD, WORD, HWND, BOOL&) {\n\tauto pView = new CAutomationTreeView(this);\n\tpView->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);\n\tm_view.AddPage(pView->m_hWnd, L\"UI Automation\", 2, pView);\n\tpView->OnActivate(true);\n\treturn 0;\n}\n\nCUpdateUIBase& CMainFrame::GetUIUpdate() {\n\treturn *this;\n}\n\nUINT CMainFrame::ShowPopupMenu(HMENU hMenu, const POINT& pt, DWORD flags) {\n\treturn (UINT)ShowContextMenu(hMenu, 0, pt.x, pt.y);\n}\n\nCMessagesView* CMainFrame::CreateMessagesView() {\n\tauto pView = new CMessagesView(this);\n\tpView->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);\n\tm_view.AddPage(pView->m_hWnd, L\"Messages\", 2, pView);\n\tpView->OnActivate(true);\n\n\treturn pView;\n}\n\nvoid CMainFrame::CloseTab(CWindow* win) {\n\tm_view.RemovePage(m_view.GetActivePage());\n}\n\nvoid CMainFrame::InitToolBar(CToolBarCtrl& tb) {\n\tCImageList tbImages;\n\ttbImages.Create(24, 24, ILC_COLOR32, 8, 4);\n\ttb.SetImageList(tbImages);\n\n\tstruct {\n\t\tUINT id;\n\t\tint image;\n\t\tint style = BTNS_BUTTON;\n\t\tPCWSTR text = nullptr;\n\t} buttons[] = {\n\t\t{ ID_VIEW_REFRESH, IDI_REFRESH },\n\t\t{ 0 },\n\t\t{ ID_VIEW_ALLWINDOWS, IDI_WINDOWS },\n\t\t{ ID_VIEW_ALLPROCESSES, IDI_PROCESSES },\n\t\t{ ID_WINDOW_FIND, IDI_WINDOWSEARCH },\n\t\t{ 0 },\n\t\t{ ID_VIEW_HIDDENWINDOWS, IDI_WINDOW_HIDDEN },\n\t\t{ ID_VIEW_EMPTYTITLEWINDOWS, IDI_WINDOW_NOTEXT },\n\t\t{ ID_WINDOW_PROPERTIES, IDI_WINPROP },\n\t};\n\tfor (auto& b : buttons) {\n\t\tif (b.id == 0)\n\t\t\ttb.AddSeparator(0);\n\t\telse {\n\t\t\tint image = tbImages.AddIcon(AtlLoadIconImage(b.image, 0, 24, 24));\n\t\t\ttb.AddButton(b.id, b.style, TBSTATE_ENABLED, image, b.text, 0);\n\t\t}\n\t}\n}\n\nvoid CMainFrame::InitMenu() {\n\tAddMenu(GetMenu());\n\n\tstruct {\n\t\tUINT id, icon;\n\t\tHICON hIcon = nullptr;\n\t} cmds[] = {\n\t\t{ ID_FILE_RUNASADMINISTRATOR, 0, IconHelper::GetShieldIcon() },\n\t\t{ ID_VIEW_REFRESH, IDI_REFRESH },\n\t\t{ ID_VIEW_ALLWINDOWS, IDI_WINDOWS },\n\t\t{ ID_VIEW_HIDDENWINDOWS, IDI_WINDOW_HIDDEN },\n\t\t{ ID_VIEW_EMPTYTITLEWINDOWS, IDI_WINDOW_NOTEXT },\n\t\t{ ID_WINDOW_CLOSE, IDI_WINDOW_CLOSE },\n\t\t{ ID_STATE_CLOSE, IDI_WINDOW_CLOSE },\n\t\t{ ID_WINDOW_MINIMIZE, IDI_WINDOW_MINIMIZE },\n\t\t{ ID_WINDOW_MAXIMIZE, IDI_WINDOW_MAXIMIZE },\n\t\t{ ID_VIEW_ALLPROCESSES, IDI_PROCESSES },\n\t\t{ ID_WINDOW_PROPERTIES, IDI_WINPROP },\n\t\t{ ID_PROCESS_PROPERTIES, IDI_PROCESS_INFO },\n\t\t{ ID_WINDOW_FIND, IDI_WINDOWSEARCH },\n\t\t{ ID_WINDOW_RESTORE, IDI_RESTORE },\n\t\t{ ID_TREE_SENDTOBACK, IDI_WINDOW_SENDTOBACK },\n\t\t{ ID_WINDOW_BRINGTOFRONT, IDI_SENDTOFRONT },\n\t};\n\tfor (auto& cmd : cmds) {\n\t\tif (cmd.icon)\n\t\t\tAddCommand(cmd.id, cmd.icon);\n\t\telse\n\t\t\tAddCommand(cmd.id, cmd.hIcon);\n\t}\n}\n\nLRESULT CMainFrame::OnTabActivated(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) {\n\tif (m_ActivePage >= 0 && m_ActivePage < m_view.GetPageCount())\n\t\t::SendMessage(m_view.GetPageHWND(m_ActivePage), TBVN_PAGEACTIVATED, 0, 0);\n\n\tm_ActivePage = m_view.GetActivePage();\n\tif (m_ActivePage < 0)\n\t\treturn 0;\n\n\treturn ::SendMessage(m_view.GetPageHWND(m_ActivePage), TBVN_PAGEACTIVATED, 1, 0);\n}\n"
  },
  {
    "path": "WinSpy/MainFrm.h",
    "content": "// MainFrm.h : interface of the CMainFrame class\n//\n/////////////////////////////////////////////////////////////////////////////\n\n#pragma once\n\n#include \"Interfaces.h\"\n#include <CustomTabView.h>\n#include <OwnerDrawnMenu.h>\n\nclass CMainFrame : \n\tpublic CFrameWindowImpl<CMainFrame>, \n\tpublic CAutoUpdateUI<CMainFrame>,\n\tpublic COwnerDrawnMenu<CMainFrame>,\n\tpublic CMessageFilter, \n\tpublic CIdleHandler,\n\tpublic IMainFrame {\npublic:\n\tDECLARE_FRAME_WND_CLASS(L\"WinSpyMainWindowClass\", IDR_MAINFRAME)\n\n\tBOOL PreTranslateMessage(MSG* pMsg) override;\n\tBOOL OnIdle() override;\n\n\tBEGIN_MSG_MAP(CMainFrame)\n\t\t//NOTIFY_CODE_HANDLER(TBVN_TABCLOSEBTN, OnTabCloseButton)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_ALLWINDOWS, OnViewAllWindows)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_ALLPROCESSES, OnViewAllProcesses)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_AUTOMATIONTREE, OnViewAutomationTree)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)\n\t\tCOMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_FIND, OnFindWindow)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)\n\t\tCOMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)\n\t\tCOMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)\n\t\tCOMMAND_ID_HANDLER(ID_FILE_RUNASADMINISTRATOR, OnRunAsAdmin)\n\t\tMESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tCHAIN_MSG_MAP(CAutoUpdateUI<CMainFrame>)\n\t\tCHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)\n\t\tCOMMAND_RANGE_HANDLER(1, 0xffff, OnCommandToActiveView)\n\t\tNOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabActivated)\n\t\tCHAIN_MSG_MAP(COwnerDrawnMenu<CMainFrame>)\n\tEND_MSG_MAP()\n\nprivate:\n\t// IMainFrame\n\tCUpdateUIBase& GetUIUpdate() override;\n\tUINT ShowPopupMenu(HMENU hMenu, const POINT& pt, DWORD flags = 0) override;\n\tHWND GetHwnd() const override {\n\t\treturn m_hWnd;\n\t}\n\tCMessagesView* CreateMessagesView() override;\n\tvoid CloseTab(CWindow* win) override;\n\n\tvoid InitToolBar(CToolBarCtrl& tb);\n\tvoid InitMenu();\n\n// Handler prototypes (uncomment arguments if needed):\n//\tLRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n//\tLRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n//\tLRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnTabActivated(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);\n\tLRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnViewAllWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnViewAllProcesses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowCloseAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowActivate(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnCommandToActiveView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnFindWindow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnRunAsAdmin(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnTabCloseButton(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnViewAutomationTree(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\n\tint m_ActivePage = -1;\n\tCCustomTabView m_view;\n};\n"
  },
  {
    "path": "WinSpy/MessageDecoder.cpp",
    "content": "#include \"pch.h\"\n#include \"MessageDecoder.h\"\n#include \"FormatHelper.h\"\n\n#define CASE_STR(x) case x: return L#x \n\nCString MessageDecoder::Decode(UINT msg, WPARAM wp, LPARAM lp) {\n    if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) {\n        CPoint pt(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));\n        return L\"Keys: [\" + MouseKey((int)wp) + L\"] Pos: \" + FormatHelper::FormatPoint(pt);\n    }\n    if (msg >= WM_KEYFIRST && msg <= WM_KEYLAST) {\n        CString text;\n        text.Format(L\"VK: %u\", (DWORD)wp);\n        return text;\n    }\n\n    switch (msg) {\n        case WM_SYSCOMMAND:\n        {\n            CPoint pt(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));\n            auto cmd = SysCommandToString((DWORD)wp);\n            CString pos;\n            if (pt.y > 1) {\n                pos = L\"Cursor: \" + FormatHelper::FormatPoint(pt);\n            }\n            return L\"Cmd: \" + cmd + L\" \" + pos;\n        }\n        case WM_SETREDRAW:\n            return CString(L\"Redraw: \") + (wp ? L\"True\" : L\"False\");\n\n        case WM_SIZE:\n        {\n            CPoint pt(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));\n            auto size = L\" Size: \" + FormatHelper::FormatPoint(pt);\n            return L\"Type: \" + SizeParamToString((DWORD)wp) + size;\n        }\n    }\n\n    return L\"\";\n}\n\nCString MessageDecoder::MouseKey(int key) {\n    static const struct {\n        int key;\n        PCWSTR name;\n    } keys[] = {\n        { MK_SHIFT, L\"Shift\" },\n        { MK_CONTROL, L\"Ctrl\" },\n        { MK_LBUTTON, L\"LButton\" },\n        { MK_RBUTTON, L\"RButton\" },\n        { MK_MBUTTON, L\"MButton\" },\n        { MK_XBUTTON1, L\"XButton1\" },\n        { MK_XBUTTON2, L\"XButton2\" },\n    };\n\n    CString text;\n    for (auto& item : keys) {\n        if ((key & item.key) == item.key)\n            text += item.name + CString(L\", \");\n    }\n    if (!text.IsEmpty())\n        text = text.Left(text.GetLength() - 2);\n    else\n        text = L\"None\";\n\n    return text;\n}\n\nCString MessageDecoder::SysCommandToString(DWORD cmd) {\n    switch (cmd) {\n        CASE_STR(SC_CLOSE);\n        CASE_STR(SC_CONTEXTHELP);\n        CASE_STR(SC_DEFAULT);\n        CASE_STR(SC_HOTKEY);\n        CASE_STR(SC_HSCROLL);\n        CASE_STR(SCF_ISSECURE);\n        CASE_STR(SC_KEYMENU);\n        CASE_STR(SC_MAXIMIZE);\n        CASE_STR(SC_MINIMIZE);\n        CASE_STR(SC_MONITORPOWER);\n        CASE_STR(SC_MOUSEMENU);\n        CASE_STR(SC_MOVE);\n        CASE_STR(SC_NEXTWINDOW);\n        CASE_STR(SC_PREVWINDOW);\n        CASE_STR(SC_RESTORE);\n        CASE_STR(SC_SCREENSAVE);\n        CASE_STR(SC_SIZE);\n        CASE_STR(SC_TASKLIST);\n        CASE_STR(SC_VSCROLL);\n    }\n    CString text;\n    text.Format(L\"0x%X\", cmd);\n    return text;\n}\n\nCString MessageDecoder::SizeParamToString(DWORD type) {\n    switch (type) {\n        CASE_STR(SIZE_MAXHIDE);\n        CASE_STR(SIZE_MAXIMIZED);\n        CASE_STR(SIZE_MAXSHOW);\n        CASE_STR(SIZE_MINIMIZED);\n        CASE_STR(SIZE_RESTORED);\n    }\n    CString text;\n    text.Format(L\"%u\", type);\n    return text;\n}\n"
  },
  {
    "path": "WinSpy/MessageDecoder.h",
    "content": "#pragma once\n\nstruct MessageDecoder final abstract {\n\tstatic CString Decode(UINT msg, WPARAM wp, LPARAM lp);\n\tstatic CString MouseKey(int key);\n\tstatic CString SysCommandToString(DWORD cmd);\n\tstatic CString SizeParamToString(DWORD type);\n};"
  },
  {
    "path": "WinSpy/MessagesView.cpp",
    "content": "#include \"pch.h\"\n#include \"MessagesView.h\"\n#include \"hooks.h\"\n#include \"FormatHelper.h\"\n#include \"WindowHelper.h\"\n#include \"MessageDecoder.h\"\n#include \"HookHelper.h\"\n\nbool CMessagesView::CaptureWindow(HWND hWnd) {\n\tif (!m_hReadyEvent)\n\t\tm_hReadyEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);\n\n\tm_CaptureHwnd = hWnd;\n\tm_CaptureOptions = CaptureOptions::Window;\n\n\tm_CaptureTid = ::GetWindowThreadProcessId(hWnd, nullptr);\n\tif (m_hThread) {\n\t\t::PostThreadMessage(::GetThreadId(m_hThread), WM_QUIT, 0, 0);\n\t\t::CloseHandle(m_hThread);\n\t}\n\n\tm_hThread = ::CreateThread(nullptr, 0, [](auto param) {\n\t\treturn ((CMessagesView*)param)->ProcessHook();\n\t\t}, this, 0, nullptr);\n\tif (!m_hThread)\n\t\treturn false;\n\n\tATLVERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hReadyEvent, INFINITE));\n\tATLASSERT(m_CallbackWnd);\n\n\tHookConfig config{};\n\tconfig.CallbackWnd = m_CallbackWnd;\n\tconfig.TargetWnd = hWnd;\n\tconfig.Options = HookOptions::Window | HookOptions::ChildWindows;\n\tconfig.ThreadId = m_CaptureTid;\n\treturn HookHelper::AddHook(WH_GETMESSAGE, config);\n}\n\nvoid CMessagesView::HookCallbackMsg(DWORD hookType, HookDataHeader* header) {\n\tswitch (header->HookType) {\n\t\tcase WH_GETMESSAGE:\n\t\t\tauto data = reinterpret_cast<GetMessageData*>(header);\n\t\t\tif (data->wParam == PM_REMOVE) {\n\t\t\t\tMessageInfo mi(data->Msg);\n\t\t\t\tmi.ThreadId = ::GetWindowThreadProcessId(mi.hwnd, &mi.ProcessId);\n\t\t\t\tstd::lock_guard locker(m_TempMessagesLock);\n\t\t\t\tm_TempMessages.push_back(mi);\n\t\t\t}\n\t\t\tbreak;\n\t}\n}\n\nvoid CMessagesView::OnFinalMessage(HWND) {\n\tdelete this;\n}\n\nCString CMessagesView::GetColumnText(HWND hWnd, int row, int col) const {\n\tauto& item = m_Messages[row];\n\tCString text;\n\tswitch (GetColumnManager(hWnd)->GetColumnTag<ColumnType>(col)) {\n\t\tcase ColumnType::Window: \n\t\t\treturn FormatHelper::FormatHWndOrNone(item.hwnd);\n\n\t\tcase ColumnType::Message: \n\t\t\ttext.Format(L\"%s (0x%X)\", (PCWSTR)WindowHelper::WindowMessageToString(item.message), item.message);\n\t\t\tbreak;\n\n\t\tcase ColumnType::Thread:\n\t\t\ttext.Format(L\"%u\", item.ThreadId);\n\t\t\tbreak;\n\n\t\tcase ColumnType::Process:\n\t\t\ttext.Format(L\"%u\", item.ProcessId);\n\t\t\tbreak;\n\n\t\tcase ColumnType::wParam:\n\t\t\ttext.Format(L\"0x%zX\", item.wParam);\n\t\t\tbreak;\n\n\t\tcase ColumnType::lParam:\n\t\t\ttext.Format(L\"0x%zX\", item.lParam);\n\t\t\tbreak;\n\n\t\tcase ColumnType::Time:\n\t\t\ttext.Format(L\"0x%X\", item.time);\n\t\t\tbreak;\n\n\t\tcase ColumnType::Point:\n\t\t\treturn FormatHelper::FormatPoint(item.pt);\n\n\t\tcase ColumnType::DecodedMessage:\n\t\t\treturn MessageDecoder::Decode(item.message, item.wParam, item.lParam);\n\t}\n\treturn text;\n}\n\nvoid CMessagesView::UpdateList() {\n\tm_List.SetItemCountEx((int)m_Messages.size(), LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);\n\tm_List.RedrawItems(m_List.GetTopIndex(), m_List.GetTopIndex() + m_List.GetCountPerPage());\n}\n\nDWORD CMessagesView::ProcessHook() {\n\tm_CallbackWnd.Create(HWND_MESSAGE, nullptr, nullptr);\n\tATLASSERT(m_CallbackWnd);\n\n\t::SetEvent(m_hReadyEvent);\n\n\tMSG msg;\n\twhile (::GetMessage(&msg, nullptr, 0, 0))\n\t\t::DispatchMessage(&msg);\n\n\tm_CallbackWnd.DestroyWindow();\n\treturn 0;\n}\n\nLRESULT CMessagesView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) {\n\tm_hWndClient = m_List.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN\n\t\t| LVS_REPORT | LVS_OWNERDATA | LVS_SINGLESEL | LVS_SHAREIMAGELISTS, WS_EX_CLIENTEDGE);\n\tm_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP);\n\t\n\tauto cm = GetColumnManager(m_List);\n\n\tstruct {\n\t\tPCWSTR text;\n\t\tColumnType type;\n\t\tint width = 100;\n\t\tint format = LVCFMT_LEFT;\n\t\tColumnFlags flags = ColumnFlags::Visible;\n\t} columns[] = {\n//\t\t{ L\"Type\", ColumnType::Type, 70 },\n\t\t{ L\"Time\", ColumnType::Time, 120, LVCFMT_LEFT },\n\t\t{ L\"Window\", ColumnType::Window, 100, LVCFMT_RIGHT },\n\t\t{ L\"Message\", ColumnType::Message, 140, LVCFMT_LEFT },\n\t\t{ L\"WPARAM\", ColumnType::wParam, 100, LVCFMT_RIGHT },\n\t\t{ L\"LPARAM\", ColumnType::lParam, 100, LVCFMT_RIGHT },\n\t\t{ L\"Thread\", ColumnType::Thread, 100, LVCFMT_RIGHT },\n\t\t{ L\"Decoded Message\", ColumnType::DecodedMessage, 250 },\n\t\t{ L\"Process\", ColumnType::Process, 100, LVCFMT_RIGHT },\n\t\t{ L\"Point\", ColumnType::Point, 100, LVCFMT_RIGHT },\n\t};\n\n\tfor (auto& col : columns) {\n\t\tcm->AddColumn(col.text, col.format, col.width, col.type, col.flags);\n\t}\n\n\tcm->UpdateColumns();\n\n\tSetTimer(1, 1200);\n\n\treturn 0;\n}\n\nLRESULT CMessagesView::OnTimer(UINT, WPARAM id, LPARAM, BOOL&) {\n\tif (id == 1) {\n\t\t{\n\t\t\tstd::lock_guard locker(m_TempMessagesLock);\n\t\t\tif (m_TempMessages.empty())\n\t\t\t\treturn 0;\n\t\t\tm_Messages.insert(m_Messages.end(), m_TempMessages.begin(), m_TempMessages.end());\n\t\t\tm_TempMessages.clear();\n\t\t}\n\t\tUpdateList();\n\t}\n\treturn 0;\n}\n\nLRESULT CMessagesView::OnDestroy(UINT, WPARAM, LPARAM, BOOL&) {\n\tif (m_hThread) {\n\t\t::PostThreadMessage(::GetThreadId(m_hThread), WM_QUIT, 0, 0);\n\t\t::CloseHandle(m_hThread);\n\t\tHookHelper::RemoveHook(m_CaptureTid);\n\t}\n\tif (m_hReadyEvent)\n\t\t::CloseHandle(m_hReadyEvent);\n\n\treturn LRESULT();\n}\n\nLRESULT CHookCallbackWnd::OnHookCallback(UINT msg, WPARAM wp, LPARAM lp, BOOL&) {\n\tauto cds = reinterpret_cast<COPYDATASTRUCT*>(lp);\n\tauto header = reinterpret_cast<HookDataHeader*>(cds->lpData);\n\tm_pView->HookCallbackMsg(header->HookType, header);\n\treturn TRUE;\n}\n"
  },
  {
    "path": "WinSpy/MessagesView.h",
    "content": "#pragma once\n\n#include \"ViewBase.h\"\n#include \"VirtualListView.h\"\n#include \"hooks.h\"\n\nstruct CMessagesView;\n\nstruct CHookCallbackWnd : CWindowImpl<CHookCallbackWnd> {\n\tCHookCallbackWnd(CMessagesView* pView) : m_pView(pView) {}\n\n\tBEGIN_MSG_MAP(CHookCallbackWnd)\n\t\tMESSAGE_HANDLER(WM_COPYDATA, OnHookCallback)\n\tEND_MSG_MAP()\n\n\tLRESULT OnHookCallback(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\nprivate:\n\tCMessagesView* m_pView;\n};\n\nstruct CMessagesView : CViewBase<CMessagesView>, CVirtualListView<CMessagesView> {\n\tCMessagesView(IMainFrame* frame) : CViewBase(frame), m_CallbackWnd(this) {}\n\n\tbool CaptureWindow(HWND hWnd);\n\tbool CaptureThread(DWORD tid);\n\tbool CaptureProcess(DWORD tid);\n\n\tvoid HookCallbackMsg(DWORD hookType, HookDataHeader* header);\n\n\tvoid OnFinalMessage(HWND) override;\n\n\tCString GetColumnText(HWND, int row, int col) const;\n\nprotected:\n\tBEGIN_MSG_MAP(CMessagesView)\n\t\tMESSAGE_HANDLER(WM_TIMER, OnTimer)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tCHAIN_MSG_MAP(CVirtualListView<CMessagesView>)\n\t\tCHAIN_MSG_MAP(CViewBase<CMessagesView>)\n\tEND_MSG_MAP()\n\nprivate:\n\tenum class ColumnType {\n\t\tType,\n\t\tWindow,\n\t\tThread,\n\t\tProcess,\n\t\tMessage,\n\t\tDecodedMessage,\n\t\twParam,\n\t\tlParam,\n\t\tTime,\n\t\tPoint\n\t};\n\n\tenum class CaptureOptions {\n\t\tWindow,\n\t\tThread,\n\t\tProcess\n\t};\n\n\tenum class MessageInfoFlags {\n\t\tNone = 0,\n\t\tResult = 1,\n\t};\n\n\tstruct MessageInfo : MSG {\n\t\tMessageInfoFlags Flags;\t\n\t\tDWORD ThreadId;\n\t\tDWORD ProcessId;\n\t};\n\n\tvoid UpdateUI();\n\tvoid UpdateList();\n\tDWORD ProcessHook();\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\n\tCListViewCtrl m_List;\n\tstd::vector<MessageInfo> m_Messages;\n\tstd::vector<MessageInfo> m_TempMessages;\n\tstd::mutex m_TempMessagesLock;\n\tCaptureOptions m_CaptureOptions;\n\tDWORD m_CaptureTid;\n\tHWND m_CaptureHwnd;\n\tHANDLE m_hThread{ nullptr };\n\tCHookCallbackWnd m_CallbackWnd;\n\tHANDLE m_hReadyEvent{ nullptr };\n};\n"
  },
  {
    "path": "WinSpy/ProcessHelper.cpp",
    "content": "#include \"pch.h\"\n#include \"ProcessHelper.h\"\n#include \"WindowHelper.h\"\n#include <TlHelp32.h>\n#include <unordered_set>\n\nCString ProcessHelper::GetProcessImageName(DWORD pid, bool fullPath) {\n\tif (_names.empty())\n\t\tEnumProcesses();\n\n\tauto hProcess = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);\n\tCString result;\n\tif (hProcess) {\n\t\tWCHAR name[MAX_PATH];\n\t\tDWORD size = _countof(name);\n\t\tif (::QueryFullProcessImageName(hProcess, 0, name, &size)) {\n\t\t\tresult = fullPath ? name : ::wcsrchr(name, L'\\\\') + 1;\n\t\t}\n\t\t::CloseHandle(hProcess);\n\t}\n\telse if (auto it = _names.find(pid); it != _names.end())\n\t\treturn it->second;\n\n\treturn result;\n}\n\nProcessesInfo ProcessHelper::EnumProcessesAndThreads(EnumProcessesOptions options) {\n\tProcessesInfo info;\n\tauto& processes = info.Processes;\n\tprocesses.reserve(512);\n\n\tauto hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);\n\tif (hSnapshot == INVALID_HANDLE_VALUE)\n\t\treturn info;\n\n\tPROCESSENTRY32 pe;\n\tpe.dwSize = sizeof(pe);\n\n\tstd::unordered_map<DWORD, int> processMap;\n\tprocessMap.reserve(512);\n\n\t::Process32First(hSnapshot, &pe);\n\n\twhile (::Process32Next(hSnapshot, &pe)) {\n\t\tProcessInfo pi;\n\t\tpi.ProcessId = pe.th32ProcessID;\n\t\tpi.Threads.reserve(pe.cntThreads);\n\t\tpi.ProcessName = pe.szExeFile;\n\t\tauto hProcess = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pi.ProcessId);\n\t\tif (hProcess) {\n\t\t\tDWORD size = MAX_PATH;\n\t\t\t::QueryFullProcessImageName(hProcess, 0, pi.FullPath.GetBufferSetLength(size), &size);\n\t\t\t::CloseHandle(hProcess);\n\t\t}\n\t\tprocesses.push_back(pi);\n\t\tprocessMap.insert({ pi.ProcessId, (int)processes.size() - 1 });\n\t}\n\n\tstd::unordered_set<DWORD> msgOnly;\n\tif ((options & EnumProcessesOptions::IncludeMessageOnly) == EnumProcessesOptions::IncludeMessageOnly) {\n\t\tHWND hWnd = nullptr;\n\t\tfor (;;) {\n\t\t\thWnd = ::FindWindowEx(HWND_MESSAGE, hWnd, nullptr, nullptr);\n\t\t\tif (!hWnd)\n\t\t\t\tbreak;\n\t\t\tauto tid = ::GetWindowThreadProcessId(hWnd, nullptr);\n\t\t\tmsgOnly.insert(tid);\n\t\t\tif (auto it = info.MessageOnly.find(tid); it != info.MessageOnly.end()) {\n\t\t\t\tit->second.push_back(hWnd);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tinfo.MessageOnly.insert({ tid, { hWnd } });\n\t\t\t}\n\t\t}\n\t}\n\tTHREADENTRY32 te;\n\tte.dwSize = sizeof(te);\n\n\t::Thread32First(hSnapshot, &te);\n\n\tdo {\n\t\t//\n\t\t// skip idle process\n\t\t//\n\t\tif (te.th32OwnerProcessID == 0)\n\t\t\tcontinue;\n\n\t\tauto& pi = processes[processMap[te.th32OwnerProcessID]];\n\t\tif ((options & EnumProcessesOptions::UIThreadsOnly) == EnumProcessesOptions::UIThreadsOnly) {\n\t\t\tif (!WindowHelper::ThreadHasWindows(te.th32ThreadID) && !msgOnly.contains(te.th32ThreadID))\n\t\t\t\tcontinue;\n\t\t}\n\t\tpi.Threads.push_back(te.th32ThreadID);\n\t} while (::Thread32Next(hSnapshot, &te));\n\n\tif ((options & EnumProcessesOptions::SkipProcessesWithNoUI) == EnumProcessesOptions::SkipProcessesWithNoUI) {\n\t\tfor (int i = 0; i < (int)processes.size(); i++) {\n\t\t\tif (processes[i].Threads.empty()) {\n\t\t\t\tprocesses.erase(processes.begin() + i);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn info;\n}\n\nvoid ProcessHelper::ShowProcessProperties(ProcessInfo const& pi) {\n}\n\nvoid ProcessHelper::EnumProcesses() {\n\tauto hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\n\tATLASSERT(hSnapshot != INVALID_HANDLE_VALUE);\n\tif (hSnapshot == INVALID_HANDLE_VALUE) {\n\t\t_names.insert({ 0, L\"(Idle)\" });\n\t\treturn;\n\t}\n\n\tPROCESSENTRY32 pe;\n\tpe.dwSize = sizeof(pe);\n\t::Process32First(hSnapshot, &pe);\n\t_names.reserve(512);\n\n\twhile (::Process32Next(hSnapshot, &pe)) {\n\t\tauto hProcess = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID);\n\t\tif (!hProcess) {\n\t\t\t_names.insert({ pe.th32ProcessID, pe.szExeFile });\n\t\t}\n\t\telse {\n\t\t\t::CloseHandle(hProcess);\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "WinSpy/ProcessHelper.h",
    "content": "#pragma once\n\nstruct ProcessInfo {\n\tDWORD ProcessId;\n\tstd::vector<DWORD> Threads;\n\tCString ProcessName;\n\tCString FullPath;\n};\n\nenum class EnumProcessesOptions {\n\tNone = 0,\n\tUIThreadsOnly = 1,\n\tSkipProcessesWithNoUI = 2,\n\tIncludeMessageOnly = 4,\n};\nDEFINE_ENUM_FLAG_OPERATORS(EnumProcessesOptions);\n\nstruct ProcessesInfo {\n\tstd::vector<ProcessInfo> Processes;\n\tstd::unordered_map<DWORD, std::vector<HWND>> MessageOnly;\n};\n\nstruct ProcessHelper {\n\tstatic CString GetProcessImageName(DWORD pid, bool fullPath = false);\n\tstatic ProcessesInfo EnumProcessesAndThreads(EnumProcessesOptions options);\n\tstatic void ShowProcessProperties(ProcessInfo const& pi);\n\tstatic void EnumProcesses();\n\nprivate:\n\tinline static std::unordered_map<DWORD, CString> _names;\n};\n\n"
  },
  {
    "path": "WinSpy/ProcessesView.cpp",
    "content": "#include \"pch.h\"\n#include \"resource.h\"\n#include \"ProcessesView.h\"\n#include \"ImageIconCache.h\"\n\nLRESULT CProcessesView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tm_Splitter.SetSplitterExtendedStyle(SPLIT_FLATBAR | SPLIT_PROPORTIONAL);\n\tm_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);\n\n\tm_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |\n\t\tTVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS, 0, IDC_TREE);\n\tm_WindowsView.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);\n\tm_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER);\n\n\tm_Tree.SetImageList(WindowHelper::GetImageList(), TVSIL_NORMAL);\n\n\tm_Splitter.SetSplitterPanes(m_Tree, m_WindowsView);\n\tUpdateLayout();\n\tm_Splitter.SetSplitterPosPct(35);\n\n\tInitTree();\n\n\treturn 0;\n}\n\nvoid CProcessesView::OnActivate(bool active) {\n\tif (active) {\n\t\tUpdateUI();\n\t}\n}\n\n\nLRESULT CProcessesView::OnTimer(UINT /*uMsg*/, WPARAM id, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tif (id == 3) {\n\t\tKillTimer(3);\n\t\tChangeSelection(m_Tree.GetSelectedItem());\n\t}\n\treturn 0;\n}\n\nvoid CProcessesView::InitTree() {\n\tm_Tree.LockWindowUpdate();\n\tm_Tree.DeleteAllItems();\n\tm_Processes.clear();\n\tm_WindowMap.clear();\n\tm_Threads.clear();\n\tm_TotalWindows = m_TotalVisibleWindows = m_TopLevelWindows = 0;\n\n\tCString text;\n\tauto info = ProcessHelper::EnumProcessesAndThreads(\n\t\tEnumProcessesOptions::UIThreadsOnly | EnumProcessesOptions::SkipProcessesWithNoUI | EnumProcessesOptions::IncludeMessageOnly);\n\tfor (auto& pi : info.Processes) {\n\t\tauto icon = ImageIconCache::Get().GetIcon(pi.FullPath);\n\t\ttext.Format(L\"%s (%u)\", (PCWSTR)pi.ProcessName, pi.ProcessId);\n\t\tauto node = m_Tree.InsertItem(text, icon, icon, TVI_ROOT, TVI_SORT);\n\t\tnode.SetData((DWORD_PTR)ItemType::Process);\n\t\tm_Processes.insert({ node, pi });\n\n\t\tfor (auto tid : pi.Threads) {\n\t\t\ttext.Format(L\"Thread %u (0x%X)\", tid, tid);\n\t\t\tauto tnode = m_Tree.InsertItem(text, icon, icon, node, TVI_LAST);\n\t\t\tif (!WindowHelper::ThreadHasWindows(tid))\n\t\t\t\ttnode.SetState(TVIS_CUT, TVIS_CUT);\n\t\t\ttnode.SetData((DWORD_PTR)ItemType::Thread);\n\t\t\tm_Threads.insert({ tnode, tid });\n\t\t\tstruct LocalData {\n\t\t\t\tCProcessesView* pThis;\n\t\t\t\tHTREEITEM hParent;\n\t\t\t};\n\t\t\tLocalData data = { this, tnode };\n\t\t\t::EnumThreadWindows(tid, [](auto hWnd, auto param) {\n\t\t\t\tauto data = (LocalData*)param;\n\t\t\t\tdata->pThis->AddNode(hWnd, data->hParent);\n\t\t\t\treturn TRUE;\n\t\t\t\t}, reinterpret_cast<LPARAM>(&data));\n\n\t\t\t//\n\t\t\t// add message-only windows\n\t\t\t//\n\t\t\tif (auto it = info.MessageOnly.find(tid); it != info.MessageOnly.end()) {\n\t\t\t\tfor (auto hWnd : it->second) {\n\t\t\t\t\tAddNode(hWnd, tnode);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tm_Tree.LockWindowUpdate(FALSE);\n}\n\nCTreeItem CProcessesView::AddNode(HWND hWnd, HTREEITEM hParent) {\n\tCString text, name;\n\tCWindow win(hWnd);\n\tm_TotalWindows++;\n\tif (win.IsWindowVisible())\n\t\tm_TotalVisibleWindows++;\n\n\tm_TopLevelWindows++;\n\n\tif (!m_ShowHiddenWindows && !win.IsWindowVisible())\n\t\treturn nullptr;\n\twin.GetWindowText(name);\n\tif (!m_ShowNoTitleWindows && name.IsEmpty())\n\t\treturn nullptr;\n\n\tif (name.GetLength() > 64)\n\t\tname = name.Left(64) + L\"...\";\n\tif (!name.IsEmpty())\n\t\tname = L\"[\" + name + L\"]\";\n\tWCHAR className[64] = { 0 };\n\t::GetClassName(hWnd, className, _countof(className));\n\ttext.Format(L\"0x%zX (%s) %s\", (DWORD_PTR)hWnd, className, (PCWSTR)name);\n\n\tHICON hIcon{ nullptr };\n\tint image = 0;\n\tif ((win.GetStyle() & WS_CHILD) == 0) {\n\t\tauto& icons = WindowHelper::GetIconMap();\n\t\tif (auto it = icons.find(hWnd); it == icons.end()) {\n\t\t\thIcon = WindowHelper::GetWindowOrProcessIcon(hWnd);\n\t\t\tif (hIcon) {\n\t\t\t\ticons.insert({ hWnd, image = WindowHelper::GetImageList().AddIcon(hIcon) });\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\timage = it->second;\n\t\t}\n\t}\n\n\tauto node = m_Tree.InsertItem(text, image, image, hParent, TVI_LAST);\n\tnode.SetData((DWORD_PTR)hWnd);\n\tm_WindowMap.insert({ hWnd, node });\n\n\tif (!win.IsWindowVisible())\n\t\tnode.SetState(TVIS_CUT, TVIS_CUT);\n\n\tif (win.GetWindow(GW_CHILD)) {\n\t\t// add a \"plus\" button\n\t\tnode.AddTail(L\"*\", 0);\n\t}\n\treturn node;\n}\n\nLRESULT CProcessesView::OnNodeExpanding(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tif (tv->action == TVE_EXPAND) {\n\t\tauto hItem = tv->itemNew.hItem;\n\n\t\tauto child = m_Tree.GetChildItem(hItem);\n\t\tif (child.GetData() == 0) {\n\t\t\tchild.Delete();\n\t\t\tAddChildWindows(hItem);\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid CProcessesView::AddChildWindows(HTREEITEM hParent) {\n\tauto hWnd = (HWND)m_Tree.GetItemData(hParent);\n\tATLASSERT(hWnd);\n\n\tm_hCurrentNode = hParent;\n\t::EnumChildWindows(hWnd, [](auto hChild, auto p) -> BOOL {\n\t\tauto pThis = (CProcessesView*)p;\n\t\treturn pThis->AddChildNode(hChild);\n\t\t}, reinterpret_cast<LPARAM>(this));\n}\n\nBOOL CProcessesView::AddChildNode(HWND hChild) {\n\tif (::GetAncestor(hChild, GA_PARENT) == (HWND)m_Tree.GetItemData(m_hCurrentNode)) {\n\t\tAddNode(hChild, m_hCurrentNode);\n\t}\n\treturn TRUE;\n}\n\nLRESULT CProcessesView::OnTreeNodeRightClick(HTREEITEM hItem, CPoint const& pt) {\n\tATLASSERT(m_Selected);\n\n\tauto data = static_cast<ItemType>(m_Selected.GetData());\n\tint index = 0;\n\tif (data == ItemType::Thread)\n\t\tindex = 3;\n\telse if (data == ItemType::Process)\n\t\tindex = 2;\n\n\tCMenu menu;\n\tmenu.LoadMenu(IDR_CONTEXT);\n\treturn GetFrame()->ShowPopupMenu(menu.GetSubMenu(index), pt);\n}\n\nLRESULT CProcessesView::OnWindowShow(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tm_SelectedHwnd.ShowWindow(SW_SHOW);\n\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowHide(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tm_SelectedHwnd.ShowWindow(SW_HIDE);\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowMinimize(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tm_SelectedHwnd.ShowWindow(SW_MINIMIZE);\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowMaximize(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tm_SelectedHwnd.ShowWindow(SW_MAXIMIZE);\n\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowRestore(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tm_SelectedHwnd.ShowWindow(SW_RESTORE);\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowFlash(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tWindowHelper::Flash((HWND)m_Selected.GetData());\n\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowBringToFront(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_Selected);\n\tm_SelectedHwnd.BringWindowToTop();\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnNodeSelected(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tif (tv->action == TVC_BYKEYBOARD) {\n\t\t// short delay before update in case the user moves quickly through the tree\n\t\tSetTimer(3, 250, nullptr);\n\t}\n\telse {\n\t\tChangeSelection(tv->itemNew.hItem);\n\t}\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnTreeNodeDoubleClick(HTREEITEM hItem, CPoint const& pt) {\n\tauto data = m_Tree.GetItemData(hItem);\n\tswitch (static_cast<ItemType>(data)) {\n\t\tcase ItemType::Process:\n\t\t\tProcessHelper::ShowProcessProperties(m_Processes[hItem]);\n\t\t\tbreak;\n\n\t\tcase ItemType::Thread:\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tauto hWnd = reinterpret_cast<HWND>(data);\n\t\t\tWindowHelper::ShowWindowProperties(hWnd);\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnWindowProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tATLASSERT(m_SelectedHwnd);\n\tWindowHelper::ShowWindowProperties(m_SelectedHwnd);\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnProcessProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tauto hItem = m_Tree.GetSelectedItem();\n\tProcessHelper::ShowProcessProperties(m_Processes[hItem]);\n\treturn 0;\n}\n\nvoid CProcessesView::ChangeSelection(HTREEITEM hItem) {\n\tm_Selected = hItem;\n\tm_Selected.m_pTreeView = &m_Tree;\n\tauto data = static_cast<ItemType>(m_Selected.GetData());\n\tswitch (data) {\n\t\tcase ItemType::Process:\n\t\t\tm_WindowsView.UpdateListByProcess(m_Processes[m_Selected]);\n\t\t\tbreak;\n\n\t\tcase ItemType::Thread:\n\t\t\tm_WindowsView.UpdateListByThread(m_Threads[m_Selected]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tauto hWnd = (HWND)m_Selected.GetData();\n\t\t\tm_SelectedHwnd = hWnd;\n\t\t\tif (!::IsWindow(hWnd))\t// window is probably destroyed\n\t\t\t\tm_Selected.Delete();\n\t\t\telse {\n\t\t\t\tm_WindowsView.UpdateList(hWnd);\n\t\t\t}\n\t\t\tbreak;\n\t}\n}\n\nLRESULT CProcessesView::OnToggleHiddenWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowHiddenWindows = !m_ShowHiddenWindows;\n\tUpdateUI();\n\tInitTree();\n\treturn 0;\n}\n\nLRESULT CProcessesView::OnToggleEmptyTitleWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowNoTitleWindows = !m_ShowNoTitleWindows;\n\tUpdateUI();\n\tInitTree();\n\treturn 0;\n}\n\nvoid CProcessesView::UpdateUI() {\n\tauto& ui = GetFrame()->GetUIUpdate();\n\tif (::GetFocus() == m_Tree) {\n\t\tui.UISetCheck(ID_VIEW_HIDDENWINDOWS, m_ShowHiddenWindows);\n\t\tui.UISetCheck(ID_VIEW_EMPTYTITLEWINDOWS, m_ShowNoTitleWindows);\n\t\tui.UIEnable(ID_WINDOW_PROPERTIES, m_SelectedHwnd != nullptr);\n\t}\n\telse {\n\t\tm_WindowsView.UpdateUI(ui);\n\t}\n}\n"
  },
  {
    "path": "WinSpy/ProcessesView.h",
    "content": "#pragma once\n\n#include \"ViewBase.h\"\n#include \"WindowsListView.h\"\n#include \"TreeViewManager.h\"\n#include \"ProcessHelper.h\"\n\nclass CProcessesView : \n\tpublic CViewBase<CProcessesView>,\n\tpublic CTreeViewManager<CProcessesView> {\npublic:\n\tCProcessesView(IMainFrame* frame) : CViewBase(frame), m_WindowsView(frame) {}\n\n\tvoid OnActivate(bool active);\n\nprotected:\n\tenum { IDC_TREE = 123 };\n\n\tBEGIN_MSG_MAP(CProcessesView)\n\t\tMESSAGE_HANDLER(WM_TIMER, OnTimer)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tNOTIFY_CODE_HANDLER(TVN_ITEMEXPANDING, OnNodeExpanding)\n\t\t//NOTIFY_CODE_HANDLER(TVN_DELETEITEM, OnNodeDeleted)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_HIDDENWINDOWS, OnToggleHiddenWindows)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_EMPTYTITLEWINDOWS, OnToggleEmptyTitleWindows)\n\t\tNOTIFY_CODE_HANDLER(TVN_SELCHANGED, OnNodeSelected)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_SHOW, OnWindowShow)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_HIDE, OnWindowHide)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_BRINGTOFRONT, OnWindowBringToFront)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MINIMIZE, OnWindowMinimize)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MAXIMIZE, OnWindowMaximize)\n\t\tCOMMAND_ID_HANDLER(ID_STATE_FLASH, OnWindowFlash)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_RESTORE, OnWindowRestore)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_PROPERTIES, OnWindowProperties)\n\t\tCOMMAND_ID_HANDLER(ID_PROCESS_PROPERTIES, OnProcessProperties)\n\t\tCHAIN_MSG_MAP(CTreeViewManager<CProcessesView>)\n\t\tCHAIN_MSG_MAP(CViewBase<CProcessesView>)\n\t\tif (m_WindowsView) {\n\t\t\tCHAIN_MSG_MAP_ALT_MEMBER(m_WindowsView, 1)\n\t\t}\n\tEND_MSG_MAP()\n\n\tLRESULT OnTreeNodeRightClick(HTREEITEM hItem, CPoint const& pt);\n\tLRESULT OnTreeNodeDoubleClick(HTREEITEM hItem, CPoint const& pt);\n\nprivate:\n\tenum class ItemType {\n\t\tProcess,\n\t\tThread,\n\t\tWindow\n\t};\n\n\tvoid InitTree();\n\tvoid UpdateUI();\n\tCTreeItem AddNode(HWND hWnd, HTREEITEM hParent);\n\tvoid AddChildWindows(HTREEITEM hParent);\n\tBOOL AddChildNode(HWND hChild);\n\tvoid ChangeSelection(HTREEITEM hItem);\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeExpanding(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeDeleted(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeSelected(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowShow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowHide(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowMinimize(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowMaximize(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowRestore(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleHiddenWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleEmptyTitleWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleChildWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowFlash(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowBringToFront(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnProcessProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\n\tCWindowsListView m_WindowsView;\n\tCSplitterWindow m_Splitter;\n\tCTreeViewCtrlEx m_Tree;\n\n\tstd::unordered_map<HTREEITEM, ProcessInfo> m_Processes;\n\tstd::unordered_map<HTREEITEM, DWORD> m_Threads;\n\tstd::unordered_map<HWND, HTREEITEM> m_WindowMap;\n\tCTreeItem m_hCurrentNode;\n\tCTreeItem m_Selected;\n\tCWindow m_SelectedHwnd;\n\tint m_TotalWindows, m_TotalVisibleWindows, m_TopLevelWindows;\n\tbool m_ShowHiddenWindows : 1 { true };\n\tbool m_ShowNoTitleWindows : 1 { true };\n\tbool m_ShowChildWindows : 1 { true };\n};\n"
  },
  {
    "path": "WinSpy/SecurityHelper.cpp",
    "content": "#include \"pch.h\"\n#include \"SecurityHelper.h\"\n\nbool SecurityHelper::IsRunningElevated() {\n\tstatic bool runningElevated = false;\n\tstatic bool runningElevatedCheck = false;\n\tif (runningElevatedCheck)\n\t\treturn runningElevated;\n\n\trunningElevatedCheck = true;\n\tHANDLE hToken;\n\tif (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))\n\t\treturn false;\n\n\tTOKEN_ELEVATION te;\n\tDWORD len;\n\tif (::GetTokenInformation(hToken, TokenElevation, &te, sizeof(te), &len)) {\n\t\trunningElevated = te.TokenIsElevated ? true : false;\n\t}\n\t::CloseHandle(hToken);\n\treturn runningElevated;\n}\n\nbool SecurityHelper::RunElevated() {\n\tWCHAR path[MAX_PATH];\n\t::GetModuleFileName(nullptr, path, _countof(path));\n\treturn (INT_PTR)::ShellExecute(nullptr, L\"runas\", path, nullptr, nullptr, SW_SHOWDEFAULT) > 31;\n}\n\nbool SecurityHelper::EnablePrivilege(PCWSTR privName, bool enable) {\n\tHANDLE hToken;\n\tif (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))\n\t\treturn false;\n\n\tbool result = false;\n\tTOKEN_PRIVILEGES tp;\n\ttp.PrivilegeCount = 1;\n\ttp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;\n\tif (::LookupPrivilegeValue(nullptr, privName,\n\t\t&tp.Privileges[0].Luid)) {\n\t\tif (::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp),\n\t\t\tnullptr, nullptr))\n\t\t\tresult = ::GetLastError() == ERROR_SUCCESS;\n\t}\n\t::CloseHandle(hToken);\n\treturn result;\n}\n\n"
  },
  {
    "path": "WinSpy/SecurityHelper.h",
    "content": "#pragma once\n\nstruct SecurityHelper abstract final {\n\tstatic bool IsRunningElevated();\n\tstatic bool RunElevated();\n\tstatic bool EnablePrivilege(PCWSTR privName, bool enable = true);\n};\n"
  },
  {
    "path": "WinSpy/TreeViewManager.h",
    "content": "#pragma once\n\ntemplate<typename T>\nclass CTreeViewManager {\nprotected:\n\tBEGIN_MSG_MAP(CTreeViewManager)\n\t\tNOTIFY_CODE_HANDLER(NM_RCLICK, OnRightClick)\n\t\tNOTIFY_CODE_HANDLER(NM_DBLCLK, OnDoubleClick)\n\t\tNOTIFY_CODE_HANDLER(TVN_SELCHANGED, OnTreeSelectionChanged)\n\tEND_MSG_MAP()\n\n\tLRESULT OnTreeSelectionChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) {\n\t\treturn 0;\n\t}\n\n\tLRESULT OnRightClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) {\n\t\tCTreeViewCtrl tv(pnmh->hwndFrom);\n\t\tCPoint pt;\n\t\t::GetCursorPos(&pt);\n\t\tCPoint pt2(pt);\n\t\ttv.ScreenToClient(&pt2);\n\t\tauto hItem = tv.HitTest(pt2, nullptr);\n\t\tif (!hItem)\n\t\t\treturn 0;\n\n\t\ttv.SelectItem(hItem);\n\t\tauto pT = static_cast<T*>(this);\n\t\treturn pT->OnTreeNodeRightClick(hItem, pt);\n\t}\n\n\tLRESULT OnDoubleClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) {\n\t\tCTreeViewCtrl tv(pnmh->hwndFrom);\n\t\tCPoint pt;\n\t\t::GetCursorPos(&pt);\n\t\tCPoint pt2(pt);\n\t\ttv.ScreenToClient(&pt2);\n\t\tauto hItem = tv.HitTest(pt2, nullptr);\n\t\tif (!hItem)\n\t\t\treturn 0;\n\n\t\tauto pT = static_cast<T*>(this);\n\t\treturn pT->OnTreeNodeDoubleClick(hItem, pt);\n\t}\n\nprivate:\n\t//\n\t// overridables\n\t//\n\tLRESULT OnTreeNodeRightClick(HTREEITEM hItem, CPoint const& pt) {\n\t\treturn 0;\n\t}\n\tLRESULT OnTreeNodeDoubleClick(HTREEITEM hItem, CPoint const& pt) {\n\t\treturn 0;\n\t}\n};\n\n"
  },
  {
    "path": "WinSpy/ViewBase.h",
    "content": "#pragma once\n\n#include \"Interfaces.h\"\n\ntemplate<typename T, typename TBase = CFrameWindowImpl<T, CWindow, CControlWinTraits>>\nclass CViewBase abstract :\n\tpublic TBase,\n\tpublic CAutoUpdateUI<T>,\n\tpublic CIdleHandler {\npublic:\n\tCViewBase(IMainFrame* frame) : m_pFrame(frame) {}\n\nprotected:\n\tBEGIN_MSG_MAP(CViewBase)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_HANDLER(TBVN_PAGEACTIVATED, OnTabActivated)\n\t\tCHAIN_MSG_MAP(TBase)\n\tEND_MSG_MAP()\n\n\tIMainFrame* GetFrame() {\n\t\treturn m_pFrame;\n\t}\n\n\tvoid OnFinalMessage(HWND) override {\n\t\tdelete this;\n\t}\n\n\tBOOL OnIdle() override {\n\t\tCAutoUpdateUI<T>::UIUpdateToolBar();\n\t\treturn FALSE;\n\t}\n\n\tLRESULT OnTabActivated(UINT /*uMsg*/, WPARAM wParam, LPARAM, BOOL& bHandled) {\n\t\tauto pT = static_cast<T*>(this);\n\t\tpT->OnActivate(wParam ? true : false);\n\t\treturn 0;\n\t}\n\n\tvoid OnActivate(bool activate) {}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) {\n\t\tauto pT = static_cast<T*>(this);\n\n\t\tbHandled = FALSE;\n\t\tif (pT->m_hWndToolBar)\n\t\t\t_Module.GetMessageLoop()->RemoveIdleHandler(this);\n\t\treturn 0;\n\t}\n\n\tHWND CreateAndInitToolBar(const ToolBarButtonInfo* buttons, int count) {\n\t\tauto pT = static_cast<T*>(this);\n\n\t\tCToolBarCtrl tb;\n\t\tauto hWndToolBar = tb.Create(pT->m_hWnd, pT->rcDefault, nullptr, ATL_SIMPLE_TOOLBAR_PANE_STYLE | TBSTYLE_LIST, 0, ATL_IDW_TOOLBAR);\n\t\ttb.SetExtendedStyle(TBSTYLE_EX_MIXEDBUTTONS);\n\n\t\tCImageList tbImages;\n\t\ttbImages.Create(24, 24, ILC_COLOR32 | ILC_COLOR | ILC_MASK, 4, 4);\n\t\ttb.SetImageList(tbImages);\n\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tauto& b = buttons[i];\n\t\t\tif (b.id == 0)\n\t\t\t\ttb.AddSeparator(0);\n\t\t\telse {\n\t\t\t\tint image = b.image == 0 ? I_IMAGENONE : tbImages.AddIcon(AtlLoadIconImage(b.image, 0, 24, 24));\n\t\t\t\ttb.AddButton(b.id, b.style | (b.text ? BTNS_SHOWTEXT : 0), TBSTATE_ENABLED, image, b.text, 0);\n\t\t\t}\n\t\t}\n\n\t\tpT->CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);\n\t\tpT->AddSimpleReBarBand(tb);\n\n\t\tUIAddToolBar(hWndToolBar);\n\t\t_Module.GetMessageLoop()->AddIdleHandler(this);\n\n\t\treturn hWndToolBar;\n\t}\n\n\tIMainFrame* m_pFrame;\n};\n"
  },
  {
    "path": "WinSpy/WinSpy.cpp",
    "content": "// WinSpy.cpp : main source file for WinSpy.exe\n//\n\n#include \"pch.h\"\n#include \"resource.h\"\n#include \"MainFrm.h\"\n#include <ThemeHelper.h>\n\nCAppModule _Module;\n\nint Run(LPCTSTR /*lpstrCmdLine*/ = nullptr, int nCmdShow = SW_SHOWDEFAULT) {\n\tCMessageLoop theLoop;\n\t_Module.AddMessageLoop(&theLoop);\n\n\tCMainFrame wndMain;\n\n\tif (wndMain.CreateEx() == nullptr) {\n\t\tATLTRACE(_T(\"Main window creation failed!\\n\"));\n\t\treturn 0;\n\t}\n\n\twndMain.ShowWindow(nCmdShow);\n\n\tint nRet = theLoop.Run();\n\n\t_Module.RemoveMessageLoop();\n\treturn nRet;\n}\n\nint WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) {\n\tHRESULT hRes = ::CoInitialize(nullptr);\n\tATLASSERT(SUCCEEDED(hRes));\n\n\tAtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES);\n\n\thRes = _Module.Init(nullptr, hInstance);\n\tATLASSERT(SUCCEEDED(hRes));\n\tThemeHelper::Init();\n\n\tint nRet = Run(lpstrCmdLine, nCmdShow);\n\n\t_Module.Term();\n\t::CoUninitialize();\n\n\treturn nRet;\n}\n"
  },
  {
    "path": "WinSpy/WinSpy.h",
    "content": "// WinSpy.h\n"
  },
  {
    "path": "WinSpy/WinSpy.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"atlres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n#pragma code_page(1252)\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE \nBEGIN\n    \"#include \"\"atlres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE \nBEGIN\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Menu\n//\n\nIDR_MAINFRAME MENU\nBEGIN\n    POPUP \"&File\"\n    BEGIN\n        MENUITEM \"&Run As Administrator...\",    ID_FILE_RUNASADMINISTRATOR\n        MENUITEM SEPARATOR\n        MENUITEM \"E&xit\",                       ID_APP_EXIT\n    END\n    POPUP \"&Edit\"\n    BEGIN\n        MENUITEM \"Cu&t\\tCtrl+X\",                ID_EDIT_CUT\n        MENUITEM \"&Copy\\tCtrl+C\",               ID_EDIT_COPY\n        MENUITEM \"&Paste\\tCtrl+V\",              ID_EDIT_PASTE\n    END\n    POPUP \"&View\"\n    BEGIN\n        MENUITEM \"&Refresh\",                    ID_VIEW_REFRESH\n        MENUITEM SEPARATOR\n        MENUITEM \"&Toolbar\",                    ID_VIEW_TOOLBAR\n        MENUITEM \"&Status Bar\",                 ID_VIEW_STATUS_BAR\n        MENUITEM SEPARATOR\n        MENUITEM \"&Windows Tree\",               ID_VIEW_ALLWINDOWS\n        MENUITEM \"&Processes Tree\",             ID_VIEW_ALLPROCESSES\n        MENUITEM \"Windows &List\",               ID_VIEW_WINDOWSLIST\n        MENUITEM \"&Automation Tree\",            ID_VIEW_AUTOMATIONTREE\n        MENUITEM SEPARATOR\n        MENUITEM \"&Hidden Windows\",             ID_VIEW_HIDDENWINDOWS\n        MENUITEM \"EmptyTitle Windows\",          ID_VIEW_EMPTYTITLEWINDOWS\n    END\n    POPUP \"&Window\"\n    BEGIN\n        MENUITEM \"&Find...\\tCtrl+W\",            ID_WINDOW_FIND\n        MENUITEM \"&Messages...\",                ID_WINDOW_MESSAGES\n        MENUITEM SEPARATOR\n        MENUITEM \"Locate in &Tree\",             ID_WINDOW_LOCATEINTREE\n        POPUP \"&Action\"\n        BEGIN\n            MENUITEM \"&Show\",                       ID_WINDOW_SHOW\n            MENUITEM \"&Hide\",                       ID_WINDOW_HIDE\n            MENUITEM \"&Highlight\",                  ID_WINDOW_HIGHLIGHT\n            MENUITEM \"&Minimize\",                   ID_WINDOW_MINIMIZE\n            MENUITEM \"Ma&ximize\",                   ID_WINDOW_MAXIMIZE\n            MENUITEM \"&Restore\",                    ID_WINDOW_RESTORE\n            MENUITEM \"&Bring To Front\",             ID_WINDOW_BRINGTOFRONT\n            MENUITEM \"&Close\",                      ID_STATE_CLOSE\n            MENUITEM \"&Flash\",                      ID_STATE_FLASH\n        END\n        MENUITEM SEPARATOR\n        MENUITEM \"&Properties...\",              ID_WINDOW_PROPERTIES\n    END\n    POPUP \"&Options\"\n    BEGIN\n        MENUITEM \"&Always On Top\",              ID_OPTIONS_ALWAYSONTOP\n        MENUITEM \"&Fonts...\",                   ID_OPTIONS_FONTS\n    END\n    POPUP \"&Tab\"\n    BEGIN\n        MENUITEM \"&Close\\tCtrl+F4\",             ID_WINDOW_CLOSE\n        MENUITEM \"Close &All\",                  ID_WINDOW_CLOSE_ALL\n    END\n    POPUP \"&Help\"\n    BEGIN\n        MENUITEM \"&About WinSpy...\",            ID_APP_ABOUT\n    END\nEND\n\nIDR_CONTEXT MENU\nBEGIN\n    POPUP \"tree\"\n    BEGIN\n        MENUITEM \"&Show\",                       ID_WINDOW_SHOW\n        MENUITEM \"&Hide\",                       ID_WINDOW_HIDE\n        MENUITEM \"&Highlight\",                  ID_WINDOW_HIGHLIGHT\n        MENUITEM \"&Minimize\",                   ID_WINDOW_MINIMIZE\n        MENUITEM \"Ma&ximize\",                   ID_WINDOW_MAXIMIZE\n        MENUITEM \"&Restore\",                    ID_WINDOW_RESTORE\n        MENUITEM \"&Bring To Front\",             ID_WINDOW_BRINGTOFRONT\n        MENUITEM \"Send to &Back\",               ID_TREE_SENDTOBACK\n        MENUITEM \"&Close\",                      ID_STATE_CLOSE\n        MENUITEM \"&Flash\",                      ID_STATE_FLASH\n        MENUITEM \"&Messages...\",                ID_WINDOW_MESSAGES\n        MENUITEM SEPARATOR\n        MENUITEM \"&Properties...\",              ID_WINDOW_PROPERTIES\n    END\n    POPUP \"list\"\n    BEGIN\n        POPUP \"&State\"\n        BEGIN\n            MENUITEM \"&Show\",                       ID_WINDOW_SHOW\n            MENUITEM \"&Hide\",                       ID_WINDOW_HIDE\n            MENUITEM \"&Highlight\",                  ID_WINDOW_HIGHLIGHT\n            MENUITEM \"&Minimize\",                   ID_WINDOW_MINIMIZE\n            MENUITEM \"Ma&ximize\",                   ID_WINDOW_MAXIMIZE\n            MENUITEM \"&Restore\",                    ID_WINDOW_RESTORE\n            MENUITEM \"&Bring To Front\",             ID_WINDOW_BRINGTOFRONT\n            MENUITEM \"&Close\",                      ID_STATE_CLOSE\n            MENUITEM \"&Flash\",                      ID_STATE_FLASH\n        END\n        MENUITEM SEPARATOR\n        MENUITEM \"&Properties...\",              ID_WINDOW_PROPERTIES\n        MENUITEM SEPARATOR\n        MENUITEM \"Locate in &Tree\",             ID_WINDOW_LOCATEINTREE\n    END\n    POPUP \"process\"\n    BEGIN\n        MENUITEM \"&Terminate\",                  ID_PROCESS_TERMINATE\n        MENUITEM SEPARATOR\n        MENUITEM \"&Properties...\",              ID_PROCESS_PROPERTIES\n    END\n    POPUP \"thread\"\n    BEGIN\n        MENUITEM \"&Properties...\",              ID_THREAD_PROPERTIES\n        MENUITEM SEPARATOR\n        MENUITEM \"&Messages...\",                ID_WINDOW_MESSAGES\n    END\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDR_MAINFRAME           ICON                    \"res\\\\WinSpy.ico\"\n\nIDI_WINDOW              ICON                    \"res\\\\window.ico\"\n\nIDI_WINDOW_HIDDEN       ICON                    \"res\\\\window-hidden.ico\"\n\nIDI_WINDOW_DELETE       ICON                    \"res\\\\window_delete.ico\"\n\nIDI_WINDOW_NEW          ICON                    \"res\\\\window_new.ico\"\n\nIDI_WINDOWS             ICON                    \"res\\\\windows.ico\"\n\nIDI_REFRESH             ICON                    \"res\\\\refresh.ico\"\n\nIDI_WINDOW_CLOSE        ICON                    \"res\\\\close-window.ico\"\n\nIDI_WINDOW_MAXIMIZE     ICON                    \"res\\\\maximize.ico\"\n\nIDI_WINDOW_NOTEXT       ICON                    \"res\\\\window-notext.ico\"\n\nIDI_WINDOW_MINIMIZE     ICON                    \"res\\\\Minimize.ico\"\n\nIDI_WINDOW_SENDTOBACK   ICON                    \"res\\\\WindowSendToBack.ico\"\n\nIDI_TARGET              ICON                    \"res\\\\Target.ico\"\n\nIDI_PROCESSES           ICON                    \"res\\\\gears.ico\"\n\nIDI_WINPROP             ICON                    \"res\\\\window-properties.ico\"\n\nIDI_PROCESS_INFO        ICON                    \"res\\\\gear_information.ico\"\n\nIDI_MESSAGE             ICON                    \"res\\\\message.ico\"\n\nIDI_MESSAGES            ICON                    \"res\\\\messages.ico\"\n\nIDI_WINDOWSEARCH        ICON                    \"res\\\\WindowSearch.ico\"\n\nIDI_SENDTOFRONT         ICON                    \"res\\\\WindowSendToFront.ico\"\n\nIDI_RESTORE             ICON                    \"res\\\\restore.ico\"\n\nIDI_AUTOMATION          ICON                    \"res\\\\Automation.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Dialog\n//\n\nIDD_ABOUTBOX DIALOGEX 0, 0, 187, 85\nSTYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"About WinSpy\"\nFONT 9, \"Segoe UI\", 0, 0, 0x0\nBEGIN\n    DEFPUSHBUTTON   \"OK\",IDOK,70,64,48,14\n    CTEXT           \"WinSpy v0.3\\n\\n2020-2024 Pavel Yosifovich\",IDC_STATIC,46,14,103,32\n    ICON            IDR_MAINFRAME,IDC_STATIC,6,6,20,20\nEND\n\nIDD_FINDWINDOW DIALOGEX 0, 0, 333, 146\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"Find Window\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Handle:\",IDC_STATIC,9,9,26,8\n    EDITTEXT        IDC_HANDLE,41,7,69,14,ES_AUTOHSCROLL\n    LTEXT           \"Class:\",IDC_STATIC,9,30,20,8\n    EDITTEXT        IDC_CLASSNAME,41,27,285,14,ES_AUTOHSCROLL\n    LTEXT           \"Text:\",IDC_STATIC,16,50,18,8\n    EDITTEXT        IDC_TEXT,41,48,285,14,ES_AUTOHSCROLL\n    LTEXT           \"Drag and drop over a window\",IDC_STATIC,12,78,96,8\n    ICON            IDI_TARGET,IDC_TARGET,119,72,20,20,SS_NOTIFY | SS_CENTERIMAGE\n    PUSHBUTTON      \"Search\",IDC_SEARCH,163,75,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,174,125,50,14\n    PUSHBUTTON      \"OK\",IDOK,108,125,50,14\n    CONTROL         \"Hide main window while dragging\",IDC_HIDE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,95,123,10\n    LTEXT           \"Thread:\",IDC_STATIC,116,9,26,8\n    EDITTEXT        IDC_THREAD,145,7,40,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Process:\",IDC_STATIC,195,9,28,8\n    EDITTEXT        IDC_PROCESS,228,7,98,14,ES_AUTOHSCROLL | ES_READONLY\nEND\n\nIDD_WINPROP DIALOGEX 0, 0, 433, 243\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD | WS_CAPTION | WS_SYSMENU\nCAPTION \"General\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    LTEXT           \"Handle:\",IDC_STATIC,7,9,26,8\n    EDITTEXT        IDC_HANDLE,35,7,69,14,ES_AUTOHSCROLL\n    LTEXT           \"Class:\",IDC_STATIC,10,30,20,8\n    EDITTEXT        IDC_CLASSNAME,35,27,306,14,ES_AUTOHSCROLL\n    LTEXT           \"Text:\",IDC_STATIC,12,50,18,8\n    EDITTEXT        IDC_TEXT,35,48,388,14,ES_AUTOHSCROLL\n    LTEXT           \"Thread:\",IDC_STATIC,116,9,26,8\n    EDITTEXT        IDC_THREAD,145,7,43,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Process:\",IDC_STATIC,203,9,28,8\n    EDITTEXT        IDC_PROCESS,239,7,151,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Window Rect:\",IDC_STATIC,7,71,46,8\n    EDITTEXT        IDC_RECT,7,82,129,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Client Rect:\",IDC_STATIC,155,71,38,8\n    EDITTEXT        IDC_CLIENTRECT,153,81,129,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Style:\",IDC_STATIC,16,129,20,8\n    EDITTEXT        IDC_STYLE,42,126,61,14,ES_AUTOHSCROLL | ES_READONLY\n    LISTBOX         IDC_STYLES,7,145,138,94,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP\n    LTEXT           \"Extended Style:\",IDC_STATIC,166,129,52,8\n    EDITTEXT        IDC_STYLEEX,222,126,61,14,ES_AUTOHSCROLL | ES_READONLY\n    LISTBOX         IDC_STYLESEX,150,145,160,93,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP\n    LTEXT           \"Atom:\",IDC_STATIC,361,31,20,8\n    EDITTEXT        IDC_ATOM,385,28,42,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Restore Rect:\",IDC_STATIC,298,71,46,8\n    EDITTEXT        IDC_RESTORE_RECT,297,82,129,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Menu / ID:\",IDC_STATIC,7,105,35,8\n    EDITTEXT        IDC_MENU,45,102,69,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"User Data:\",IDC_STATIC,135,106,36,8\n    EDITTEXT        IDC_USERDATA,178,103,80,14,ES_AUTOHSCROLL | ES_READONLY\n    LTEXT           \"Class Style:\",IDC_STATIC,320,129,38,8\n    EDITTEXT        IDC_STYLECLASS,364,127,61,14,ES_AUTOHSCROLL | ES_READONLY\n    LISTBOX         IDC_CLASSSTYLE,322,146,109,93,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP\nEND\n\nIDD_PROPWINDOWS DIALOGEX 0, 0, 401, 247\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\nCAPTION \"Windows\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x0\nBEGIN\n    GROUPBOX        \"Parent Window\",IDC_STATIC,7,7,387,56\n    LTEXT           \"Handle:\",IDC_STATIC,15,23,26,8\n    LTEXT           \"Class:\",IDC_STATIC,118,22,20,8\n    EDITTEXT        IDC_CLASS,148,20,246,14,ES_AUTOHSCROLL | ES_READONLY\n    CONTROL         \"<a>SysLink1</a>\",IDC_HANDLE,\"SysLink\",LWS_RIGHT | WS_TABSTOP,45,23,60,10\n    LTEXT           \"Text:\",IDC_STATIC,15,43,18,8\n    EDITTEXT        IDC_TEXT,39,41,355,14,ES_AUTOHSCROLL | ES_READONLY\n    GROUPBOX        \"Next Window\",IDC_STATIC,7,66,387,56\n    LTEXT           \"Handle:\",IDC_STATIC,15,82,26,8\n    LTEXT           \"Class:\",IDC_STATIC,118,81,20,8\n    EDITTEXT        IDC_CLASS2,148,79,246,14,ES_AUTOHSCROLL | ES_READONLY\n    CONTROL         \"<a>SysLink1</a>\",IDC_HANDLE2,\"SysLink\",LWS_RIGHT | WS_TABSTOP,45,82,60,10\n    LTEXT           \"Text:\",IDC_STATIC,15,102,18,8\n    EDITTEXT        IDC_TEXT2,39,100,355,14,ES_AUTOHSCROLL | ES_READONLY\n    GROUPBOX        \"Previous Window\",IDC_STATIC,7,126,387,56\n    LTEXT           \"Handle:\",IDC_STATIC,15,142,26,8\n    LTEXT           \"Class:\",IDC_STATIC,118,142,20,8\n    EDITTEXT        IDC_CLASS3,148,139,246,14,ES_AUTOHSCROLL | ES_READONLY\n    CONTROL         \"<a>SysLink1</a>\",IDC_HANDLE3,\"SysLink\",LWS_RIGHT | WS_TABSTOP,45,142,60,10\n    LTEXT           \"Text:\",IDC_STATIC,15,162,18,8\n    EDITTEXT        IDC_TEXT3,39,161,355,14,ES_AUTOHSCROLL | ES_READONLY\n    GROUPBOX        \"First Child Window\",IDC_STATIC,7,184,387,56\n    LTEXT           \"Handle:\",IDC_STATIC,15,200,26,8\n    LTEXT           \"Class:\",IDC_STATIC,118,200,20,8\n    EDITTEXT        IDC_CLASS4,148,197,246,14,ES_AUTOHSCROLL | ES_READONLY\n    CONTROL         \"<a>SysLink1</a>\",IDC_HANDLE4,\"SysLink\",LWS_RIGHT | WS_TABSTOP,45,200,60,10\n    LTEXT           \"Text:\",IDC_STATIC,15,220,18,8\n    EDITTEXT        IDC_TEXT4,39,219,355,14,ES_AUTOHSCROLL | ES_READONLY\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// DESIGNINFO\n//\n\n#ifdef APSTUDIO_INVOKED\nGUIDELINES DESIGNINFO\nBEGIN\n    IDD_ABOUTBOX, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 180\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 78\n    END\n\n    IDD_FINDWINDOW, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 326\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 139\n    END\n\n    IDD_WINPROP, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 426\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 236\n    END\n\n    IDD_PROPWINDOWS, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 394\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 240\n    END\nEND\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Accelerator\n//\n\nIDR_MAINFRAME ACCELERATORS\nBEGIN\n    \"N\",            ID_FILE_NEW,            VIRTKEY, CONTROL\n    \"O\",            ID_FILE_OPEN,           VIRTKEY, CONTROL\n    \"S\",            ID_FILE_SAVE,           VIRTKEY, CONTROL\n    \"P\",            ID_FILE_PRINT,          VIRTKEY, CONTROL\n    \"Z\",            ID_EDIT_UNDO,           VIRTKEY, CONTROL\n    \"X\",            ID_EDIT_CUT,            VIRTKEY, CONTROL\n    \"C\",            ID_EDIT_COPY,           VIRTKEY, CONTROL\n    \"V\",            ID_EDIT_PASTE,          VIRTKEY, CONTROL\n    VK_BACK,        ID_EDIT_UNDO,           VIRTKEY, ALT\n    VK_DELETE,      ID_EDIT_CUT,            VIRTKEY, SHIFT\n    VK_INSERT,      ID_EDIT_COPY,           VIRTKEY, CONTROL\n    VK_INSERT,      ID_EDIT_PASTE,          VIRTKEY, SHIFT\n    VK_F6,          ID_NEXT_PANE,           VIRTKEY \n    VK_F6,          ID_PREV_PANE,           VIRTKEY, SHIFT\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION 0,3,0,0\n PRODUCTVERSION 0,3,0,0\n FILEFLAGSMASK 0x3fL\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS 0x4L\n FILETYPE 0x2L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904b0\"\n        BEGIN\n            VALUE \"CompanyName\", \"Scorpio Software\"\n            VALUE \"FileDescription\", \"WinSpy - UI Windows Properties and Messages\"\n            VALUE \"FileVersion\", \"0.3.0.0\"\n            VALUE \"InternalName\", \"WinSpy\"\n            VALUE \"LegalCopyright\", \"2021-2024 Pavel Yosifovich\"\n            VALUE \"OriginalFilename\", \"WinSpy.exe\"\n            VALUE \"ProductName\", \"WinSpy\"\n            VALUE \"ProductVersion\", \"0.3.0.0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1200\n    END\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// AFX_DIALOG_LAYOUT\n//\n\nIDD_ABOUTBOX AFX_DIALOG_LAYOUT\nBEGIN\n    0\nEND\n\nIDD_FINDWINDOW AFX_DIALOG_LAYOUT\nBEGIN\n    0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 100, 0,\n    0, 0, 0, 0,\n    0, 0, 100, 0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    50, 100, 0, 0,\n    50, 100, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 0, 0,\n    0, 0, 100, 0\nEND\n\nIDD_WINPROP AFX_DIALOG_LAYOUT\nBEGIN\n    0\nEND\n\nIDD_PROPWINDOWS AFX_DIALOG_LAYOUT\nBEGIN\n    0\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// String Table\n//\n\nSTRINGTABLE\nBEGIN\n    IDR_MAINFRAME           \"WinSpy v0.3\"\n    IDS_TITLE               \"WinSpy\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_FILE_NEW             \"Create a new document\\nNew\"\n    ID_FILE_OPEN            \"Open an existing document\\nOpen\"\n    ID_FILE_CLOSE           \"Close the active document\\nClose\"\n    ID_FILE_SAVE            \"Save the active document\\nSave\"\n    ID_FILE_SAVE_AS         \"Save the active document with a new name\\nSave As\"\n    ID_FILE_PAGE_SETUP      \"Change the printing options\\nPage Setup\"\n    ID_FILE_PRINT_SETUP     \"Change the printer and printing options\\nPrint Setup\"\n    ID_FILE_PRINT           \"Print the active document\\nPrint\"\n    ID_FILE_PRINT_PREVIEW   \"Display full pages\\nPrint Preview\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_APP_ABOUT            \"Display program information, version number and copyright\\nAbout\"\n    ID_APP_EXIT             \"Quit the application; prompts to save documents\\nExit\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_NEXT_PANE            \"Switch to the next window pane\\nNext Pane\"\n    ID_PREV_PANE            \"Switch back to the previous window pane\\nPrevious Pane\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_WINDOW_NEW           \"Open another window for the active document\\nNew Window\"\n    ID_WINDOW_ARRANGE       \"Arrange icons at the bottom of the window\\nArrange Icons\"\n    ID_WINDOW_CASCADE       \"Arrange windows so they overlap\\nCascade Windows\"\n    ID_WINDOW_TILE_HORZ     \"Arrange windows as non-overlapping tiles\\nTile Windows\"\n    ID_WINDOW_TILE_VERT     \"Arrange windows as non-overlapping tiles\\nTile Windows\"\n    ID_WINDOW_SPLIT         \"Split the active window into panes\\nSplit\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_EDIT_CLEAR           \"Erase the selection\\nErase\"\n    ID_EDIT_CLEAR_ALL       \"Erase everything\\nErase All\"\n    ID_EDIT_COPY            \"Copy the selection and put it on the Clipboard\\nCopy\"\n    ID_EDIT_CUT             \"Cut the selection and put it on the Clipboard\\nCut\"\n    ID_EDIT_FIND            \"Find the specified text\\nFind\"\n    ID_EDIT_PASTE           \"Insert Clipboard contents\\nPaste\"\n    ID_EDIT_REPEAT          \"Repeat the last action\\nRepeat\"\n    ID_EDIT_REPLACE         \"Replace specific text with different text\\nReplace\"\n    ID_EDIT_SELECT_ALL      \"Select the entire document\\nSelect All\"\n    ID_EDIT_UNDO            \"Undo the last action\\nUndo\"\n    ID_EDIT_REDO            \"Redo the previously undone action\\nRedo\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_VIEW_TOOLBAR         \"Show or hide the toolbar\\nToggle ToolBar\"\n    ID_VIEW_STATUS_BAR      \"Show or hide the status bar\\nToggle StatusBar\"\n    ID_VIEW_REFRESH         \"\\nRefresh\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ATL_IDS_SCSIZE          \"Change the window size\"\n    ATL_IDS_SCMOVE          \"Change the window position\"\n    ATL_IDS_SCMINIMIZE      \"Reduce the window to an icon\"\n    ATL_IDS_SCMAXIMIZE      \"Enlarge the window to full size\"\n    ATL_IDS_SCNEXTWINDOW    \"Switch to the next document window\"\n    ATL_IDS_SCPREVWINDOW    \"Switch to the previous document window\"\n    ATL_IDS_SCCLOSE         \"Close the active window and prompts to save the documents\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ATL_IDS_SCRESTORE       \"Restore the window to normal size\"\n    ATL_IDS_SCTASKLIST      \"Activate Task List\"\n    ATL_IDS_MDICHILD        \"Activate this window\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ATL_IDS_IDLEMESSAGE     \"Ready\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ATL_IDS_MRU_FILE        \"Open this document\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_WINDOW_CLOSE         \"\\nClose Tab\"\n    ID_WINDOW_CLOSE_ALL     \"\\nClose All Tabs\"\n    ID_VIEW_ALLWINDOWS      \"\\nWindow Tree\"\n    ID_VIEW_ALLPROCESSES    \"\\nProcesses, Threads && Windows\"\n    ID_WINDOW_SHOW          \"\\nShow Window\"\n    ID_WINDOW_HIDE          \"\\nHide Window\"\n    ID_WINDOW_HIGHLIGHT     \"\\nHighlight Window\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_WINDOW_PROPERTIES    \"\\nWindow Properties\"\n    ID_WINDOW_FIND          \"\\nFind Window\"\n    ID_VIEW_HIDDENWINDOWS   \"\\nHidden Windows\"\n    ID_VIEW_EMPTYTITLEWINDOWS \"\\nWindows with no Titles\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_WINDOW_MESSAGES      \"\\nMonitor Messages\"\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n"
  },
  {
    "path": "WinSpy/WinSpy.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSigned|Win32\">\n      <Configuration>ReleaseSigned</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSigned|x64\">\n      <Configuration>ReleaseSigned</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <ProjectGuid>{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}</ProjectGuid>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>..\\WTL;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>..\\WTL;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>..\\WTL;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>..\\WTL;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>..\\WTL;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>..\\WTL;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;STRICT;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <ExceptionHandling>false</ExceptionHandling>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <AdditionalIncludeDirectories>..\\WinSpyHook;..\\WTLHelper\\WTLHelper</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <TargetEnvironment>Win32</TargetEnvironment>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <HeaderFileName>WinSpy.h</HeaderFileName>\n      <InterfaceIdentifierFileName>WinSpy_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>WinSpy_p.c</ProxyFileName>\n      <GenerateStublessProxies>true</GenerateStublessProxies>\n      <TypeLibraryName>$(IntDir)/WinSpy.tlb</TypeLibraryName>\n      <DllDataFileName />\n    </Midl>\n    <Manifest>\n      <EnableDpiAwareness>false</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_WINDOWS;STRICT;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <ExceptionHandling>false</ExceptionHandling>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <AdditionalIncludeDirectories>..\\WinSpyHook;..\\WTLHelper\\WTLHelper</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <HeaderFileName>WinSpy.h</HeaderFileName>\n      <InterfaceIdentifierFileName>WinSpy_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>WinSpy_p.c</ProxyFileName>\n      <GenerateStublessProxies>true</GenerateStublessProxies>\n      <TypeLibraryName>$(IntDir)/WinSpy.tlb</TypeLibraryName>\n      <DllDataFileName />\n    </Midl>\n    <Manifest>\n      <EnableDpiAwareness>false</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <ExceptionHandling>false</ExceptionHandling>\n      <DebugInformationFormat />\n      <PreprocessorDefinitions>WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <AdditionalIncludeDirectories>..\\WinSpyHook;..\\WTLHelper\\WTLHelper</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <TargetEnvironment>Win32</TargetEnvironment>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <HeaderFileName>WinSpy.h</HeaderFileName>\n      <InterfaceIdentifierFileName>WinSpy_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>WinSpy_p.c</ProxyFileName>\n      <GenerateStublessProxies>true</GenerateStublessProxies>\n      <TypeLibraryName>$(IntDir)/WinSpy.tlb</TypeLibraryName>\n      <DllDataFileName />\n    </Midl>\n    <PostBuildEvent>\n      <Command>\n      </Command>\n    </PostBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>false</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <ExceptionHandling>false</ExceptionHandling>\n      <DebugInformationFormat>\n      </DebugInformationFormat>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <AdditionalIncludeDirectories>..\\WinSpyHook;..\\WTLHelper\\WTLHelper</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <TargetEnvironment>Win32</TargetEnvironment>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <HeaderFileName>WinSpy.h</HeaderFileName>\n      <InterfaceIdentifierFileName>WinSpy_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>WinSpy_p.c</ProxyFileName>\n      <GenerateStublessProxies>true</GenerateStublessProxies>\n      <TypeLibraryName>$(IntDir)/WinSpy.tlb</TypeLibraryName>\n      <DllDataFileName>\n      </DllDataFileName>\n    </Midl>\n    <PostBuildEvent>\n      <Command>signtool sign /i DigiCert /fd sha256 $(TargetPath)</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>false</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <ExceptionHandling>false</ExceptionHandling>\n      <DebugInformationFormat />\n      <PreprocessorDefinitions>_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <AdditionalIncludeDirectories>..\\WinSpyHook;..\\WTLHelper\\WTLHelper</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <HeaderFileName>WinSpy.h</HeaderFileName>\n      <InterfaceIdentifierFileName>WinSpy_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>WinSpy_p.c</ProxyFileName>\n      <GenerateStublessProxies>true</GenerateStublessProxies>\n      <TypeLibraryName>$(IntDir)/WinSpy.tlb</TypeLibraryName>\n      <DllDataFileName />\n    </Midl>\n    <PostBuildEvent>\n      <Command>\n      </Command>\n    </PostBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>false</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <ExceptionHandling>false</ExceptionHandling>\n      <DebugInformationFormat>\n      </DebugInformationFormat>\n      <PreprocessorDefinitions>_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <AdditionalIncludeDirectories>..\\WinSpyHook;..\\WTLHelper\\WTLHelper</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <HeaderFileName>WinSpy.h</HeaderFileName>\n      <InterfaceIdentifierFileName>WinSpy_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>WinSpy_p.c</ProxyFileName>\n      <GenerateStublessProxies>true</GenerateStublessProxies>\n      <TypeLibraryName>$(IntDir)/WinSpy.tlb</TypeLibraryName>\n      <DllDataFileName>\n      </DllDataFileName>\n    </Midl>\n    <PostBuildEvent>\n      <Command>signtool sign /a /n Scorpio /t http://timestamp.digicert.com /fd sha256 $(TargetPath)</Command>\n    </PostBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>false</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AboutDlg.cpp\" />\n    <ClCompile Include=\"AutomationTreeView.cpp\" />\n    <ClCompile Include=\"HookHelper.cpp\" />\n    <ClCompile Include=\"IconHelper.cpp\" />\n    <ClCompile Include=\"ImageIconCache.cpp\" />\n    <ClCompile Include=\"MessageDecoder.cpp\" />\n    <ClCompile Include=\"MessagesView.cpp\" />\n    <ClCompile Include=\"ProcessesView.cpp\" />\n    <ClCompile Include=\"SecurityHelper.cpp\" />\n    <ClCompile Include=\"WindowGeneralPage.cpp\" />\n    <ClCompile Include=\"WindowsListView.cpp\" />\n    <ClCompile Include=\"FindWindowDlg.cpp\" />\n    <ClCompile Include=\"FormatHelper.cpp\" />\n    <ClCompile Include=\"MainFrm.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"ProcessHelper.cpp\" />\n    <ClCompile Include=\"WindowHelper.cpp\" />\n    <ClCompile Include=\"WindowsView.cpp\" />\n    <ClCompile Include=\"WindowWindowsPage.cpp\" />\n    <ClCompile Include=\"WinSpy.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AboutDlg.h\" />\n    <ClInclude Include=\"AutomationTreeView.h\" />\n    <ClInclude Include=\"DialogHelper.h\" />\n    <ClInclude Include=\"HookHelper.h\" />\n    <ClInclude Include=\"IconHelper.h\" />\n    <ClInclude Include=\"ImageIconCache.h\" />\n    <ClInclude Include=\"MessageDecoder.h\" />\n    <ClInclude Include=\"MessagesView.h\" />\n    <ClInclude Include=\"SecurityHelper.h\" />\n    <ClInclude Include=\"FrameWindowHelper.h\" />\n    <ClInclude Include=\"WindowGeneralPage.h\" />\n    <ClInclude Include=\"WindowsListView.h\" />\n    <ClInclude Include=\"FindWindowDlg.h\" />\n    <ClInclude Include=\"FormatHelper.h\" />\n    <ClInclude Include=\"Interfaces.h\" />\n    <ClInclude Include=\"MainFrm.h\" />\n    <ClInclude Include=\"ProcessesView.h\" />\n    <ClInclude Include=\"ProcessHelper.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"TreeViewManager.h\" />\n    <ClInclude Include=\"ViewBase.h\" />\n    <ClInclude Include=\"WindowHelper.h\" />\n    <ClInclude Include=\"WindowsView.h\" />\n    <ClInclude Include=\"WindowWindowsPage.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"WinSpy.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"res\\Automation.ico\" />\n    <Image Include=\"res\\close-window.ico\" />\n    <Image Include=\"res\\gears.ico\" />\n    <Image Include=\"res\\gear_information.ico\" />\n    <Image Include=\"res\\maximize.ico\" />\n    <Image Include=\"res\\message.ico\" />\n    <Image Include=\"res\\messages.ico\" />\n    <Image Include=\"res\\Minimize.ico\" />\n    <Image Include=\"res\\refresh.ico\" />\n    <Image Include=\"res\\restore.ico\" />\n    <Image Include=\"res\\Target.ico\" />\n    <Image Include=\"res\\window-close.ico\" />\n    <Image Include=\"res\\window-hidden.ico\" />\n    <Image Include=\"res\\window-notext.ico\" />\n    <Image Include=\"res\\window-properties.ico\" />\n    <Image Include=\"res\\window.ico\" />\n    <Image Include=\"res\\windows.ico\" />\n    <Image Include=\"res\\WindowSearch.ico\" />\n    <Image Include=\"res\\WindowSendToBack.ico\" />\n    <Image Include=\"res\\WindowSendToFront.ico\" />\n    <Image Include=\"res\\window_delete.ico\" />\n    <Image Include=\"res\\window_new.ico\" />\n    <Image Include=\"res\\WinSpy.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\WTLHelper\\WTLHelper\\WTLHelper.vcxproj\">\n      <Project>{ae53419f-a769-4548-8e15-e311904df7df}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "WinSpy/WinSpy.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{f871bb5c-f151-4e10-8bbb-10019ddd6a72}</UniqueIdentifier>\n      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{47fb17d7-d54c-4fc7-85b2-7c653d04b30a}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{9c7daf0d-2916-49f7-872d-30cf5e95725d}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\\Icons\">\n      <UniqueIdentifier>{ff137a25-faa3-4d88-af38-5c1bc296546b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Dialogs\">\n      <UniqueIdentifier>{96be1941-f83d-4366-ad55-930da999a2eb}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Views\">\n      <UniqueIdentifier>{9a542756-dfdb-4a47-b231-2b2ae2aef120}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Helpers\">\n      <UniqueIdentifier>{3b473b33-73a4-4bd6-a469-d86318a53f81}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"WinSpy.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainFrm.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AboutDlg.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"pch.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FindWindowDlg.cpp\">\n      <Filter>Dialogs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WindowsView.cpp\">\n      <Filter>Views</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ProcessHelper.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FormatHelper.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WindowHelper.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WindowsListView.cpp\">\n      <Filter>Views</Filter>\n    </ClCompile>\n    <ClCompile Include=\"IconHelper.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ProcessesView.cpp\">\n      <Filter>Views</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ImageIconCache.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WindowGeneralPage.cpp\">\n      <Filter>Dialogs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WindowWindowsPage.cpp\">\n      <Filter>Dialogs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SecurityHelper.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MessagesView.cpp\">\n      <Filter>Views</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MessageDecoder.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"HookHelper.cpp\">\n      <Filter>Helpers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AutomationTreeView.cpp\">\n      <Filter>Views</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"MainFrm.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AboutDlg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"pch.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ViewBase.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Interfaces.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TreeViewManager.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FindWindowDlg.h\">\n      <Filter>Dialogs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WindowsView.h\">\n      <Filter>Views</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ProcessesView.h\">\n      <Filter>Views</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WindowHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ProcessHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Resource Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FormatHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WindowsListView.h\">\n      <Filter>Views</Filter>\n    </ClInclude>\n    <ClInclude Include=\"IconHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ImageIconCache.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WindowGeneralPage.h\">\n      <Filter>Dialogs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DialogHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WindowWindowsPage.h\">\n      <Filter>Dialogs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SecurityHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MessagesView.h\">\n      <Filter>Views</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FrameWindowHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MessageDecoder.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"HookHelper.h\">\n      <Filter>Helpers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AutomationTreeView.h\">\n      <Filter>Views</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"WinSpy.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"res\\window.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\window-hidden.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\WinSpy.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\window_delete.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\window_new.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\windows.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\refresh.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\window-close.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\window-notext.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\WindowSendToBack.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\Minimize.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\maximize.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\close-window.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\Target.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\window-properties.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\gears.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\gear_information.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\message.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\messages.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\WindowSearch.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\WindowSendToFront.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\restore.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n    <Image Include=\"res\\Automation.ico\">\n      <Filter>Resource Files\\Icons</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "WinSpy/WindowGeneralPage.cpp",
    "content": "#include \"pch.h\"\n#include \"resource.h\"\n#include \"WindowGeneralPage.h\"\n#include \"FormatHelper.h\"\n#include \"ProcessHelper.h\"\n#include \"WindowHelper.h\"\n\nvoid CWindowGeneralPage::UpdateData() {\n\tWINDOWINFO wi{ sizeof(wi) };\n\t::GetWindowInfo(m_Win, &wi);\n\tGetParent().SetIcon(WindowHelper::GetWindowIcon(m_Win));\n\n\tSetDlgItemText(IDC_RECT, FormatHelper::RectToString(wi.rcWindow));\n\tSetDlgItemText(IDC_CLIENTRECT, FormatHelper::RectToString(wi.rcClient));\n\tDWORD pid;\n\tauto tid = ::GetWindowThreadProcessId(m_Win, &pid);\n\tSetDlgItemInt(IDC_THREAD, tid, FALSE);\n\tCString text;\n\ttext.Format(L\"0x%zX\", DWORD_PTR(m_Win.m_hWnd));\n\tSetDlgItemText(IDC_HANDLE, text);\n\n\tif (tid) {\n\t\ttext.Format(L\"%s (%u)\", (PCWSTR)ProcessHelper::GetProcessImageName(pid), pid);\n\t\tSetDlgItemText(IDC_PROCESS, text);\n\t}\n\tWINDOWPLACEMENT wp{ sizeof(wp) };\n\tm_Win.GetWindowPlacement(&wp);\n\tSetDlgItemText(IDC_RESTORE_RECT, FormatHelper::RectToString(wp.rcNormalPosition));\n\n\tm_Win.GetWindowText(text);\n\tSetDlgItemText(IDC_TEXT, text);\n\ttext.Format(L\"0x%04X\\n\", wi.atomWindowType);\n\tSetDlgItemText(IDC_ATOM, text);\n\ttext.Format(L\"0x%08X\\n\", wi.dwStyle);\n\tSetDlgItemText(IDC_STYLE, text);\n\ttext.Format(L\"0x%08X\\n\", wi.dwExStyle);\n\tSetDlgItemText(IDC_STYLEEX, text);\n\ttext.Format(L\"0x%zX\", m_Win.GetMenu() ? (ULONG_PTR)m_Win.GetMenu() : WindowHelper::GetID(m_Win));\n\tSetDlgItemText(IDC_MENU, text);\n\ttext.Format(L\"0x%zX\", m_Win.GetWindowLongPtr(GWLP_USERDATA));\n\tSetDlgItemText(IDC_USERDATA, text);\n\n\tWCHAR className[128];\n\tif (::GetClassName(m_Win, className, _countof(className)))\n\t\tSetDlgItemText(IDC_CLASSNAME, className);\n\n\tauto clsStyle = (DWORD)::GetClassLongPtr(m_Win, GCL_STYLE);\n\ttext.Format(L\"0x%08X\", clsStyle);\n\tSetDlgItemText(IDC_STYLECLASS, text);\n\tFillStyleList(wi.dwStyle, WindowHelper::GetWindowStyleArray(), IDC_STYLES, L\"\", L\"WS_OVERLAPPED\");\n\tFillSpecificControlStyles();\n\tFillStyleList(wi.dwExStyle, WindowHelper::GetWindowStyleExArray(), IDC_STYLESEX, L\"\", L\"WS_EX_LEFT\");\n\tFillStyleList(clsStyle, WindowHelper::GetClassStyleArray(), IDC_CLASSSTYLE, L\"\", nullptr);\n}\n\nvoid CWindowGeneralPage::FillStyleList(DWORD style, std::pair<StyleItem const*, int> styles, UINT id, PCWSTR prefix, PCWSTR defaultStyle, bool clear) {\n\tauto const [items, count] = styles;\n\tCListBox lb(GetDlgItem(id));\n\tATLASSERT(lb);\n\tif(clear)\n\t\tlb.ResetContent();\n\n\tCString text;\n\tfor (int i = 0; i < count; i++) {\n\t\tif ((style & items[i].Mask) == items[i].Value) {\n\t\t\ttext.Format(L\"%s%s (0x%X)\", prefix, (PCWSTR)items[i].Text, items[i].Value);\n\t\t\tlb.AddString(text);\n\t\t}\n\t}\n\tif (style == 0 && defaultStyle)\n\t\tlb.AddString(CString(defaultStyle) + L\" (0)\");\n}\n\nvoid CWindowGeneralPage::FillSpecificControlStyles() {\n\tWCHAR name[64];\n\tif (!::GetClassName(m_Win, name, _countof(name)))\n\t\treturn;\n\n\tauto style = m_Win.GetStyle() & 0xffff;\n\tconst CString ATLPrefix = L\"ATL:\";\n\n\tstatic const struct {\n\t\tPCWSTR className;\n\t\tstd::pair<StyleItem const*, int> items;\n\t\tPCWSTR def = L\"\";\n\t} controls[] = {\n\t\t{ WC_LISTVIEW, WindowHelper::GetListViewStyleArray(), L\"LVS_ALIGNTOP\" },\n\t\t{ WC_TREEVIEW, WindowHelper::GetTreeViewStyleArray() },\n\t\t{ WC_TABCONTROL, WindowHelper::GetTabCtrlStyleArray(), L\"TCS_TABS\" },\n\t\t{ WC_LISTBOX, WindowHelper::GetListBoxStyleArray() },\n\t\t{ WC_COMBOBOX, WindowHelper::GetComboBoxStyleArray() },\n\t\t{ WC_EDIT, WindowHelper::GetEditStyleArray(), L\"ES_LEFT\" },\n\t\t{ WC_BUTTON, WindowHelper::GetButtonStyleArray(), L\"BS_TEXT\" },\n\t\t{ WC_HEADER, WindowHelper::GetHeaderStyleArray(), L\"HDS_HORZ\" },\n\t\t{ WC_STATIC, WindowHelper::GetStaticStyleArray(), L\"SS_LEFT\" },\n\t\t{ TOOLTIPS_CLASS, WindowHelper::GetToolTipStyleArray() },\n\t\t{ STATUSCLASSNAME, WindowHelper::GetStatusBarStyleArray() },\n\t\t{ TOOLBARCLASSNAME, WindowHelper::GetToolBarStyleArray() },\n\t\t{ REBARCLASSNAME, WindowHelper::GetRebarStyleArray() },\n\t\t{ WC_SCROLLBAR, WindowHelper::GetScrollBarStyleArray(), L\"SBS_HORZ\" },\n\t};\n\n\tfor (auto& item : controls) {\n\t\tif (_wcsicmp(name, item.className) == 0 || _wcsicmp(name, ATLPrefix + item.className) == 0) {\n\t\t\tFillStyleList(style, item.items, IDC_STYLES, L\"\", item.def, false);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nLRESULT CWindowGeneralPage::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) {\n\tUpdateData();\n\n\treturn 0;\n}\n\nLRESULT CWindowGeneralPage::OnUpdate(UINT, WPARAM, LPARAM lp, BOOL&) {\n\tATLASSERT(lp);\n\tm_Win.Detach();\n\tm_Win.Attach(reinterpret_cast<HWND>(lp));\n\tUpdateData();\n\n\treturn 0;\n}\n"
  },
  {
    "path": "WinSpy/WindowGeneralPage.h",
    "content": "#pragma once\n\n#include \"DialogHelper.h\"\n\nstruct StyleItem;\n\nclass CWindowGeneralPage :\n\tpublic CDialogHelper<CWindowGeneralPage>,\n\tpublic CPropertyPageImpl<CWindowGeneralPage> {\npublic:\n\tenum { IDD = IDD_WINPROP };\n\n\tconst UINT WM_UPDATE = WM_USER + 300;\n\n\tCWindowGeneralPage(HWND hWnd) : m_Win(hWnd) {\n\t\tm_psp.dwFlags |= PSP_USEICONID;\n\t\tm_psp.pszIcon = MAKEINTRESOURCE(IDI_WINPROP);\n\t}\n\n\tvoid UpdateData();\n\nprotected:\n\tBEGIN_MSG_MAP(CWindowGeneralPage)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tMESSAGE_HANDLER(WM_UPDATE, OnUpdate)\n\tEND_MSG_MAP()\n\nprivate:\n\tvoid FillStyleList(DWORD style, std::pair<StyleItem const*, int> styles, UINT id, PCWSTR prefix, PCWSTR defaultStyle, bool clear = true);\n\tvoid FillSpecificControlStyles();\n\n//\tLRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n//\tLRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n//\tLRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnUpdate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\n\tCWindow m_Win;\n};\n"
  },
  {
    "path": "WinSpy/WindowHelper.cpp",
    "content": "#include \"pch.h\"\n#include \"resource.h\"\n#include \"WindowHelper.h\"\n#include \"ProcessHelper.h\"\n#include \"FormatHelper.h\"\n#include \"WindowGeneralPage.h\"\n#include \"WindowWindowsPage.h\"\n\n#define CASE_STR(x) case x: return L#x \n#define PAIR_STR(x) { x, L#x }\n#define PAIR_STR2(x, mask) { x, L#x, mask }\n\nCString WindowHelper::WindowStyleToString(HWND hWnd) {\n\tauto style = CWindow(hWnd).GetStyle();\n\tCString text;\n\n\tauto const [styles, count] = GetWindowStyleArray();\n\tfor (int i = 0; i < count; i++) {\n\t\tauto& item = styles[i];\n\t\tif ((style & item.Value) == item.Value)\n\t\t\ttext += CString(item.Text) += L\", \";\n\t}\n\tif (text.IsEmpty())\n\t\ttext = L\"OVERLAPPED, \";\n\treturn L\"(WS_) \" + text.Left(text.GetLength() - 2);\n}\n\nCString WindowHelper::ClassStyleToString(HWND hWnd) {\n\tauto style = ::GetClassLongPtr(hWnd, GCL_STYLE);\n\tCString text;\n\n\tauto const [styles, count] = GetWindowStyleArray();\n\tfor (int i = 0; i < count; i++) {\n\t\tauto& item = styles[i];\n\t\tif ((style & item.Value) == item.Value)\n\t\t\ttext += CString(item.Text) += L\", \";\n\t}\n\tif (text.IsEmpty())\n\t\treturn L\"\";\n\n\treturn L\"(CS_) \" + text.Left(text.GetLength() - 2);\n}\n\nCString WindowHelper::WindowExtendedStyleToString(HWND hWnd) {\n\tauto style = CWindow(hWnd).GetExStyle();\n\tCString text;\n\n\tauto const [styles, count] = GetWindowStyleArray();\n\tfor (int i = 0; i < count; i++) {\n\t\tauto& item = styles[i];\n\t\tif ((style & item.Value) == item.Value)\n\t\t\ttext += CString(item.Text) += L\", \";\n\t}\n\n\tif (text.IsEmpty())\n\t\ttext = L\"LEFT, RIGHTSCROLLBAR, \";\n\n\treturn L\"(WS_EX_) \" + text.Left(text.GetLength() - 2);\n}\n\nCString WindowHelper::WindowRectToString(HWND hWnd) {\n\tCWindow win(hWnd);\n\tCRect rc;\n\twin.GetWindowRect(&rc);\n\treturn FormatHelper::RectToString(rc);\n}\n\nCString WindowHelper::GetWindowClassName(HWND hWnd) {\n\tWCHAR name[128];\n\t::GetClassName(hWnd, name, _countof(name));\n\treturn name;\n}\n\nCString WindowHelper::GetWindowText(HWND hWnd) {\n\tCString text;\n\tCWindow(hWnd).GetWindowText(text);\n\treturn text;\n}\n\nHICON WindowHelper::GetWindowOrProcessIcon(HWND hWnd) {\n\tauto hIcon = GetWindowIcon(hWnd);\n\tif (!hIcon) {\n\t\tDWORD pid = 0;\n\t\t::GetWindowThreadProcessId(hWnd, &pid);\n\t\tif (pid) {\n\t\t\t::ExtractIconEx(ProcessHelper::GetProcessImageName(pid, true), 0, nullptr, &hIcon, 1);\n\t\t}\n\t}\n\n\treturn hIcon;\n}\n\nbool WindowHelper::Flash(HWND hWnd) {\n\tFLASHWINFO info = { sizeof(info) };\n\tinfo.dwFlags = FLASHW_CAPTION;\n\tinfo.uCount = 3;\n\tinfo.hwnd = hWnd;\n\treturn ::FlashWindowEx(&info);\n}\n\nvoid WindowHelper::HighlightBorder(HWND hWnd, bool highlight) {\n\tCRect rc;\n\t::GetWindowRect(hWnd, &rc);\n\trc.OffsetRect(-rc.left, -rc.top);\n\n\tCRgn rgn1;\n\trc.InflateRect(2, 2);\n\trgn1.CreateRectRgnIndirect(&rc);\n\trc.DeflateRect(5, 5);\n\tCRgn rgn2;\n\trgn2.CreateRectRgnIndirect(&rc);\n\tCRgn rgn;\n\trgn.CreateRectRgn(0, 0, 1, 1);\n\trgn.CombineRgn(rgn1, rgn2, RGN_DIFF);\n\tif (!highlight) {\n\t\t::RedrawWindow(hWnd, nullptr, rgn, RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME);\n\t\treturn;\n\t}\n\n\tCWindowDC dc(hWnd);\n\tCBrush b;\n\tb.CreateSolidBrush(RGB(255, 0, 0));\n\tdc.FillRgn(rgn, b);\n}\n\nHICON WindowHelper::GetWindowIcon(HWND hWnd) {\n\tHICON hIcon{ nullptr };\n\t::SendMessageTimeout(hWnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG | SMTO_ERRORONEXIT, 100, (DWORD_PTR*)&hIcon);\n\tif (!hIcon) {\n\t\thIcon = (HICON)::GetClassLongPtr(hWnd, GCLP_HICONSM);\n\t}\n\treturn hIcon;\n}\n\nCString WindowHelper::GetWindowClassAndTitle(HWND hWnd) {\n\tif (hWnd == nullptr || !::IsWindow(hWnd))\n\t\treturn L\"\";\n\n\tWCHAR className[64];\n\tCString text;\n\tif (::GetClassName(hWnd, className, _countof(className)))\n\t\ttext.Format(L\"[%s]\", className);\n\tCString title;\n\tCWindow(hWnd).GetWindowText(title);\n\tif (!title.IsEmpty())\n\t\ttext.Format(L\"%s (%s)\", (PCWSTR)text, (PCWSTR)title);\n\treturn text;\n}\n\nstd::unordered_map<HWND, int>& WindowHelper::GetIconMap() {\n\tstatic std::unordered_map<HWND, int> s_IconMap;\n\treturn s_IconMap;\n}\n\nCImageList& WindowHelper::GetImageList() {\n\tstatic CImageList images;\n\tif (!images) {\n\t\timages.Create(16, 16, ILC_COLOR32, 64, 16);\n\t\timages.AddIcon(AtlLoadIconImage(IDI_WINDOW, 0, 16, 16));\n\t}\n\treturn images;\n}\n\nWindowItem WindowHelper::GetWindowInfo(HWND hWnd) {\n\tWindowItem wi;\n\twi.hWnd = hWnd;\n\twi.ThreadId = ::GetWindowThreadProcessId(hWnd, &wi.ProcessId);\n\twi.ProcessName = ProcessHelper::GetProcessImageName(wi.ProcessId);\n\n\treturn wi;\n}\n\nbool WindowHelper::ThreadHasWindows(DWORD tid) {\n\tbool hasWindows = false;\n\t::EnumThreadWindows(tid, [](auto, auto param) {\n\t\t*reinterpret_cast<bool*>(param) = true;\n\t\treturn FALSE;\n\t\t}, reinterpret_cast<LPARAM>(&hasWindows));\n\treturn hasWindows;\n}\n\nint WindowHelper::ShowWindowProperties(HWND hWnd) {\n\tCString text;\n\ttext.Format(L\"Window 0x%X Properties\", PtrToUlong(hWnd));\n\tCPropertySheet sheet((PCWSTR)text);\n\tsheet.m_psh.dwFlags |= PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP;\n\tCWindowGeneralPage general(hWnd);\n\tCWindowWindowsPage windows(hWnd);\n\tsheet.AddPage(general);\n\tsheet.AddPage(windows);\n\tsheet.DoModal();\n\n\treturn 0;\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetWindowStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(WS_POPUP),\n\t\tPAIR_STR(WS_CHILD),\n\t\tPAIR_STR(WS_MINIMIZE),\n\t\tPAIR_STR(WS_VISIBLE),\n\t\tPAIR_STR(WS_DISABLED),\n\t\tPAIR_STR(WS_CLIPSIBLINGS),\n\t\tPAIR_STR(WS_CLIPCHILDREN),\n\t\tPAIR_STR(WS_MAXIMIZE),\n\t\tPAIR_STR(WS_BORDER),\n\t\tPAIR_STR(WS_DLGFRAME),\n\t\tPAIR_STR(WS_VSCROLL),\n\t\tPAIR_STR(WS_HSCROLL),\n\t\tPAIR_STR(WS_SYSMENU),\n\t\tPAIR_STR(WS_THICKFRAME),\n\t\tPAIR_STR(WS_MINIMIZEBOX),\n\t\tPAIR_STR(WS_MAXIMIZEBOX),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetListViewStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(LVS_ALIGNLEFT),\n\t\tPAIR_STR(LVS_AUTOARRANGE),\n\t\tPAIR_STR(LVS_EDITLABELS),\n\t\tPAIR_STR(LVS_ICON),\n\t\tPAIR_STR(LVS_LIST),\n\t\tPAIR_STR(LVS_NOCOLUMNHEADER),\n\t\tPAIR_STR(LVS_NOLABELWRAP),\n\t\tPAIR_STR(LVS_SINGLESEL),\n\t\tPAIR_STR(LVS_REPORT),\n\t\tPAIR_STR(LVS_SMALLICON),\n\t\tPAIR_STR(LVS_SORTASCENDING),\n\t\tPAIR_STR(LVS_SORTDESCENDING),\n\t\tPAIR_STR(LVS_SHOWSELALWAYS),\n\t\tPAIR_STR(LVS_SHAREIMAGELISTS),\n\t\tPAIR_STR(LVS_OWNERDATA),\n\t\tPAIR_STR(LVS_OWNERDRAWFIXED),\n\t\tPAIR_STR(LVS_NOSCROLL),\n\t\tPAIR_STR(LVS_NOSORTHEADER),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetTreeViewStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(TVS_CHECKBOXES),\n\t\tPAIR_STR(TVS_DISABLEDRAGDROP),\n\t\tPAIR_STR(TVS_EDITLABELS),\n\t\tPAIR_STR(TVS_FULLROWSELECT),\n\t\tPAIR_STR(TVS_HASBUTTONS),\n\t\tPAIR_STR(TVS_HASLINES),\n\t\tPAIR_STR(TVS_LINESATROOT),\n\t\tPAIR_STR(TVS_NOHSCROLL),\n\t\tPAIR_STR(TVS_INFOTIP),\n\t\tPAIR_STR(TVS_NONEVENHEIGHT),\n\t\tPAIR_STR(TVS_NOTOOLTIPS),\n\t\tPAIR_STR(TVS_RTLREADING),\n\t\tPAIR_STR(TVS_SHOWSELALWAYS),\n\t\tPAIR_STR(TVS_SINGLEEXPAND),\n\t\tPAIR_STR(TVS_TRACKSELECT),\n\t\tPAIR_STR(TVS_NOSCROLL),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetTabCtrlStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(TCS_BOTTOM),\n\t\tPAIR_STR(TCS_BUTTONS),\n\t\tPAIR_STR(TCS_FIXEDWIDTH),\n\t\tPAIR_STR(TCS_FLATBUTTONS),\n\t\tPAIR_STR(TCS_FOCUSNEVER),\n\t\tPAIR_STR(TCS_FOCUSONBUTTONDOWN),\n\t\tPAIR_STR(TCS_FORCEICONLEFT),\n\t\tPAIR_STR(TCS_FORCELABELLEFT),\n\t\tPAIR_STR(TCS_HOTTRACK),\n\t\tPAIR_STR(TCS_MULTILINE),\n\t\tPAIR_STR(TCS_MULTISELECT),\n\t\tPAIR_STR(TCS_OWNERDRAWFIXED),\n\t\tPAIR_STR(TCS_RAGGEDRIGHT),\n\t\tPAIR_STR(TCS_RIGHT),\n\t\tPAIR_STR(TCS_RIGHTJUSTIFY),\n\t\tPAIR_STR(TCS_SCROLLOPPOSITE),\n\t\tPAIR_STR(TCS_SINGLELINE),\n\t\tPAIR_STR(TCS_TOOLTIPS),\n\t\tPAIR_STR(TCS_VERTICAL),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetWindowStyleExArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(WS_EX_DLGMODALFRAME),\n\t\tPAIR_STR(WS_EX_NOPARENTNOTIFY),\n\t\tPAIR_STR(WS_EX_TOPMOST),\n\t\tPAIR_STR(WS_EX_ACCEPTFILES),\n\t\tPAIR_STR(WS_EX_TRANSPARENT),\n\t\tPAIR_STR(WS_EX_TOOLWINDOW),\n\t\tPAIR_STR(WS_EX_WINDOWEDGE),\n\t\tPAIR_STR(WS_EX_CLIENTEDGE),\n\t\tPAIR_STR(WS_EX_CONTEXTHELP),\n\t\tPAIR_STR(WS_EX_RIGHT),\n\t\tPAIR_STR(WS_EX_RTLREADING),\n\t\tPAIR_STR(WS_EX_LEFTSCROLLBAR),\n\t\tPAIR_STR(WS_EX_CONTROLPARENT),\n\t\tPAIR_STR(WS_EX_STATICEDGE),\n\t\tPAIR_STR(WS_EX_APPWINDOW),\n\t\tPAIR_STR(WS_EX_LAYERED),\n\t\tPAIR_STR(WS_EX_NOINHERITLAYOUT),\n\t\tPAIR_STR(WS_EX_NOREDIRECTIONBITMAP),\n\t\tPAIR_STR(WS_EX_LAYOUTRTL),\n\t\tPAIR_STR(WS_EX_COMPOSITED),\n\t\tPAIR_STR(WS_EX_NOACTIVATE),\n\t\t{ 0x8000, L\"WS_EX_FEEDBACK\" },\n\t\t{ 0x80000000, L\"WS_EX_ANSICREATOR\" },\n\t\t{ 0x800000,\tL\"WS_EX_NOPADDEDBORDER\" },\n\t\t{ 0x2,\tL\"WS_EX_DRAGOBJECT\" },\n\t};\n\t\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetClassStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(CS_HREDRAW),\n\t\tPAIR_STR(CS_VREDRAW),\n\t\tPAIR_STR(CS_DBLCLKS),\n\t\tPAIR_STR(CS_OWNDC),\n\t\tPAIR_STR(CS_CLASSDC),\n\t\tPAIR_STR(CS_PARENTDC),\n\t\tPAIR_STR(CS_SAVEBITS),\n\t\tPAIR_STR(CS_GLOBALCLASS),\n\t\tPAIR_STR(CS_BYTEALIGNCLIENT),\n\t\tPAIR_STR(CS_BYTEALIGNWINDOW),\n\t\tPAIR_STR(CS_IME),\n\t\tPAIR_STR(CS_NOCLOSE),\n\t\tPAIR_STR(CS_DROPSHADOW),\n\t\t{ 0x8000, L\"CS_SYSTEM\" },\n\t};\n\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetEditStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(ES_AUTOHSCROLL),\n\t\tPAIR_STR(ES_AUTOVSCROLL),\n\t\tPAIR_STR(ES_READONLY),\n\t\tPAIR_STR(ES_CENTER),\n\t\tPAIR_STR(ES_RIGHT),\n\t\tPAIR_STR(ES_NOHIDESEL),\n\t\tPAIR_STR(ES_LOWERCASE),\n\t\tPAIR_STR(ES_UPPERCASE),\n\t\tPAIR_STR(ES_WANTRETURN),\n\t\tPAIR_STR(ES_MULTILINE),\n\t\tPAIR_STR(ES_PASSWORD),\n\t\tPAIR_STR(ES_NUMBER),\n\t\tPAIR_STR(ES_OEMCONVERT),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetToolTipStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(TTS_ALWAYSTIP),\n\t\tPAIR_STR(TTS_BALLOON),\n\t\tPAIR_STR(TTS_CLOSE),\n\t\tPAIR_STR(TTS_NOANIMATE),\n\t\tPAIR_STR(TTS_NOFADE),\n\t\tPAIR_STR(TTS_NOPREFIX),\n\t\tPAIR_STR(TTS_USEVISUALSTYLE),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetScrollBarStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(SBS_VERT),\n\t\tPAIR_STR(SBS_SIZEBOX),\n\t\tPAIR_STR(SBS_SIZEGRIP),\n\t\tPAIR_STR(SBS_RIGHTALIGN),\n\t\tPAIR_STR(SBS_BOTTOMALIGN),\n\t\tPAIR_STR(SBS_TOPALIGN),\n\t\tPAIR_STR(SBS_LEFTALIGN),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetStatusBarStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(SBARS_SIZEGRIP),\n\t\tPAIR_STR(SBARS_TOOLTIPS),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetToolBarStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(TBSTYLE_ALTDRAG),\n\t\tPAIR_STR(TBSTYLE_FLAT),\n\t\tPAIR_STR(TBSTYLE_LIST),\n\t\tPAIR_STR(TBSTYLE_WRAPABLE),\n\t\tPAIR_STR(TBSTYLE_CUSTOMERASE),\n\t\tPAIR_STR(TBSTYLE_REGISTERDROP),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetRebarStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(RBS_AUTOSIZE),\n\t\tPAIR_STR(RBS_BANDBORDERS),\n\t\tPAIR_STR(RBS_DBLCLKTOGGLE),\n\t\tPAIR_STR(RBS_FIXEDORDER),\n\t\tPAIR_STR(RBS_VERTICALGRIPPER),\n\t\tPAIR_STR(RBS_REGISTERDROP),\n\t\tPAIR_STR(RBS_VARHEIGHT),\n\t\tPAIR_STR(RBS_TOOLTIPS),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetStaticStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR2(SS_RIGHT, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_BLACKFRAME, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_GRAYFRAME, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_SIMPLE, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_GRAYRECT, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_BLACKRECT, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_ICON, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_BITMAP, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_OWNERDRAW, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_ENHMETAFILE, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_ETCHEDFRAME, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_ETCHEDHORZ, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_ETCHEDVERT, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_WHITEFRAME, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_LEFTNOWORDWRAP, SS_TYPEMASK),\n\t\tPAIR_STR2(SS_CENTER, SS_TYPEMASK),\n\n\t\tPAIR_STR(SS_NOPREFIX),\n\t\tPAIR_STR(SS_NOTIFY),\n\t\tPAIR_STR(SS_CENTERIMAGE),\n\t\tPAIR_STR(SS_SUNKEN),\n\t\tPAIR_STR(SS_EDITCONTROL),\n\t\tPAIR_STR(SS_RIGHTJUST),\n\t\tPAIR_STR(SS_REALSIZEIMAGE),\n\t\tPAIR_STR2(SS_PATHELLIPSIS, SS_ELLIPSISMASK),\n\t\tPAIR_STR2(SS_WORDELLIPSIS, SS_ELLIPSISMASK),\n\t\tPAIR_STR2(SS_ENDELLIPSIS, SS_ELLIPSISMASK),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetHeaderStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(HDS_BUTTONS),\n\t\tPAIR_STR(HDS_CHECKBOXES),\n\t\tPAIR_STR(HDS_DRAGDROP),\n\t\tPAIR_STR(HDS_FILTERBAR),\n\t\tPAIR_STR(HDS_FLAT),\n\t\tPAIR_STR(HDS_FULLDRAG),\n\t\tPAIR_STR(HDS_HIDDEN),\n\t\tPAIR_STR(HDS_HOTTRACK),\n\t\tPAIR_STR(HDS_NOSIZING),\n\t\tPAIR_STR(HDS_OVERFLOW),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetButtonStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR2(BS_AUTO3STATE, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_AUTOCHECKBOX, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_AUTORADIOBUTTON, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_GROUPBOX, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_OWNERDRAW, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_PUSHBOX, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_CHECKBOX, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_DEFPUSHBUTTON, BS_TYPEMASK),\n\t\tPAIR_STR2(BS_DEFSPLITBUTTON, BS_TYPEMASK),\n\n\t\tPAIR_STR(BS_CENTER),\n\t\tPAIR_STR(BS_RIGHT),\n\t\tPAIR_STR(BS_BITMAP),\n\t\tPAIR_STR(BS_BOTTOM),\n\t\tPAIR_STR(BS_COMMANDLINK),\n\t\tPAIR_STR(BS_FLAT),\n\t\tPAIR_STR(BS_NOTIFY),\n\t\tPAIR_STR(BS_MULTILINE),\n\t\tPAIR_STR(BS_TOP),\n\t\tPAIR_STR(BS_FLAT),\n\t\tPAIR_STR(BS_LEFTTEXT),\n\t\tPAIR_STR2(BS_USERBUTTON, BS_TYPEMASK),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetListBoxStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(LBS_COMBOBOX),\n\t\tPAIR_STR(LBS_NOSEL),\n\t\tPAIR_STR(LBS_SORT),\n\t\tPAIR_STR(LBS_NOTIFY),\n\t\tPAIR_STR(LBS_NOREDRAW),\n\t\tPAIR_STR(LBS_MULTICOLUMN),\n\t\tPAIR_STR(LBS_MULTIPLESEL),\n\t\tPAIR_STR(LBS_HASSTRINGS),\n\t\tPAIR_STR(LBS_USETABSTOPS),\n\t\tPAIR_STR(LBS_NOINTEGRALHEIGHT),\n\t\tPAIR_STR(LBS_OWNERDRAWFIXED),\n\t\tPAIR_STR(LBS_OWNERDRAWVARIABLE),\n\t\tPAIR_STR(LBS_WANTKEYBOARDINPUT),\n\t\tPAIR_STR(LBS_EXTENDEDSEL),\n\t\tPAIR_STR(LBS_DISABLENOSCROLL),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\nstd::pair<StyleItem const*, int> WindowHelper::GetComboBoxStyleArray() {\n\tstatic const StyleItem styles[] = {\n\t\tPAIR_STR(CBS_AUTOHSCROLL),\n\t\tPAIR_STR(CBS_SIMPLE),\n\t\tPAIR_STR(CBS_SORT),\n\t\tPAIR_STR(CBS_DROPDOWN),\n\t\tPAIR_STR(CBS_DROPDOWNLIST),\n\t\tPAIR_STR(CBS_HASSTRINGS),\n\t\tPAIR_STR(CBS_HASSTRINGS),\n\t\tPAIR_STR(CBS_UPPERCASE),\n\t\tPAIR_STR(CBS_LOWERCASE),\n\t\tPAIR_STR(CBS_OWNERDRAWFIXED),\n\t\tPAIR_STR(CBS_OWNERDRAWVARIABLE),\n\t};\n\treturn std::make_pair(styles, (int)_countof(styles));\n}\n\n\nCString WindowHelper::WindowMessageToString(DWORD msg) {\n\tswitch (msg) {\n\t\tCASE_STR(WM_NULL);\n\t\tCASE_STR(WM_CREATE);\n\t\tCASE_STR(WM_DESTROY);\n\t\tCASE_STR(WM_MOVE);\n\t\tCASE_STR(WM_SIZE);\n\t\tCASE_STR(WM_ACTIVATE);\n\t\tCASE_STR(WM_SETFOCUS);\n\t\tCASE_STR(WM_KILLFOCUS);\n\t\tCASE_STR(WM_ENABLE);\n\t\tCASE_STR(WM_SETREDRAW);\n\t\tCASE_STR(WM_SETTEXT);\n\t\tCASE_STR(WM_GETTEXT);\n\t\tCASE_STR(WM_GETTEXTLENGTH);\n\t\tCASE_STR(WM_PAINT);\n\t\tCASE_STR(WM_CLOSE);\n\t\tCASE_STR(WM_QUERYENDSESSION);\n\t\tCASE_STR(WM_QUIT);\n\t\tCASE_STR(WM_QUERYOPEN);\n\t\tCASE_STR(WM_ERASEBKGND);\n\t\tCASE_STR(WM_SYSCOLORCHANGE);\n\t\tCASE_STR(WM_ENDSESSION);\n\t\tCASE_STR(WM_SHOWWINDOW);\n\t\tCASE_STR(WM_SETTINGCHANGE);\n\t\tCASE_STR(WM_DEVMODECHANGE);\n\t\tCASE_STR(WM_ACTIVATEAPP);\n\t\tCASE_STR(WM_FONTCHANGE);\n\t\tCASE_STR(WM_TIMECHANGE);\n\t\tCASE_STR(WM_CANCELMODE);\n\t\tCASE_STR(WM_SETCURSOR);\n\t\tCASE_STR(WM_MOUSEACTIVATE);\n\t\tCASE_STR(WM_CHILDACTIVATE);\n\t\tCASE_STR(WM_QUEUESYNC);\n\t\tCASE_STR(WM_GETMINMAXINFO);\n\t\tCASE_STR(WM_PAINTICON);\n\t\tCASE_STR(WM_ICONERASEBKGND);\n\t\tCASE_STR(WM_NEXTDLGCTL);\n\t\tCASE_STR(WM_SPOOLERSTATUS);\n\t\tCASE_STR(WM_DRAWITEM);\n\t\tCASE_STR(WM_MEASUREITEM);\n\t\tCASE_STR(WM_DELETEITEM);\n\t\tCASE_STR(WM_VKEYTOITEM);\n\t\tCASE_STR(WM_CHARTOITEM);\n\t\tCASE_STR(WM_SETFONT);\n\t\tCASE_STR(WM_GETFONT);\n\t\tCASE_STR(WM_SETHOTKEY);\n\t\tCASE_STR(WM_GETHOTKEY);\n\t\tCASE_STR(WM_QUERYDRAGICON);\n\t\tCASE_STR(WM_COMPAREITEM);\n\t\tCASE_STR(WM_GETOBJECT);\n\t\tCASE_STR(WM_COMPACTING);\n\t\tCASE_STR(WM_COMMNOTIFY);\n\t\tCASE_STR(WM_WINDOWPOSCHANGING);\n\t\tCASE_STR(WM_WINDOWPOSCHANGED);\n\t\tCASE_STR(WM_POWER);\n\t\tCASE_STR(WM_COPYDATA);\n\t\tCASE_STR(WM_CANCELJOURNAL);\n\t\tCASE_STR(WM_NOTIFY);\n\t\tCASE_STR(WM_INPUTLANGCHANGEREQUEST);\n\t\tCASE_STR(WM_INPUTLANGCHANGE);\n\t\tCASE_STR(WM_TCARD);\n\t\tCASE_STR(WM_HELP);\n\t\tCASE_STR(WM_USERCHANGED);\n\t\tCASE_STR(WM_NOTIFYFORMAT);\n\t\tCASE_STR(WM_CONTEXTMENU);\n\t\tCASE_STR(WM_STYLECHANGING);\n\t\tCASE_STR(WM_STYLECHANGED);\n\t\tCASE_STR(WM_DISPLAYCHANGE);\n\t\tCASE_STR(WM_GETICON);\n\t\tCASE_STR(WM_SETICON);\n\t\tCASE_STR(WM_NCCREATE);\n\t\tCASE_STR(WM_NCDESTROY);\n\t\tCASE_STR(WM_NCCALCSIZE);\n\t\tCASE_STR(WM_NCHITTEST);\n\t\tCASE_STR(WM_NCPAINT);\n\t\tCASE_STR(WM_NCACTIVATE);\n\t\tCASE_STR(WM_GETDLGCODE);\n\t\tCASE_STR(WM_SYNCPAINT);\n\t\tCASE_STR(WM_NCMOUSEMOVE);\n\t\tCASE_STR(WM_NCLBUTTONDOWN);\n\t\tCASE_STR(WM_NCLBUTTONUP);\n\t\tCASE_STR(WM_NCLBUTTONDBLCLK);\n\t\tCASE_STR(WM_NCRBUTTONDOWN);\n\t\tCASE_STR(WM_NCRBUTTONUP);\n\t\tCASE_STR(WM_NCRBUTTONDBLCLK);\n\t\tCASE_STR(WM_NCMBUTTONDOWN);\n\t\tCASE_STR(WM_NCMBUTTONUP);\n\t\tCASE_STR(WM_NCMBUTTONDBLCLK);\n\t\tCASE_STR(WM_NCXBUTTONDOWN);\n\t\tCASE_STR(WM_NCXBUTTONUP);\n\t\tCASE_STR(WM_NCXBUTTONDBLCLK);\n\t\tCASE_STR(WM_INPUT);\n\t\tCASE_STR(WM_KEYDOWN);\n\t\tCASE_STR(WM_KEYUP);\n\t\tCASE_STR(WM_CHAR);\n\t\tCASE_STR(WM_DEADCHAR);\n\t\tCASE_STR(WM_SYSKEYDOWN);\n\t\tCASE_STR(WM_SYSKEYUP);\n\t\tCASE_STR(WM_SYSCHAR);\n\t\tCASE_STR(WM_SYSDEADCHAR);\n\t\tCASE_STR(WM_KEYLAST);\n\t\tCASE_STR(WM_IME_STARTCOMPOSITION);\n\t\tCASE_STR(WM_IME_ENDCOMPOSITION);\n\t\tCASE_STR(WM_IME_COMPOSITION);\n\t\tCASE_STR(WM_INITDIALOG);\n\t\tCASE_STR(WM_COMMAND);\n\t\tCASE_STR(WM_SYSCOMMAND);\n\t\tCASE_STR(WM_TIMER);\n\t\tCASE_STR(WM_HSCROLL);\n\t\tCASE_STR(WM_VSCROLL);\n\t\tCASE_STR(WM_INITMENU);\n\t\tCASE_STR(WM_INITMENUPOPUP);\n\t\tCASE_STR(WM_GESTURE);\n\t\tCASE_STR(WM_GESTURENOTIFY);\n\t\tCASE_STR(WM_MENUSELECT);\n\t\tCASE_STR(WM_MENUCHAR);\n\t\tCASE_STR(WM_ENTERIDLE);\n\t\tCASE_STR(WM_UNINITMENUPOPUP);\n\t\tCASE_STR(WM_CHANGEUISTATE);\n\t\tCASE_STR(WM_UPDATEUISTATE);\n\t\tCASE_STR(WM_QUERYUISTATE);\n\t\tCASE_STR(WM_CTLCOLORMSGBOX);\n\t\tCASE_STR(WM_CTLCOLOREDIT);\n\t\tCASE_STR(WM_CTLCOLORLISTBOX);\n\t\tCASE_STR(WM_CTLCOLORBTN);\n\t\tCASE_STR(WM_CTLCOLORDLG);\n\t\tCASE_STR(WM_CTLCOLORSCROLLBAR);\n\t\tCASE_STR(WM_CTLCOLORSTATIC);\n\t\tCASE_STR(WM_MOUSEMOVE);\n\t\tCASE_STR(WM_LBUTTONDOWN);\n\t\tCASE_STR(WM_LBUTTONUP);\n\t\tCASE_STR(WM_LBUTTONDBLCLK);\n\t\tCASE_STR(WM_RBUTTONDOWN);\n\t\tCASE_STR(WM_RBUTTONUP);\n\t\tCASE_STR(WM_RBUTTONDBLCLK);\n\t\tCASE_STR(WM_MBUTTONDOWN);\n\t\tCASE_STR(WM_MBUTTONUP);\n\t\tCASE_STR(WM_MBUTTONDBLCLK);\n\t\tCASE_STR(WM_MOUSEWHEEL);\n\t\tCASE_STR(WM_XBUTTONDOWN);\n\t\tCASE_STR(WM_XBUTTONUP);\n\t\tCASE_STR(WM_XBUTTONDBLCLK);\n\t\tCASE_STR(WM_MOUSEHWHEEL);\n\t\tCASE_STR(WM_PARENTNOTIFY);\n\t\tCASE_STR(WM_ENTERMENULOOP);\n\t\tCASE_STR(WM_EXITMENULOOP);\n\t\tCASE_STR(WM_NEXTMENU);\n\t\tCASE_STR(WM_SIZING);\n\t\tCASE_STR(WM_CAPTURECHANGED);\n\t\tCASE_STR(WM_MOVING);\n\t\tCASE_STR(WM_POWERBROADCAST);\n\t\tCASE_STR(WM_DEVICECHANGE);\n\t\tCASE_STR(WM_POINTERDEVICECHANGE);\n\t\tCASE_STR(WM_POINTERDEVICEINRANGE);\n\t\tCASE_STR(WM_POINTERDEVICEOUTOFRANGE);\n\t\tCASE_STR(WM_POINTERUPDATE);\n\t\tCASE_STR(WM_POINTERDOWN);\n\t\tCASE_STR(WM_POINTERUP);\n\t\tCASE_STR(WM_POINTERENTER);\n\t\tCASE_STR(WM_POINTERLEAVE);\n\t\tCASE_STR(WM_POINTERACTIVATE);\n\t\tCASE_STR(WM_POINTERCAPTURECHANGED);\n\t\tCASE_STR(WM_IME_SETCONTEXT);\n\t\tCASE_STR(WM_IME_NOTIFY);\n\t\tCASE_STR(WM_IME_CONTROL);\n\t\tCASE_STR(WM_IME_COMPOSITIONFULL);\n\t\tCASE_STR(WM_IME_SELECT);\n\t\tCASE_STR(WM_IME_CHAR);\n\t\tCASE_STR(WM_IME_REQUEST);\n\t\tCASE_STR(WM_IME_KEYDOWN);\n\t\tCASE_STR(WM_IME_KEYUP);\n\t\tCASE_STR(WM_MDICREATE);\n\t\tCASE_STR(WM_MDIDESTROY);\n\t\tCASE_STR(WM_MDIACTIVATE);\n\t\tCASE_STR(WM_MDIRESTORE);\n\t\tCASE_STR(WM_MDINEXT);\n\t\tCASE_STR(WM_MDIMAXIMIZE);\n\t\tCASE_STR(WM_MDITILE);\n\t\tCASE_STR(WM_MDICASCADE);\n\t\tCASE_STR(WM_MDIICONARRANGE);\n\t\tCASE_STR(WM_MDIGETACTIVE);\n\t\tCASE_STR(WM_MDISETMENU);\n\t\tCASE_STR(WM_ENTERSIZEMOVE);\n\t\tCASE_STR(WM_EXITSIZEMOVE);\n\t\tCASE_STR(WM_DROPFILES);\n\t\tCASE_STR(WM_MDIREFRESHMENU);\n\t\tCASE_STR(WM_MOUSEHOVER);\n\t\tCASE_STR(WM_NCMOUSELEAVE);\n\t\tCASE_STR(WM_MOUSELEAVE);\n\t\tCASE_STR(WM_WTSSESSION_CHANGE);\n\t\tCASE_STR(WM_DPICHANGED);\n\t\tCASE_STR(WM_DPICHANGED_BEFOREPARENT);\n\t\tCASE_STR(WM_DPICHANGED_AFTERPARENT);\n\t\tCASE_STR(WM_CUT);\n\t\tCASE_STR(WM_COPY);\n\t\tCASE_STR(WM_PASTE);\n\t\tCASE_STR(WM_CLEAR);\n\t\tCASE_STR(WM_UNDO);\n\t\tCASE_STR(WM_RENDERFORMAT);\n\t\tCASE_STR(WM_RENDERALLFORMATS);\n\t\tCASE_STR(WM_DESTROYCLIPBOARD);\n\t\tCASE_STR(WM_DRAWCLIPBOARD);\n\t\tCASE_STR(WM_PAINTCLIPBOARD);\n\t\tCASE_STR(WM_VSCROLLCLIPBOARD);\n\t\tCASE_STR(WM_SIZECLIPBOARD);\n\t\tCASE_STR(WM_ASKCBFORMATNAME);\n\t\tCASE_STR(WM_CHANGECBCHAIN);\n\t\tCASE_STR(WM_HSCROLLCLIPBOARD);\n\t\tCASE_STR(WM_QUERYNEWPALETTE);\n\t\tCASE_STR(WM_PALETTEISCHANGING);\n\t\tCASE_STR(WM_PALETTECHANGED);\n\t\tCASE_STR(WM_HOTKEY);\n\t\tCASE_STR(WM_PRINT);\n\t\tCASE_STR(WM_PRINTCLIENT);\n\t\tCASE_STR(WM_APPCOMMAND);\n\t\tCASE_STR(WM_THEMECHANGED);\n\t\tCASE_STR(WM_DWMCOMPOSITIONCHANGED);\n\t\tCASE_STR(WM_DWMNCRENDERINGCHANGED);\n\t\tCASE_STR(WM_DWMCOLORIZATIONCOLORCHANGED);\n\t\tCASE_STR(WM_DWMWINDOWMAXIMIZEDCHANGE);\n\t\tCASE_STR(WM_HANDHELDFIRST);\n\t\tCASE_STR(WM_HANDHELDLAST);\n\t\tCASE_STR(WM_AFXFIRST);\n\t\tCASE_STR(WM_AFXLAST);\n\t\tCASE_STR(WM_PENWINFIRST);\n\t\tCASE_STR(WM_PENWINLAST);\n\t\tCASE_STR(WM_DWMSENDICONICTHUMBNAIL);\n\t\tCASE_STR(WM_DWMSENDICONICLIVEPREVIEWBITMAP);\n\t\tCASE_STR(WM_USER);\n\t\tCASE_STR(WM_APP);\n\t\tcase 0x0118: return L\"WM_SYSTIMER\";\n\t\tdefault:\n\t\t\tif (msg > WM_USER && msg < WM_APP) {\n\t\t\t\tCString text;\n\t\t\t\ttext.Format(L\"WM_USER + %d\", msg - WM_USER);\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tif (msg > WM_APP) {\n\t\t\t\tCString text;\n\t\t\t\ttext.Format(L\"WM_APP + %d\", msg - WM_APP);\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn L\"\";\n}\n\nULONG_PTR WindowHelper::GetID(HWND hWnd) {\n\treturn ::GetWindowLongPtr(hWnd, GWLP_ID);\n}\n\nULONG_PTR WindowHelper::GetUserData(HWND hWnd) {\n\treturn ::GetWindowLongPtr(hWnd, GWLP_USERDATA);\n}\n\n"
  },
  {
    "path": "WinSpy/WindowHelper.h",
    "content": "#pragma once\n\nstruct WindowItem {\n\tHWND hWnd;\n\tDWORD ThreadId;\n\tDWORD ProcessId;\n\tCString ProcessName;\n};\n\nstruct StyleItem {\n\tDWORD Value;\n\tPCWSTR Text;\n\tDWORD Mask{ Value };\n};\n\nstruct WindowHelper abstract final {\n\tstatic CString WindowStyleToString(HWND hWnd);\n\tstatic CString ClassStyleToString(HWND hWnd);\n\tstatic CString WindowExtendedStyleToString(HWND hWnd);\n\tstatic CString WindowRectToString(HWND hWnd);\n\tstatic CString GetWindowClassName(HWND hWnd);\n\tstatic CString GetWindowText(HWND hWnd);\n\tstatic HICON GetWindowIcon(HWND hWnd);\n\tstatic HICON GetWindowOrProcessIcon(HWND hWnd);\n\tstatic bool Flash(HWND hWnd);\n\tstatic void HighlightBorder(HWND hWnd, bool highlight = true);\n\tstatic CString GetWindowClassAndTitle(HWND hWnd);\n\tstatic std::unordered_map<HWND, int>& GetIconMap();\n\tstatic CImageList& GetImageList();\n\tstatic WindowItem GetWindowInfo(HWND hWnd);\n\tstatic bool ThreadHasWindows(DWORD tid);\n\tstatic int ShowWindowProperties(HWND hWnd);\n\tstatic CString WindowMessageToString(DWORD msg);\n\tstatic ULONG_PTR GetID(HWND hWnd);\n\tstatic ULONG_PTR GetUserData(HWND hWnd);\n\n\tstatic std::pair<StyleItem const*, int> GetWindowStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetListViewStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetTreeViewStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetTabCtrlStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetWindowStyleExArray();\n\tstatic std::pair<StyleItem const*, int> GetClassStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetEditStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetListBoxStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetComboBoxStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetHeaderStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetButtonStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetStaticStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetToolTipStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetStatusBarStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetToolBarStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetRebarStyleArray();\n\tstatic std::pair<StyleItem const*, int> GetScrollBarStyleArray();\n};\n\n\n"
  },
  {
    "path": "WinSpy/WindowWindowsPage.cpp",
    "content": "#include \"pch.h\"\n#include \"resource.h\"\n#include \"WindowWindowsPage.h\"\n#include \"FormatHelper.h\"\n\nconst UINT WM_UPDATE = WM_USER + 300;\n\nvoid CWindowWindowsPage::UpdateData() {\n    const struct {\n        CWindow win;\n        UINT idHandle, idClass, idText;\n    } windows[] = {\n        { m_Win.GetParent(), IDC_HANDLE, IDC_CLASS, IDC_TEXT },\n        { m_Win.GetWindow(GW_HWNDNEXT), IDC_HANDLE2, IDC_CLASS2, IDC_TEXT2 },\n        { m_Win.GetWindow(GW_HWNDPREV), IDC_HANDLE3, IDC_CLASS3, IDC_TEXT3 },\n        { m_Win.GetWindow(GW_CHILD), IDC_HANDLE4, IDC_CLASS4, IDC_TEXT4 },\n    };\n\n    CString text;\n    for (auto& item : windows) {\n        if (!::IsWindow(item.win.m_hWnd)) {\n            SetDlgItemText(item.idHandle, L\"(none)    \");\n            continue;\n        }\n        text.Format(L\"<a>0x%zX</a>\", (ULONG_PTR)item.win.m_hWnd);\n        SetDlgItemText(item.idHandle, text);\n        if (::GetClassName(item.win, text.GetBufferSetLength(128), 128))\n            SetDlgItemText(item.idClass, text);\n        item.win.GetWindowText(text);\n        SetDlgItemText(item.idText, text);\n    }\n}\n\nLRESULT CWindowWindowsPage::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) {\n    UpdateData();\n\n    return 0;\n}\n\nLRESULT CWindowWindowsPage::OnClickHandle(int, LPNMHDR hdr, BOOL&) {\n    auto id = (UINT)hdr->idFrom;\n    CString text;\n    GetDlgItemText(id, text);\n    auto hWnd = (HWND)FormatHelper::ParseHex(text.Mid(3, text.GetLength() - 6));\n    m_Win.Detach();\n    m_Win.Attach(hWnd);\n    UpdateData();\n    GetParent().SendMessageToDescendants(WM_UPDATE, 0, reinterpret_cast<LPARAM>(hWnd));\n    return 0;\n}\n\n"
  },
  {
    "path": "WinSpy/WindowWindowsPage.h",
    "content": "#pragma once\n\n#include \"DialogHelper.h\"\n\nclass CWindowWindowsPage :\n\tpublic CDialogHelper<CWindowWindowsPage>,\n\tpublic CPropertyPageImpl<CWindowWindowsPage> {\npublic:\n\tenum { IDD = IDD_PROPWINDOWS };\n\n\tCWindowWindowsPage(HWND hWnd) : m_Win(hWnd) {\n\t\tm_psp.dwFlags |= PSP_USEICONID;\n\t\tm_psp.pszIcon = MAKEINTRESOURCE(IDI_WINDOWS);\n\t}\n\nprotected:\n\tBEGIN_MSG_MAP(CWindowWindowsPage)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tNOTIFY_CODE_HANDLER(NM_CLICK, OnClickHandle)\n\t\tNOTIFY_CODE_HANDLER(NM_RETURN, OnClickHandle)\n\tEND_MSG_MAP()\n\nprivate:\n\tvoid UpdateData();\n\n\t//\tLRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t//\tLRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t//\tLRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnClickHandle(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\n\tCWindow m_Win;\n};\n"
  },
  {
    "path": "WinSpy/WindowsListView.cpp",
    "content": "#include \"pch.h\"\n#include \"resource.h\"\n#include \"WindowsListView.h\"\n#include \"FormatHelper.h\"\n#include \"SortHelper.h\"\n#include \"ProcessHelper.h\"\n\nvoid CWindowsListView::SetSelectedHwnd(HWND hWnd) {\n\tm_SelectedHwnd.Detach();\n\tm_SelectedHwnd.Attach(hWnd);\n}\n\nLRESULT CWindowsListView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) {\n\tm_hWndClient = m_List.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN\n\t\t| LVS_REPORT | LVS_OWNERDATA | LVS_SINGLESEL | LVS_SHAREIMAGELISTS, 0);\n\tm_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP);\n\tm_List.SetImageList(WindowHelper::GetImageList(), LVSIL_SMALL);\n\n\tauto cm = GetColumnManager(m_List);\n\n\tstruct {\n\t\tPCWSTR text;\n\t\tDataItemType type;\n\t\tint width = 100;\n\t\tint format = LVCFMT_LEFT;\n\t\tColumnFlags flags = ColumnFlags::Visible;\n\t} columns[] = {\n\t\t{ L\"Class Name\", DataItemType::ClassName, 140 },\n\t\t{ L\"Handle\", DataItemType::Handle, 80, LVCFMT_RIGHT },\n\t\t{ L\"Text\", DataItemType::Text, 150 },\n\t\t{ L\"Style\", DataItemType::Style, 80, LVCFMT_RIGHT },\n\t\t{ L\"Ex Style\", DataItemType::ExtendedStyle, 80, LVCFMT_RIGHT },\n\t\t{ L\"PID\", DataItemType::ProcessId, 70, LVCFMT_RIGHT },\n\t\t{ L\"Process Name\", DataItemType::ProcessName, 120 },\n\t\t{ L\"TID\", DataItemType::ThreadId, 70, LVCFMT_RIGHT },\n\t\t{ L\"Rectangle\", DataItemType::Rectangle, 170, LVCFMT_LEFT, ColumnFlags::None },\n\t\t{ L\"Parent HWND\", DataItemType::ParentWindow, 100, LVCFMT_RIGHT, ColumnFlags::Fixed | ColumnFlags::Visible },\n\t\t{ L\"Owner HWND\", DataItemType::OwnerWindow, 100, LVCFMT_RIGHT, ColumnFlags::Fixed | ColumnFlags::Visible },\n\t\t{ L\"Next HWND\", DataItemType::NextWindow, 100, LVCFMT_RIGHT, ColumnFlags::Fixed | ColumnFlags::Visible },\n\t\t{ L\"Prev HWND\", DataItemType::PrevWindow, 100, LVCFMT_RIGHT, ColumnFlags::Fixed | ColumnFlags::Visible },\n\t\t{ L\"Child HWND\", DataItemType::FirstChildWindow, 100, LVCFMT_RIGHT, ColumnFlags::Fixed | ColumnFlags::Visible },\n\t\t{ L\"WndProc\", DataItemType::WindowProc, 100, LVCFMT_RIGHT, ColumnFlags::Fixed },\n\t\t{ L\"User Data\", DataItemType::UserData, 100, LVCFMT_RIGHT },\n\t\t{ L\"ID\", DataItemType::ID, 80, LVCFMT_RIGHT },\n\t\t{ L\"Class Atom\", DataItemType::ClassAtom, 90, LVCFMT_RIGHT },\n\t\t{ L\"Class Style\", DataItemType::ClassStyle, 80, LVCFMT_RIGHT, ColumnFlags::Fixed },\n\t\t{ L\"Class Extra Bytes\", DataItemType::ClassExtra, 70, LVCFMT_RIGHT, ColumnFlags::Fixed },\n\t\t{ L\"Window Extra Bytes\", DataItemType::WindowExtra, 70, LVCFMT_RIGHT, ColumnFlags::Fixed },\n\t};\n\n\tfor (auto& col : columns) {\n\t\tcm->AddColumn(col.text, col.format, col.width, col.type, col.flags);\n\t}\n\n\tcm->UpdateColumns();\n\n\n    return 0;\n}\n\nLRESULT CWindowsListView::OnWindowShow(WORD, WORD, HWND, BOOL&) {\n\tCWindow win(m_Items[m_List.GetSelectionMark()].hWnd);\n\twin.ShowWindowAsync(SW_SHOW);\n\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowHide(WORD, WORD, HWND, BOOL&) {\n\tATLASSERT(m_SelectedHwnd);\n\tm_SelectedHwnd.ShowWindowAsync(SW_HIDE);\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowMinimize(WORD, WORD, HWND, BOOL&) {\n\tCWindow win(m_Items[m_List.GetSelectionMark()].hWnd);\n\twin.ShowWindowAsync(SW_MINIMIZE);\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowMaximize(WORD, WORD, HWND, BOOL&) {\n\tCWindow win(m_Items[m_List.GetSelectionMark()].hWnd);\n\twin.ShowWindowAsync(SW_MAXIMIZE);\n\n\treturn 0;\n}\n\nCString CWindowsListView::GetColumnText(HWND, int row, int col) const {\n\tauto& item = m_Items[row];\n\tif (!::IsWindow(item.hWnd)) {\n\t\treturn L\"\";\n\t}\n\n\tCWindow win(item.hWnd);\n\tauto h = item.hWnd;\n\n\tCString text;\n\tswitch (GetColumnManager(m_List)->GetColumnTag<DataItemType>(col)) {\n\t\tcase DataItemType::Handle:\n\t\t\ttext.Format(L\"0x%zX\", (ULONG_PTR)h);\n\t\t\tbreak;\n\n\t\tcase DataItemType::Style:\n\t\t\ttext.Format(L\"0x%08X\", win.GetStyle());\n\t\t\tbreak;\n\n\t\tcase DataItemType::ProcessId:\n\t\t\ttext.Format(L\"%u\", item.ProcessId);\n\t\t\tbreak;\n\n\t\tcase DataItemType::ProcessName:\n\t\t\treturn item.ProcessName;\n\n\t\tcase DataItemType::ThreadId:\n\t\t\ttext.Format(L\"%u\", item.ThreadId);\n\t\t\tbreak;\n\n\t\tcase DataItemType::Rectangle:\n\t\t\treturn WindowHelper::WindowRectToString(h);\n\n\t\tcase DataItemType::ExtendedStyle:\n\t\t\ttext.Format(L\"0x%08X\", win.GetExStyle());\n\t\t\tbreak;\n\n\t\tcase DataItemType::ClassName:\n\t\t\treturn WindowHelper::GetWindowClassName(h);\n\n\t\tcase DataItemType::Text:\n\t\t\twin.GetWindowText(text);\n\t\t\tif (text.GetLength() > 256)\n\t\t\t\ttext = text.Left(256) + L\"...\";\n\t\t\tbreak;\n\n\t\tcase DataItemType::WindowProc:\n\t\t\ttext.Format(L\"0x%zX\", win.GetWindowLongPtr(GWLP_WNDPROC));\n\t\t\tbreak;\n\n\t\tcase DataItemType::UserData:\n\t\t\ttext.Format(L\"0x%zX\", win.GetWindowLongPtr(GWLP_USERDATA));\n\t\t\tbreak;\n\n\t\tcase DataItemType::ID:\n\t\t\ttext.Format(L\"0x%zX\", win.GetWindowLongPtr(GWLP_ID));\n\t\t\tbreak;\n\n\t\tcase DataItemType::ParentWindow: return FormatHelper::FormatHWndOrNone(::GetAncestor(win, GA_PARENT));\n\t\tcase DataItemType::NextWindow: return FormatHelper::FormatHWndOrNone(win.GetWindow(GW_HWNDNEXT));\n\t\tcase DataItemType::PrevWindow: return FormatHelper::FormatHWndOrNone(win.GetWindow(GW_HWNDPREV));\n\t\tcase DataItemType::OwnerWindow: return FormatHelper::FormatHWndOrNone(win.GetWindow(GW_OWNER));\n\t\tcase DataItemType::FirstChildWindow: return FormatHelper::FormatHWndOrNone(win.GetWindow(GW_CHILD));\n\n\t\tcase DataItemType::ClassAtom:\n\t\t\ttext.Format(L\"0x%04X\", (DWORD)::GetClassLongPtr(win, GCW_ATOM));\n\t\t\tbreak;\n\n\t\tcase DataItemType::ClassStyle:\n\t\t\ttext.Format(L\"0x%04X\", (DWORD)::GetClassLongPtr(win, GCL_STYLE));\n\t\t\tbreak;\n\n\t\tcase DataItemType::ClassExtra:\n\t\t\ttext.Format(L\"%u\", (ULONG)::GetClassLongPtr(win, GCL_CBCLSEXTRA));\n\t\t\tbreak;\n\n\t\tcase DataItemType::WindowExtra:\n\t\t\ttext.Format(L\"%u\", (ULONG)::GetClassLongPtr(win, GCL_CBWNDEXTRA));\n\t\t\tbreak;\n\t}\n\treturn text;\n}\n\nint CWindowsListView::GetRowImage(HWND, int row, int col) const {\n\tauto& item = m_Items[row];\n\tauto h = item.hWnd;\n\tauto& icons = WindowHelper::GetIconMap();\n\tif (auto it = icons.find(h); it != icons.end()) {\n\t\treturn it->second;\n\t}\n\tauto hIcon = WindowHelper::GetWindowIcon(h);\n\tif (hIcon) {\n\t\tint image = WindowHelper::GetImageList().AddIcon(hIcon);\n\t\ticons.insert({ h, image });\n\t\treturn image;\n\t}\n\treturn 0;\n}\n\nvoid CWindowsListView::DoSort(const SortInfo* si) {\n\tif (si == nullptr)\n\t\treturn;\n\n\tstd::sort(m_Items.begin(), m_Items.end(), [&](const auto& h1, const auto& h2) -> bool {\n\t\tswitch (GetColumnManager(m_List)->GetColumnTag<DataItemType>(si->SortColumn)) {\n\t\t\tcase DataItemType::ClassName: return SortHelper::Sort(WindowHelper::GetWindowClassName(h1.hWnd), WindowHelper::GetWindowClassName(h2.hWnd), si->SortAscending);\n\t\t\tcase DataItemType::Text: return SortHelper::Sort(WindowHelper::GetWindowText(h1.hWnd), WindowHelper::GetWindowText(h2.hWnd), si->SortAscending);\n\t\t\tcase DataItemType::Handle: return SortHelper::Sort(h1.hWnd, h2.hWnd, si->SortAscending);\n\t\t\tcase DataItemType::FirstChildWindow: return SortHelper::Sort(::GetWindow(h1.hWnd, GW_CHILD), ::GetWindow(h2.hWnd, GW_CHILD), si->SortAscending);\n\t\t\tcase DataItemType::PrevWindow: return SortHelper::Sort(::GetWindow(h1.hWnd, GW_HWNDPREV), ::GetWindow(h2.hWnd, GW_HWNDPREV), si->SortAscending);\n\t\t\tcase DataItemType::NextWindow: return SortHelper::Sort(::GetWindow(h1.hWnd, GW_HWNDNEXT), ::GetWindow(h2.hWnd, GW_HWNDNEXT), si->SortAscending);\n\t\t\tcase DataItemType::OwnerWindow: return SortHelper::Sort(::GetWindow(h1.hWnd, GW_OWNER), ::GetWindow(h2.hWnd, GW_OWNER), si->SortAscending);\n\t\t\tcase DataItemType::ParentWindow: return SortHelper::Sort(::GetParent(h1.hWnd), ::GetParent(h2.hWnd), si->SortAscending);\n\t\t\tcase DataItemType::Style: return SortHelper::Sort(CWindow(h1.hWnd).GetStyle(), CWindow(h2.hWnd).GetStyle(), si->SortAscending);\n\t\t\tcase DataItemType::ExtendedStyle: return SortHelper::Sort(CWindow(h1.hWnd).GetExStyle(), CWindow(h2.hWnd).GetExStyle(), si->SortAscending);\n\t\t\tcase DataItemType::ThreadId: return SortHelper::Sort(h1.ThreadId, h2.ThreadId, si->SortAscending);\n\t\t\tcase DataItemType::ProcessId: return SortHelper::Sort(h1.ProcessId, h2.ProcessId, si->SortAscending);\n\t\t\tcase DataItemType::ProcessName: return SortHelper::Sort(h1.ProcessName, h2.ProcessName, si->SortAscending);\n\t\t\tcase DataItemType::ID: return SortHelper::Sort(WindowHelper::GetID(h1.hWnd), WindowHelper::GetID(h2.hWnd), si->SortAscending);\n\t\t\tcase DataItemType::UserData: return SortHelper::Sort(WindowHelper::GetUserData(h1.hWnd), WindowHelper::GetUserData(h2.hWnd), si->SortAscending);\n\t\t}\n\t\treturn false;\n\t\t});\n}\n\nbool CWindowsListView::OnRightClickList(HWND, int row, int col, CPoint const& pt) {\n\tCMenu menu;\n\tmenu.LoadMenu(IDR_CONTEXT);\n\tm_ContextMenuOpen = true;\n\tauto cmd = m_pFrame->ShowPopupMenu(menu.GetSubMenu(0), pt, TPM_RETURNCMD);\n\tm_ContextMenuOpen = false;\n\tif (cmd) {\n\t\tLRESULT result;\n\t\treturn ProcessWindowMessage(m_hWnd, WM_COMMAND, cmd, 0, result, 1);\n\t}\n\treturn false;\n}\n\nbool CWindowsListView::IsSortable(HWND, int col) const {\n\treturn true;\n}\n\nDWORD CWindowsListView::OnPrePaint(int, LPNMCUSTOMDRAW cd) {\n\tif (cd->hdr.hwndFrom == m_List)\n\t\treturn CDRF_NOTIFYITEMDRAW;\n\n\treturn CDRF_DODEFAULT;\n}\n\nDWORD CWindowsListView::OnItemPrePaint(int, LPNMCUSTOMDRAW cd) {\n\tATLASSERT(cd->hdr.hwndFrom == m_List);\n\n\tauto& h = m_Items[(int)cd->dwItemSpec];\n\tauto lv = (LPNMLVCUSTOMDRAW)cd;\n\tlv->clrTextBk = m_SelectedHwnd == nullptr || ::IsWindowVisible(h.hWnd) ? CLR_INVALID : RGB(224, 224, 224);\n\n\treturn CDRF_DODEFAULT;\n}\n\nvoid CWindowsListView::AddMessageOnlyWindows() {\n\tHWND hWnd = nullptr;\n\tfor (;;) {\n\t\thWnd = ::FindWindowEx(HWND_MESSAGE, hWnd, nullptr, nullptr);\n\t\tif (!hWnd)\n\t\t\tbreak;\n\t\t\n\t\tm_Items.push_back(WindowHelper::GetWindowInfo(hWnd));\n\t}\n}\n\nvoid CWindowsListView::UpdateList(HWND hWnd) {\n\tif (m_ContextMenuOpen)\n\t\treturn;\n\n\tm_Items.clear();\n\tm_SelectedHwnd = hWnd;\n\tif (hWnd == nullptr) {\n\t\t//\n\t\t// message only windows\n\t\t//\n\t\tAddMessageOnlyWindows();\n\t}\n\telse {\n\t\tm_Items.push_back(WindowHelper::GetWindowInfo(m_SelectedHwnd));\n\t\tAddChildWindows(m_Items, m_SelectedHwnd, true);\n\t}\n\tm_List.SetItemCountEx((int)m_Items.size(), LVSICF_NOSCROLL);\n\tUpdateList();\n}\n\nvoid CWindowsListView::UpdateListByThread(DWORD tid) {\n\tm_SelectedHwnd.Detach();\n\tm_Items.clear();\n\tAddThreadWindows(tid);\n\n\tm_List.SetItemCountEx((int)m_Items.size(), LVSICF_NOSCROLL);\n\tUpdateList();\n}\n\nvoid CWindowsListView::UpdateListByProcess(ProcessInfo const& pi) {\n\tm_Items.clear();\n\tfor (auto tid : pi.Threads)\n\t\tAddThreadWindows(tid);\n\n\tm_List.SetItemCountEx((int)m_Items.size(), LVSICF_NOSCROLL);\n\tUpdateList();\n}\n\nvoid CWindowsListView::UpdateUI(CUpdateUIBase& ui) {\n\tif (::GetFocus() != m_List)\n\t\treturn;\n\n\tint first = m_List.GetSelectionMark();\n\tint selected = m_List.GetSelectedCount();\n\tui.UIEnable(ID_WINDOW_PROPERTIES, selected == 1);\n}\n\nvoid CWindowsListView::AddThreadWindows(DWORD tid) {\n\t::EnumThreadWindows(tid, [](auto hWnd, auto param) {\n\t\tauto p = reinterpret_cast<CWindowsListView*>(param);\n\t\tp->m_Items.push_back(WindowHelper::GetWindowInfo(hWnd));\n\t\treturn TRUE;\n\t\t}, reinterpret_cast<LPARAM>(this));\n}\n\nvoid CWindowsListView::Refresh() {\n}\n\nvoid CWindowsListView::AddChildWindows(std::vector<WindowItem>& v, HWND hParent, bool directOnly) {\n\tstruct LocalInfo {\n\t\tstd::vector<WindowItem>& v;\n\t\tCWindowsListView* pThis;\n\t\tbool directOnly;\n\t};\n\n\tLocalInfo info{ v, this, directOnly };\n\n\t::EnumChildWindows(hParent, [](auto hWnd, auto param) {\n\t\tauto info = reinterpret_cast<LocalInfo*>(param);\n\t\tif (info->pThis->m_ShowHiddenWindows || ::IsWindowVisible(hWnd)) {\n\t\t\tinfo->v.push_back(WindowHelper::GetWindowInfo(hWnd));\n\t\t\tif (!info->directOnly)\n\t\t\t\tinfo->pThis->AddChildWindows(info->v, hWnd, false);\n\t\t}\n\t\treturn TRUE;\n\t\t}, reinterpret_cast<LPARAM>(&info));\n}\n\nCString CWindowsListView::GetDetails(const DataItem& item) const {\n\tCString text;\n\tswitch (item.Type) {\n\t\tcase DataItemType::ProcessId:\n\t\t{\n\t\t\tDWORD pid = 0;\n\t\t\t::GetWindowThreadProcessId(m_SelectedHwnd, &pid);\n\t\t\treturn ProcessHelper::GetProcessImageName(pid);\n\t\t}\n\n\t\tcase DataItemType::Text:\n\t\t\ttext.Format(L\"Length: %d\", m_SelectedHwnd.GetWindowTextLength());\n\t\t\tbreak;\n\n\t\t\treturn WindowHelper::WindowStyleToString(m_SelectedHwnd);\n\t\tcase DataItemType::Style: return WindowHelper::WindowStyleToString(m_SelectedHwnd);\n\t\tcase DataItemType::ClassStyle: return WindowHelper::ClassStyleToString(m_SelectedHwnd);\n\t\tcase DataItemType::ExtendedStyle: return WindowHelper::WindowExtendedStyleToString(m_SelectedHwnd);\n\t\tcase DataItemType::Rectangle:\n\t\t\tif (m_SelectedHwnd.IsZoomed())\n\t\t\t\treturn L\"Maximized\";\n\t\t\tif (m_SelectedHwnd.IsIconic())\n\t\t\t\treturn L\"Minimized\";\n\t\t\tbreak;\n\t\tcase DataItemType::NextWindow: return WindowHelper::GetWindowClassAndTitle(m_SelectedHwnd.GetWindow(GW_HWNDNEXT));\n\t\tcase DataItemType::PrevWindow: return WindowHelper::GetWindowClassAndTitle(m_SelectedHwnd.GetWindow(GW_HWNDPREV));\n\t\tcase DataItemType::OwnerWindow: return WindowHelper::GetWindowClassAndTitle(m_SelectedHwnd.GetWindow(GW_OWNER));\n\t\tcase DataItemType::ParentWindow: return WindowHelper::GetWindowClassAndTitle(::GetAncestor(m_SelectedHwnd, GA_PARENT));\n\t\tcase DataItemType::FirstChildWindow: return WindowHelper::GetWindowClassAndTitle(m_SelectedHwnd.GetWindow(GW_CHILD));\n\t}\n\treturn text;\n}\n\nvoid CWindowsListView::UpdateList() {\n\tDoSort(GetSortInfo(m_List));\n\tm_List.RedrawItems(m_List.GetTopIndex(), m_List.GetCountPerPage() + m_List.GetTopIndex());\n}\n\nLRESULT CWindowsListView::OnToggleEmptyTitleWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowNoTitleWindows = !m_ShowNoTitleWindows;\n\tUpdateList(m_SelectedHwnd);\n\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnToggleChildWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowChildWindows = !m_ShowChildWindows;\n\tUpdateList(m_SelectedHwnd);\n\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowRestore(WORD, WORD, HWND, BOOL&) {\n\tCWindow win(m_Items[m_List.GetSelectionMark()].hWnd);\n\twin.ShowWindowAsync(SW_RESTORE);\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowBringToFront(WORD, WORD, HWND, BOOL&) {\n\tCWindow win(m_Items[m_List.GetSelectionMark()].hWnd);\n\twin.BringWindowToTop();\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowProperties(WORD, WORD, HWND, BOOL&) {\n\tauto& item = m_Items[m_List.GetSelectionMark()];\n\tWindowHelper::ShowWindowProperties(item.hWnd);\n\treturn LRESULT();\n}\n\nLRESULT CWindowsListView::OnItemChanged(int, LPNMHDR, BOOL&) {\n\tUpdateUI(m_pFrame->GetUIUpdate());\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnWindowFlash(WORD, WORD, HWND, BOOL&) {\n\tauto& item = m_Items[m_List.GetSelectionMark()];\n\tWindowHelper::Flash(item.hWnd);\n\n\treturn 0;\n}\n\nLRESULT CWindowsListView::OnToggleHiddenWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowHiddenWindows = !m_ShowHiddenWindows;\n\tUpdateList(m_SelectedHwnd);\n\n\treturn 0;\n}\n\nbool CWindowsListView::OnDoubleClickList(HWND, int row, int col, CPoint const&) {\n\tif (row >= 0) {\n\t\tWindowHelper::ShowWindowProperties(m_Items[row].hWnd);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n"
  },
  {
    "path": "WinSpy/WindowsListView.h",
    "content": "#pragma once\n\n#include <VirtualListView.h>\n#include \"Interfaces.h\"\n#include \"WindowHelper.h\"\n#include \"ProcessHelper.h\"\n\nclass CWindowsListView : \n\tpublic CFrameWindowImpl<CWindowsListView, CWindow, CControlWinTraits>,\n\tpublic CVirtualListView<CWindowsListView>,\n\tpublic CCustomDraw<CWindowsListView> {\npublic:\n\tusing BaseFrame = CFrameWindowImpl<CWindowsListView, CWindow, CControlWinTraits>;\n\n\tCWindowsListView(IMainFrame* frame) : m_pFrame(frame) {}\n\n\tCString GetColumnText(HWND, int row, int col) const;\n\tint GetRowImage(HWND, int row, int col) const;\n\tbool IsSortable(HWND, int col) const;\n\tvoid DoSort(const SortInfo* si);\n\tbool OnRightClickList(HWND, int row, int col, CPoint const&);\n\tbool OnDoubleClickList(HWND, int row, int col, CPoint const&);\n\n\tDWORD OnPrePaint(int, LPNMCUSTOMDRAW cd);\n\tDWORD OnItemPrePaint(int, LPNMCUSTOMDRAW cd);\n\n\tvoid SetSelectedHwnd(HWND hWnd);\n\tvoid UpdateList(HWND hWnd);\n\tvoid UpdateListByThread(DWORD tid);\n\tvoid UpdateListByProcess(ProcessInfo const& pi);\n\tvoid UpdateUI(CUpdateUIBase& ui);\n\n\tvoid Refresh();\n\n\tenum class DataItemType {\n\t\tHandle, ClassName, Text, Style, ExtendedStyle, ProcessName,\n\t\tProcessId, ThreadId, ParentWindow, FirstChildWindow, NextWindow, PrevWindow, OwnerWindow,\n\t\tWindowProc, UserData, ID, Rectangle,\n\t\tClassAtom, ClassStyle, ClassExtra, WindowExtra,\n\t};\n\tstruct DataItem {\n\t\tCString Property;\n\t\tDataItemType Type;\n\t};\n\nprotected:\n\tBEGIN_MSG_MAP(CWindowsListView)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tNOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnItemChanged)\n\t\tCHAIN_MSG_MAP(CVirtualListView<CWindowsListView>)\n\t\tCHAIN_MSG_MAP(CCustomDraw<CWindowsListView>)\n\t\tCHAIN_MSG_MAP(BaseFrame)\n\n\tALT_MSG_MAP(1)\n\t\tif (::GetFocus() != m_List)\n\t\t\treturn FALSE;\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_SHOW, OnWindowShow)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_HIDE, OnWindowHide)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_BRINGTOFRONT, OnWindowBringToFront)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MINIMIZE, OnWindowMinimize)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MAXIMIZE, OnWindowMaximize)\n\t\tCOMMAND_ID_HANDLER(ID_STATE_FLASH, OnWindowFlash)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_RESTORE, OnWindowRestore)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_HIDDENWINDOWS, OnToggleHiddenWindows)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_EMPTYTITLEWINDOWS, OnToggleEmptyTitleWindows)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_CHILDWINDOWS, OnToggleChildWindows)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_PROPERTIES, OnWindowProperties)\n\tEND_MSG_MAP()\n\nprivate:\n\tvoid AddChildWindows(std::vector<WindowItem>& v, HWND hParent, bool directOnly);\n\tvoid AddThreadWindows(DWORD tid);\n\tCString GetDetails(const DataItem& item) const;\n\tvoid UpdateList();\n\tvoid AddMessageOnlyWindows();\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowShow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowHide(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowMinimize(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowMaximize(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowRestore(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowFlash(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleHiddenWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleEmptyTitleWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleChildWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowBringToFront(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\nprivate:\n\n\tCListViewCtrl m_List;\n\tstd::vector<WindowItem> m_Items;\n\tDWORD m_TotalWindows, m_TotalVisibleWindows, m_TopLevelWindows;\n\tCWindow m_SelectedHwnd;\n\tIMainFrame* m_pFrame;\n\tbool m_ShowHiddenWindows : 1 { false };\n\tbool m_ShowNoTitleWindows : 1 { true };\n\tbool m_ShowChildWindows : 1 { true };\n\tbool m_Deleting : 1{ false };\n\tbool m_ContextMenuOpen : 1{ false };\n};\n"
  },
  {
    "path": "WinSpy/WindowsView.cpp",
    "content": "// View.cpp : implementation of the CWindowsView class\n//\n/////////////////////////////////////////////////////////////////////////////\n\n#include \"pch.h\"\n#include \"resource.h\"\n#include \"FormatHelper.h\"\n#include \"WindowsView.h\"\n#include \"ProcessHelper.h\"\n#include \"WindowHelper.h\"\n#include \"SortHelper.h\"\n#include \"MessagesView.h\"\n\n\nBOOL CWindowsView::PreTranslateMessage(MSG* pMsg) {\n\tpMsg;\n\treturn FALSE;\n}\n\nvoid CWindowsView::OnActivate(bool activate) {\n\tif (activate) {\n\t\tUpdateUI();\n\t\tSetTimer(1, 2000, nullptr);\n\t}\n\telse {\n\t\tKillTimer(1);\n\t}\n}\n\nvoid CWindowsView::UpdateUI() {\n\tauto& ui = GetFrame()->GetUIUpdate();\n\tif (::GetFocus() == m_Tree) {\n\t\tui.UISetCheck(ID_VIEW_HIDDENWINDOWS, m_ShowHiddenWindows);\n\t\tui.UISetCheck(ID_VIEW_EMPTYTITLEWINDOWS, m_ShowNoTitleWindows);\n\t\tui.UIEnable(ID_WINDOW_PROPERTIES, m_SelectedHwnd != nullptr);\n\t\t//ui.UISetCheck(ID_VIEW_CHILDWINDOWS, m_ShowChildWindows);\n\t}\n\telse {\n\t\tm_WindowsView.UpdateUI(ui);\n\t}\n}\n\nvoid CWindowsView::Refresh() {\n\tif (m_SelectedHwnd != nullptr && !m_SelectedHwnd.IsWindow()) {\n\t\tm_Tree.DeleteItem(m_Selected);\n\t\treturn;\n\t}\n\tm_WindowsView.UpdateList(m_SelectedHwnd);\n}\n\nLRESULT CWindowsView::OnRefreshAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tInitTree();\n\treturn 0;\n}\n\nvoid CWindowsView::InitTree() {\n\tm_TotalVisibleWindows = m_TotalWindows = m_TopLevelWindows = 0;\n\tm_DesktopNode = nullptr;\n\tHWND hDesktop = ::GetDesktopWindow();\n\tif (!hDesktop)\n\t\treturn;\n\n\tCWaitCursor wait;\n\n\tm_Tree.LockWindowUpdate(TRUE);\n\tm_Deleting = true;\n\tm_Tree.DeleteAllItems();\n\tm_WindowMap.clear();\n\tm_Deleting = false;\n\n\tm_DesktopNode = AddNode(hDesktop, TVI_ROOT);\n\n\t::EnumWindows([](auto hWnd, auto lp) -> BOOL {\n\t\tauto pThis = (CWindowsView*)lp;\n\t\tpThis->AddNode(hWnd, pThis->m_DesktopNode);\n\t\treturn TRUE;\n\t\t}, reinterpret_cast<LPARAM>(this));\n\n\tAddMessageOnlyWindows();\n\n\tm_DesktopNode.Expand(TVE_EXPAND);\n\tm_Tree.LockWindowUpdate(FALSE);\n\tm_DesktopNode.Select();\n\tm_DesktopNode.EnsureVisible();\n\tm_Tree.SetScrollPos(SB_HORZ, 0);\n}\n\nvoid CWindowsView::AddChildWindows(HTREEITEM hParent) {\n\tauto hWnd = (HWND)m_Tree.GetItemData(hParent);\n\tATLASSERT(hWnd);\n\n\tm_hCurrentNode = hParent;\n\t::EnumChildWindows(hWnd, [](auto hChild, auto p) -> BOOL {\n\t\tauto pThis = (CWindowsView*)p;\n\t\treturn pThis->AddChildNode(hChild);\n\t\t}, reinterpret_cast<LPARAM>(this));\n\n}\n\nCTreeItem CWindowsView::AddNode(HWND hWnd, HTREEITEM hParent) {\n\tCString text, name;\n\tCWindow win(hWnd);\n\tm_TotalWindows++;\n\tif (win.IsWindowVisible())\n\t\tm_TotalVisibleWindows++;\n\n\tif (m_DesktopNode) {\n\t\tif (::GetAncestor(hWnd, GA_PARENT) == (HWND)m_DesktopNode.GetData())\n\t\t\tm_TopLevelWindows++;\n\n\t\tif (!m_ShowHiddenWindows && !win.IsWindowVisible())\n\t\t\treturn nullptr;\n\t\twin.GetWindowText(name);\n\t\tif (!m_ShowNoTitleWindows && name.IsEmpty())\n\t\t\treturn nullptr;\n\t}\n\n\tif (name.GetLength() > 64)\n\t\tname = name.Left(64) + L\"...\";\n\tif (!name.IsEmpty())\n\t\tname = L\"[\" + name + L\"]\";\n\tWCHAR className[64] = { 0 };\n\t::GetClassName(hWnd, className, _countof(className));\n\ttext.Format(L\"0x%zX (%s) %s\", (DWORD_PTR)hWnd, className, (PCWSTR)name);\n\n\tHICON hIcon{ nullptr };\n\tint image = 0;\n\tif ((win.GetStyle() & WS_CHILD) == 0) {\n\t\tauto& icons = WindowHelper::GetIconMap();\n\t\tif (auto it = icons.find(hWnd); it == icons.end()) {\n\t\t\thIcon = WindowHelper::GetWindowOrProcessIcon(hWnd);\n\t\t\tif (hIcon) {\n\t\t\t\ticons.insert({ hWnd, image = WindowHelper::GetImageList().AddIcon(hIcon) });\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\timage = it->second;\n\t\t}\n\t}\n\n\tauto node = m_Tree.InsertItem(text, image, image, hParent, TVI_LAST);\n\tnode.SetData((DWORD_PTR)hWnd);\n\tm_WindowMap.insert({ hWnd, node });\n\n\tif (!win.IsWindowVisible())\n\t\tnode.SetState(TVIS_CUT, TVIS_CUT);\n\n\tif (m_DesktopNode && win.GetWindow(GW_CHILD)) {\n\t\t// add a \"plus\" button\n\t\tnode.AddTail(L\"*\", 0);\n\t}\n\treturn node;\n}\n\nBOOL CWindowsView::AddChildNode(HWND hChild) {\n\tif (::GetAncestor(hChild, GA_PARENT) == (HWND)m_Tree.GetItemData(m_hCurrentNode)) {\n\t\tAddNode(hChild, m_hCurrentNode);\n\t}\n\treturn TRUE;\n}\n\nLRESULT CWindowsView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tm_Splitter.SetSplitterExtendedStyle(SPLIT_FLATBAR | SPLIT_PROPORTIONAL);\n\tm_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);\n\t\n\t//m_TreeFrame.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);\n\t//m_Tree.Attach(m_TreeFrame.m_hWndClient);\n\n\t//ToolBarButtonInfo buttons[] = {\n\t//\t{ ID_VIEW_REFRESH, IDI_REFRESH },\n\t//\t{ 0 },\n\t//\t{ ID_VIEW_HIDDENWINDOWS, IDI_WINDOW_HIDDEN },\n\t//\t{ ID_VIEW_EMPTYTITLEWINDOWS, IDI_WINDOW_NOTEXT },\n\t//\t{ ID_WINDOW_PROPERTIES, IDI_WINPROP },\n\t//};\n\n\t//m_TreeFrame.CreateAndInitToolBar(buttons, _countof(buttons));\n\n\tm_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |\n\t\tTVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS, 0);\n\tm_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER);\n\tm_Tree.SetImageList(WindowHelper::GetImageList(), TVSIL_NORMAL);\n\n\tm_WindowsView.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);\n\n\tm_Splitter.SetSplitterPanes(m_Tree, m_WindowsView);\n\tUpdateLayout();\n\tm_Splitter.SetSplitterPosPct(35);\n\n\tInitTree();\n\tm_WindowMap.reserve(256);\n\n\tSetTimer(1, 2000, nullptr);\n\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnTimer(UINT, WPARAM id, LPARAM, BOOL&) {\n\tif (id == 1)\n\t\tRefresh();\n\telse if (id == 3) {\n\t\tKillTimer(3);\n\t\tm_Selected = m_Tree.GetSelectedItem();\n\t\tNodeSelected();\n\t}\n\treturn 0;\n}\n\nvoid CWindowsView::NodeSelected() {\n\tm_SelectedHwnd.Detach();\n\tauto data = m_Selected.GetData();\n\tauto hWnd = (HWND)data;\n\tif (data != MessageOnlyWindowsNode && !::IsWindow(hWnd))\t// window is probably destroyed\n\t\tm_Selected.Delete();\n\telse {\n\t\tif (data == MessageOnlyWindowsNode)\n\t\t\tm_WindowsView.UpdateList(nullptr);\n\t\telse {\n\t\t\tm_SelectedHwnd.Attach(hWnd);\n\t\t\tm_WindowsView.UpdateList(hWnd);\n\t\t}\n\t}\n\tUpdateUI();\n}\n\nLRESULT CWindowsView::OnNodeExpanding(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tif (tv->action == TVE_EXPAND) {\n\t\tauto hItem = tv->itemNew.hItem;\n\n\t\tauto child = m_Tree.GetChildItem(hItem);\n\t\tif (child.GetData() == 0) {\n\t\t\tchild.Delete();\n\t\t\tAddChildWindows(hItem);\n\t\t}\n\t}\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnNodeDeleted(int, LPNMHDR hdr, BOOL&) {\n\tif (!m_Deleting) {\n\t\tauto tv = (NMTREEVIEW*)hdr;\n\t\tm_WindowMap.erase((HWND)tv->itemOld.lParam);\n\t}\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnNodeSelected(int, LPNMHDR hdr, BOOL&) {\n\tauto tv = (NMTREEVIEW*)hdr;\n\tif (tv->action == TVC_BYKEYBOARD) {\n\t\t// short delay before update in case the user moves quickly through the tree\n\t\tSetTimer(3, 250, nullptr);\n\t}\n\telse {\n\t\tm_Selected.m_hTreeItem = tv->itemNew.hItem;\n\t\tm_Selected.m_pTreeView = &m_Tree;\n\t\tNodeSelected();\n\t}\n\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowShow(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.ShowWindowAsync(SW_SHOW);\n\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowHide(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.ShowWindowAsync(SW_HIDE);\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowClose(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.PostMessage(WM_CLOSE);\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowMinimize(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.ShowWindowAsync(SW_MINIMIZE);\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowMaximize(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.ShowWindowAsync(SW_MAXIMIZE);\n\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowRestore(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.ShowWindowAsync(SW_RESTORE);\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowBringToFront(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tm_SelectedHwnd.BringWindowToTop();\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnRefresh(WORD, WORD, HWND, BOOL&) {\n\tInitTree();\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnToggleHiddenWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowHiddenWindows = !m_ShowHiddenWindows;\n\tUpdateUI();\n\tInitTree();\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnToggleEmptyTitleWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowNoTitleWindows = !m_ShowNoTitleWindows;\n\tUpdateUI();\n\tInitTree();\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnToggleChildWindows(WORD, WORD, HWND, BOOL&) {\n\tm_ShowChildWindows = !m_ShowChildWindows;\n\tUpdateUI();\n\tInitTree();\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnTreeNodeRightClick(HTREEITEM hItem, CPoint const& pt) {\n\tATLASSERT(m_Selected);\n\tif (!m_Selected)\n\t\treturn 0;\n\n\tCMenu menu;\n\tmenu.LoadMenu(IDR_CONTEXT);\n\n\treturn GetFrame()->ShowPopupMenu(menu.GetSubMenu(0), pt);\n}\n\nLRESULT CWindowsView::OnWindowFlash(WORD, WORD, HWND, BOOL&) {\n\tif (m_SelectedHwnd)\n\t\tWindowHelper::Flash(m_SelectedHwnd);\n\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowHighlight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tif (m_SelectedHwnd) {\n\t\t::TrySubmitThreadpoolCallback([](auto, auto p) {\n\t\t\tauto hWnd = (HWND)p;\n\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\tWindowHelper::HighlightBorder(hWnd);\n\t\t\t\t::Sleep(500);\n\t\t\t\tWindowHelper::HighlightBorder(hWnd, false);\n\t\t\t\t::Sleep(500);\n\t\t\t}\n\t\t\t}, m_SelectedHwnd, nullptr);\n\t}\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnWindowProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& handled) {\n\tif (::GetFocus() != m_Tree) {\n\t\thandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tif (m_SelectedHwnd) {\n\t\tWindowHelper::ShowWindowProperties(m_SelectedHwnd);\n\t}\n\treturn 0;\n}\n\nLRESULT CWindowsView::OnTreeNodeDoubleClick(HTREEITEM hItem, CPoint const& pt) {\n\tWindowHelper::ShowWindowProperties((HWND)m_Tree.GetItemData(hItem));\n\treturn 1;\n}\n\nLRESULT CWindowsView::OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {\n\tm_Tree.SetFocus();\n\treturn 0;\n}\n\nCTreeItem CWindowsView::AddMessageOnlyWindows() {\n\tm_MsgOnlyNode = m_Tree.InsertItem(L\"Message Only Windows\", TVI_ROOT, TVI_LAST);\n\tm_MsgOnlyNode.SetData(MessageOnlyWindowsNode);\n\treturn m_MsgOnlyNode;\n}\n\nLRESULT CWindowsView::OnCaptureMessages(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {\n\tif (m_SelectedHwnd) {\n\t\tauto view = GetFrame()->CreateMessagesView();\n\t\tif (!view->CaptureWindow(m_SelectedHwnd)) {\n\t\t\tAtlMessageBox(m_hWnd, L\"Failed to register hook\", IDS_TITLE, MB_ICONERROR);\n\t\t\tGetFrame()->CloseTab(view);\n\t\t}\n\t}\n\treturn 0;\n}\n\n"
  },
  {
    "path": "WinSpy/WindowsView.h",
    "content": "// View.h : interface of the CView class\n//\n/////////////////////////////////////////////////////////////////////////////\n\n#pragma once\n\n#include \"TreeViewManager.h\"\n#include \"ViewBase.h\"\n#include \"WindowsListView.h\"\n#include <CustomSplitterWindow.h>\n\nclass CWindowsView : \n\tpublic CViewBase<CWindowsView>,\n\tpublic CTreeViewManager<CWindowsView> {\npublic:\n\tCWindowsView(IMainFrame* frame) : CViewBase(frame), m_WindowsView(frame) {}\n\n\tBOOL PreTranslateMessage(MSG* pMsg);\n\n\tvoid OnActivate(bool activate);\n\tLRESULT OnTreeNodeDoubleClick(HTREEITEM hItem, CPoint const& pt);\n\nprotected:\n\tenum { IDC_TREE = 123 };\n\n\tBEGIN_MSG_MAP(CWindowsView)\n\t\tMESSAGE_HANDLER(WM_TIMER, OnTimer)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tNOTIFY_CODE_HANDLER(TVN_ITEMEXPANDING, OnNodeExpanding)\n\t\tNOTIFY_CODE_HANDLER(TVN_DELETEITEM, OnNodeDeleted)\n\t\tNOTIFY_CODE_HANDLER(TVN_SELCHANGED, OnNodeSelected)\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_HIDDENWINDOWS, OnToggleHiddenWindows)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_EMPTYTITLEWINDOWS, OnToggleEmptyTitleWindows)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_SHOW, OnWindowShow)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_HIDE, OnWindowHide)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_BRINGTOFRONT, OnWindowBringToFront)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MINIMIZE, OnWindowMinimize)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MAXIMIZE, OnWindowMaximize)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_HIGHLIGHT, OnWindowHighlight)\n\t\tCOMMAND_ID_HANDLER(ID_STATE_FLASH, OnWindowFlash)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_RESTORE, OnWindowRestore)\n\t\tCOMMAND_ID_HANDLER(ID_STATE_CLOSE, OnWindowClose)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_MESSAGES, OnCaptureMessages)\n\t\tCOMMAND_ID_HANDLER(ID_WINDOW_PROPERTIES, OnWindowProperties)\n\t\tCOMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnRefreshAll)\n\t\tCHAIN_MSG_MAP(CTreeViewManager<CWindowsView>)\n\t\tCHAIN_MSG_MAP(CViewBase<CWindowsView>)\n\t\tif (m_WindowsView) {\n\t\t\tCHAIN_MSG_MAP_ALT_MEMBER(m_WindowsView, 1)\n\t\t}\n\tEND_MSG_MAP()\n\n\tLRESULT OnTreeNodeRightClick(HTREEITEM hItem, CPoint const& pt);\n\nprivate:\n\tvoid UpdateUI();\n\tvoid Refresh();\n\tvoid InitTree();\n\tvoid AddChildWindows(HTREEITEM hParent);\n\tCTreeItem AddNode(HWND hWnd, HTREEITEM hParent);\n\tBOOL AddChildNode(HWND hChild);\n\tvoid NodeSelected();\n\tCTreeItem AddMessageOnlyWindows();\n\n\t// Handler prototypes (uncomment arguments if needed):\n\t//\tLRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t//\tLRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t//\tLRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeExpanding(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeDeleted(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnNodeSelected(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);\n\tLRESULT OnRefreshAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowShow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowHide(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowMinimize(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowMaximize(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowRestore(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleHiddenWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleEmptyTitleWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnToggleChildWindows(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowFlash(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowBringToFront(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnWindowHighlight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\tLRESULT OnCaptureMessages(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);\n\n\tenum { MessageOnlyWindowsNode = 1 };\n\n\tCCustomSplitterWindow m_Splitter;\n\tCWindowsListView m_WindowsView;\n\t//CTreeViewFrame m_TreeFrame;\n\tCTreeViewCtrlEx m_Tree;\n\tCTreeItem m_hCurrentNode;\n\tCTreeItem m_DesktopNode;\n\tCTreeItem m_Selected;\n\tCTreeItem m_MsgOnlyNode;\n\tCWindow m_SelectedHwnd;\n\tstd::unordered_map<HWND, HTREEITEM> m_WindowMap;\n\tDWORD m_TotalWindows, m_TotalVisibleWindows, m_TopLevelWindows;\n\n\tbool m_ShowHiddenWindows : 1 { false };\n\tbool m_ShowNoTitleWindows : 1 { true };\n\tbool m_ShowChildWindows : 1 { true };\n\tbool m_Deleting{ false };\n};\n"
  },
  {
    "path": "WinSpy/pch.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\n//\tWinSpy.pch will be the pre-compiled header\n//\tstdafx.obj will contain the pre-compiled type information\n\n#include \"pch.h\"\n"
  },
  {
    "path": "WinSpy/pch.h",
    "content": "// stdafx.h : include file for standard system include files,\n//  or project specific include files that are used frequently, but\n//  are changed infrequently\n//\n\n#pragma once\n\n// Change these values to use different versions\n#define WINVER\t\t0x0605\n#define _WIN32_WINNT\t0x0601\n#define _WIN32_IE\t0x0700\n#define _RICHEDIT_VER\t0x0500\n#define _HAS_EXCEPTIONS 0\n\n#include <atlbase.h>\n#include <atlapp.h>\n#include <atlstr.h>\n\nextern CAppModule _Module;\n\n#include <atlwin.h>\n#include <atlframe.h>\n#include <atlctrls.h>\n#include <atldlgs.h>\n#include <atlctrlw.h>\n#include <atlctrlx.h>\n#include <atlsplit.h>\n#include <atlmisc.h>\n#include <strsafe.h>\n#include <vector>\n#include <memory>\n#include <unordered_map>\n#include <algorithm>\n#include <mutex>\n#include <format>\n\n#if defined _M_IX86\n  #pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#elif defined _M_IA64\n  #pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#elif defined _M_X64\n  #pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#else\n  #pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#endif\n"
  },
  {
    "path": "WinSpy/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by WinSpy.rc\n//\n#define IDD_ABOUTBOX                    100\n#define IDD_PROPWINDOWS                 107\n#define IDR_MAINFRAME                   128\n#define IDS_TITLE                       129\n#define IDI_WINDOW                      201\n#define IDI_WINDOW_HIDDEN               202\n#define IDI_WINDOW_DELETE               204\n#define IDI_WINDOW_NEW                  205\n#define IDI_WINDOWS                     206\n#define IDI_REFRESH                     207\n#define IDR_CONTEXT                     208\n#define IDI_WINDOW_CLOSE                209\n#define IDI_WINDOW_NOTEXT               210\n#define IDD_FINDWINDOW                  211\n#define IDI_WINDOW_MINIMIZE             213\n#define IDI_WINDOW_SENDTOBACK           214\n#define IDI_WINDOW_MAXIMIZE             215\n#define IDI_TARGET                      216\n#define IDI_PROCESSES                   217\n#define IDD_WINPROP                     218\n#define IDI_WINPROP                     221\n#define IDI_PROCESS_INFO                222\n#define IDI_MESSAGE                     223\n#define IDI_MESSAGES                    224\n#define IDI_WINDOWSEARCH                225\n#define IDI_SENDTOFRONT                 227\n#define IDI_RESTORE                     228\n#define IDI_ICON1                       229\n#define IDI_AUTOMATION                  229\n#define IDC_HANDLE                      1000\n#define IDC_CLASSNAME                   1001\n#define IDC_HANDLE2                     1001\n#define IDC_CLASSNAME2                  1002\n#define IDC_TEXT                        1002\n#define IDC_SEARCH                      1003\n#define IDC_TEXT2                       1003\n#define IDC_TARGET                      1004\n#define IDC_HANDLE3                     1004\n#define IDC_HIDE                        1005\n#define IDC_TEXT3                       1005\n#define IDC_THREAD                      1006\n#define IDC_HANDLE4                     1006\n#define IDC_PROCESS                     1007\n#define IDC_TEXT4                       1007\n#define IDC_RECT                        1008\n#define IDC_CLIENTRECT                  1009\n#define IDC_STYLE                       1010\n#define IDC_STYLES                      1011\n#define IDC_STYLEEX                     1012\n#define IDC_STYLESEX                    1013\n#define IDC_ATOM                        1014\n#define IDC_RESTORE_RECT                1015\n#define IDC_MENU                        1016\n#define IDC_CLASS                       1016\n#define IDC_USERDATA                    1017\n#define IDC_CLASS2                      1017\n#define IDC_STYLECLASS                  1018\n#define IDC_CLASS3                      1018\n#define IDC_CLASSSTYLE                  1019\n#define IDC_CLASS4                      1019\n#define ID_WINDOW_CLOSE                 32772\n#define ID_WINDOW_CLOSE_ALL             32773\n#define ID_VIEW_ALLWINDOWS              32775\n#define ID_VIEW_ALLPROCESSES            32776\n#define ID_VIEW_REFRESH32777            32777\n#define ID_VIEW_REFRES                  32778\n#define ID_WINDOW_SHOW                  32779\n#define ID_WINDOW_HIDE                  32780\n#define ID_WINDOW_HIGHLIGHT             32781\n#define ID_WINDOW_MINIMIZE              32782\n#define ID_WINDOW_MAXIMIZE              32783\n#define ID_WINDOW_RESTORE               32784\n#define ID_WINDOW_BRINGTOFRONT          32785\n#define ID_WINDOW_PROPERTIES            32786\n#define ID_WINDOW_FIND                  32787\n#define ID_WINDOW_STATE                 32788\n#define ID_OPTIONS_ALWAYSONTOP          32789\n#define ID_VIEW_HIDDENWINDOWS           32790\n#define ID_VIEW_EMPTYTITLEWINDOWS       32791\n#define ID_STATE_CLOSE                  32792\n#define ID_STATE_FLASH                  32793\n#define ID_VIEW_CHILDWINDOWS            32794\n#define ID_VIEW_WINDOWSLIST             32795\n#define ID_LIST_LOCATEINTREE            32796\n#define ID_WINDOW_LOCATEINTREE          32797\n#define ID_TREE_SENDTOBACK              32798\n#define ID_FILE_RUNASADMINISTRATOR      32799\n#define ID_OPTIONS_FONTS                32800\n#define ID_PROCESS_TERMINATE            32801\n#define ID_PROCESS_PROPERTIES           32802\n#define ID_THREAD_PROPERTIES            32803\n#define ID_WINDOW_MESSAGES              32804\n#define ID_VIEW_AUTOMATIONTREE          32805\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        230\n#define _APS_NEXT_COMMAND_VALUE         32806\n#define _APS_NEXT_CONTROL_VALUE         1019\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "WinSpy.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.3.32519.111\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"WinSpy\", \"WinSpy\\WinSpy.vcxproj\", \"{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"WinSpyHook\", \"WinSpyHook\\WinSpyHook.vcxproj\", \"{1CA31FEE-1F81-4C94-9205-D908841958DD}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"WTLHelper\", \"WTLHelper\\WTLHelper\\WTLHelper.vcxproj\", \"{AE53419F-A769-4548-8E15-E311904DF7DF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\t\tReleaseSigned|ARM64 = ReleaseSigned|ARM64\n\t\tReleaseSigned|x64 = ReleaseSigned|x64\n\t\tReleaseSigned|x86 = ReleaseSigned|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Debug|ARM64.ActiveCfg = Debug|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Debug|ARM64.Build.0 = Debug|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Debug|x64.Build.0 = Debug|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Debug|x86.Build.0 = Debug|Win32\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Release|ARM64.ActiveCfg = Release|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Release|ARM64.Build.0 = Release|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Release|x64.ActiveCfg = Release|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Release|x64.Build.0 = Release|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Release|x86.ActiveCfg = Release|Win32\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.Release|x86.Build.0 = Release|Win32\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32\n\t\t{3988E48D-F582-4E0F-B1AF-FC70A4D0B4D7}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Debug|ARM64.ActiveCfg = Debug|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Debug|ARM64.Build.0 = Debug|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Debug|x64.Build.0 = Debug|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Debug|x86.Build.0 = Debug|Win32\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Release|ARM64.ActiveCfg = Release|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Release|ARM64.Build.0 = Release|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Release|x64.ActiveCfg = Release|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Release|x64.Build.0 = Release|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Release|x86.ActiveCfg = Release|Win32\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.Release|x86.Build.0 = Release|Win32\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32\n\t\t{1CA31FEE-1F81-4C94-9205-D908841958DD}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x64.Build.0 = Debug|x64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x86.Build.0 = Debug|Win32\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x64.ActiveCfg = Release|x64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x64.Build.0 = Release|x64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x86.ActiveCfg = Release|Win32\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x86.Build.0 = Release|Win32\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|ARM64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|ARM64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32\n\t\t{AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {E58082A6-A00C-40B6-AA8C-78702BA61918}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "WinSpyHook/WinSpyHook.def",
    "content": "LIBRARY\nEXPORTS\n\tHookFunc3\t\tPRIVATE\n\tHookFunc4\t\tPRIVATE\n\tHookFunc12\t\tPRIVATE\n\tAddHook\n\tRemoveHook\n"
  },
  {
    "path": "WinSpyHook/WinSpyHook.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSigned|Win32\">\n      <Configuration>ReleaseSigned</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSigned|x64\">\n      <Configuration>ReleaseSigned</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{1ca31fee-1f81-4c94-9205-d908841958dd}</ProjectGuid>\n    <RootNamespace>WinSpyHook</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;WINSPYHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n      <ModuleDefinitionFile>WinSpyHook.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;WINSPYHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n      <ModuleDefinitionFile>WinSpyHook.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;WINSPYHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n      <ModuleDefinitionFile>WinSpyHook.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;WINSPYHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n      <ModuleDefinitionFile>WinSpyHook.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;WINSPYHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n      <ModuleDefinitionFile>WinSpyHook.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;WINSPYHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp20</LanguageStandard>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableUAC>false</EnableUAC>\n      <ModuleDefinitionFile>WinSpyHook.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"hooks.h\" />\n    <ClInclude Include=\"pch.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"dllmain.cpp\" />\n    <ClCompile Include=\"hooks.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='ReleaseSigned|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"WinSpyHook.def\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "WinSpyHook/WinSpyHook.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"hooks.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"dllmain.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"pch.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"hooks.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"WinSpyHook.def\">\n      <Filter>Source Files</Filter>\n    </None>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "WinSpyHook/dllmain.cpp",
    "content": "// dllmain.cpp : Defines the entry point for the DLL application.\n#include \"pch.h\"\n\nHINSTANCE g_hInstDll;\n\nBOOL WINAPI DllMain(HMODULE hModule, DWORD reason, PVOID lpReserved) {\n\tswitch (reason) {\n\t\tcase DLL_PROCESS_ATTACH:\n\t\t\tg_hInstDll = hModule;\n\t\t\t::DisableThreadLibraryCalls(hModule);\n\t\t\tbreak;\n\t}\n\treturn TRUE;\n}\n\n"
  },
  {
    "path": "WinSpyHook/hooks.cpp",
    "content": "#include \"pch.h\"\n#include \"hooks.h\"\n\nconst unsigned MaxHooks = 8;\n\nstruct HookEntry {\n\tHHOOK hHook;\n\tHWND CallbackWnd;\n\tDWORD ThreadId;\n\tHWND TargetHwnd;\n\tHookOptions Options;\n};\n\n#pragma data_seg(\".shared\")\nunsigned g_HookCount = 0;\nHookEntry g_HookMap[3][MaxHooks] {};\n#pragma data_seg()\n#pragma comment(linker, \"/section:.shared,RWS\")\n\nbool IsNotify(HWND hTarget, HookEntry const& entry) {\n\tif ((entry.Options & HookOptions::Thread) == HookOptions::Thread)\n\t\treturn true;\n\n\tif ((entry.Options & HookOptions::Window) == HookOptions::Window && hTarget == entry.TargetHwnd)\n\t\treturn true;\n\n\t//\n\t// check if child window\n\t//\n\treturn entry.TargetHwnd == ::GetAncestor(hTarget, GA_PARENT);\n}\n\nLRESULT WINAPI HookFunc3(int code, WPARAM wParam, LPARAM lParam) {\n\tif (code == HC_ACTION) {\n\t\tauto msg = reinterpret_cast<MSG*>(lParam);\n\t\tauto hWnd =  msg->hwnd;\n\t\tauto tid = ::GetWindowThreadProcessId(hWnd, nullptr);\n\t\tATLTRACE(L\"HookFunc3: hWnd: 0x%p TID: %u\\n\", hWnd, tid);\n\t\tfor (auto& hook : g_HookMap[0]) {\n\t\t\tif (hook.ThreadId == tid) {\n\t\t\t\tif (IsNotify(hWnd, hook)) {\n\t\t\t\t\tATLTRACE(L\"HookFunc3: Sending message to 0x%p (%u)\\n\", hook.CallbackWnd, WM_HOOKCALLBACK);\n\t\t\t\t\tCOPYDATASTRUCT cds;\n\t\t\t\t\tGetMessageData data;\n\t\t\t\t\tdata.Msg = *msg;\n\t\t\t\t\tdata.HookType = WH_GETMESSAGE;\n\t\t\t\t\tdata.wParam = wParam;\n\t\t\t\t\tcds.cbData = sizeof(data);\n\t\t\t\t\tcds.lpData = &data;\n\t\t\t\t\t::SendMessage(hook.CallbackWnd, WM_COPYDATA, 0, reinterpret_cast<LPARAM>(&cds));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn ::CallNextHookEx(nullptr, code, wParam, lParam);\n}\n\nLRESULT WINAPI HookFunc4(int code, WPARAM wParam, LPARAM lParam) {\n\n\treturn ::CallNextHookEx(nullptr, code, wParam, lParam);\n}\n\nLRESULT WINAPI HookFunc12(int code, WPARAM wParam, LPARAM lParam) {\n\n\treturn ::CallNextHookEx(nullptr, code, wParam, lParam);\n}\n\nbool WINAPI AddHook(DWORD hookType, HookConfig const& config) {\n\tif (g_HookCount == MaxHooks)\n\t\treturn false;\n\n\textern HINSTANCE g_hInstDll;\n\tCStringA name;\n\tname.Format(\"HookFunc%u\", hookType);\n\tauto proc = (HOOKPROC)::GetProcAddress(g_hInstDll, name);\n\tATLASSERT(proc);\n\tauto hHook = ::SetWindowsHookEx(hookType, proc, g_hInstDll, config.ThreadId);\n\tif (!hHook)\n\t\treturn false;\n\n\tauto index = -1;\n\tswitch (hookType) {\n\t\tcase WH_GETMESSAGE: index = 0; break;\n\t\tcase WH_CALLWNDPROC: index = 1; break;\n\t\tcase WH_CALLWNDPROCRET: index = 2; break;\n\t\tdefault:\n\t\t\tATLASSERT(false);\n\t\t\tbreak;\n\t}\n\tif (index < 0)\n\t\treturn false;\n\n\tHookEntry entry{ hHook, config.CallbackWnd, config.ThreadId, config.TargetWnd, config.Options };\n\t//std::lock_guard locker(g_Lock);\n\tg_HookMap[index][g_HookCount++] = entry;\n\treturn true;\n}\n\nbool WINAPI RemoveHook(DWORD tid) {\n\t//std::lock_guard locker(g_Lock);\n\tfor (int i = 0; i < _countof(g_HookMap); i++) {\n\t\tfor(auto& hook : g_HookMap[i]) {\n\t\t\tif (hook.ThreadId == tid) {\n\t\t\t\t::UnhookWindowsHookEx(hook.hHook);\n\t\t\t\thook.ThreadId = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n"
  },
  {
    "path": "WinSpyHook/hooks.h",
    "content": "#pragma once\n\nconst UINT WM_HOOKCALLBACK = WM_USER + 333;\n\nenum class HookOptions {\n\tNone = 0,\n\tWindow = 1,\n\tChildWindows = 2,\n\tThread = 4,\n};\nDEFINE_ENUM_FLAG_OPERATORS(HookOptions);\n\nstruct HookConfig {\n\tHWND TargetWnd;\n\tDWORD ThreadId;\n\tHWND CallbackWnd;\n\tHookOptions Options;\n};\n\nbool WINAPI AddHook(DWORD hookType, HookConfig const& config);\nbool WINAPI RemoveHook(DWORD tid);\n\nstruct HookDataHeader {\n\tDWORD HookType;\n};\n\nstruct GetMessageData : HookDataHeader {\n\tWPARAM wParam;\n\tMSG Msg;\n};\n"
  },
  {
    "path": "WinSpyHook/pch.cpp",
    "content": "// pch.cpp: source file corresponding to the pre-compiled header\n\n#include \"pch.h\"\n\n// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.\n"
  },
  {
    "path": "WinSpyHook/pch.h",
    "content": "// pch.h: This is a precompiled header file.\n// Files listed below are compiled only once, improving build performance for future builds.\n// This also affects IntelliSense performance, including code completion and many code browsing features.\n// However, files listed here are ALL re-compiled if any one of them is updated between builds.\n// Do not add files here that you will be updating frequently as this negates the performance advantage.\n\n#ifndef PCH_H\n#define PCH_H\n\n#include <Windows.h>\n#include <vector>\n#include <functional>\n#include <mutex>\n#include <algorithm>\n#include <atlstr.h>\n\n#endif //PCH_H\n"
  }
]