go my file uploader

This commit is contained in:
AirDog46
2025-05-13 19:45:22 +03:00
commit c5fab8aa94
708 changed files with 343216 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
1.5
* Fixed window list not displaying Modern UI windows
1.4
* Fixed hook support for low integrity processes
1.3
* Fixed hook bugs
1.2
* Added more window properties
1.1
* Added Always on Top and Opacity
* Renamed Show/Hide and Enable/Disable to Visible and Enabled
1.0
* Initial release

View File

@@ -0,0 +1,307 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (Australia) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,0,0
PRODUCTVERSION 1,5,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "0c0904b0"
BEGIN
VALUE "CompanyName", "wj32"
VALUE "FileDescription", "Window Explorer plugin for Process Hacker"
VALUE "FileVersion", "1.5"
VALUE "InternalName", "WindowExplorer"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "WindowExplorer.dll"
VALUE "ProductName", "Window Explorer plugin for Process Hacker"
VALUE "ProductVersion", "1.5"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_WNDLIST DIALOGEX 0, 0, 447, 309
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Windows"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Refresh",IDC_REFRESH,7,6,50,14
CONTROL "Windows",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x2,7,25,433,277,WS_EX_CLIENTEDGE
END
IDD_WNDPROPS DIALOGEX 0, 0, 233, 152
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Properties"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Property list for the window:",IDC_STATIC,7,7,92,8
CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,20,219,125
END
IDD_WNDGENERAL DIALOGEX 0, 0, 233, 147
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "General"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Text:",IDC_STATIC,7,8,18,8
EDITTEXT IDC_TEXT,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY
LTEXT "Thread:",IDC_STATIC,7,22,26,8
LTEXT "Static",IDC_THREAD,77,22,149,8,SS_ENDELLIPSIS
LTEXT "Rectangle:",IDC_STATIC,7,33,36,8
LTEXT "Static",IDC_RECTANGLE,77,33,149,8,SS_ENDELLIPSIS
LTEXT "Normal rectangle:",IDC_STATIC,7,44,60,8
LTEXT "Static",IDC_NORMALRECTANGLE,77,44,149,8,SS_ENDELLIPSIS
LTEXT "Client rectangle:",IDC_STATIC,7,55,56,8
LTEXT "Static",IDC_CLIENTRECTANGLE,77,55,149,8,SS_ENDELLIPSIS
LTEXT "Instance handle:",IDC_STATIC,7,66,56,8
LTEXT "Static",IDC_INSTANCEHANDLE,77,66,149,8,SS_ENDELLIPSIS
LTEXT "Menu handle:",IDC_STATIC,7,77,45,8
LTEXT "Static",IDC_MENUHANDLE,77,77,149,8,SS_ENDELLIPSIS
LTEXT "User data:",IDC_STATIC,7,88,36,8
LTEXT "Static",IDC_USERDATA,77,88,149,8,SS_ENDELLIPSIS
LTEXT "Unicode:",IDC_STATIC,7,99,29,8
LTEXT "Static",IDC_UNICODE,77,99,149,8
LTEXT "Window proc:",IDC_STATIC,7,110,45,8
EDITTEXT IDC_WINDOWPROC,75,110,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
LTEXT "Dialog proc:",IDC_STATIC,7,121,39,8
EDITTEXT IDC_DIALOGPROC,75,121,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
LTEXT "Dialog control ID:",IDC_STATIC,7,132,61,8
LTEXT "Static",IDC_CTRLID,77,132,149,8
END
IDD_WNDSTYLES DIALOGEX 0, 0, 233, 140
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Styles"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Styles:",IDC_STATIC,7,7,23,8
LTEXT "Static",IDC_STYLES,67,7,159,8
LISTBOX IDC_STYLESLIST,7,19,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
LTEXT "Extended styles:",IDC_STATIC,7,69,56,8
LTEXT "Static",IDC_EXTENDEDSTYLES,67,69,159,8
LISTBOX IDC_EXTENDEDSTYLESLIST,7,81,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
END
IDD_WNDCLASS DIALOGEX 0, 0, 233, 132
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Class"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Name:",IDC_STATIC,7,8,22,8
EDITTEXT IDC_NAME,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY
LTEXT "Atom:",IDC_STATIC,7,22,20,8
LTEXT "Static",IDC_ATOM,77,22,149,8,SS_ENDELLIPSIS
LTEXT "Styles:",IDC_STATIC,7,33,23,8
EDITTEXT IDC_STYLES,75,33,150,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
LTEXT "Instance handle:",IDC_STATIC,7,44,56,8
LTEXT "Static",IDC_INSTANCEHANDLE,77,44,149,8,SS_ENDELLIPSIS
LTEXT "Icon handle:",IDC_STATIC,7,55,42,8
LTEXT "Static",IDC_ICONHANDLE,77,55,149,8,SS_ENDELLIPSIS
LTEXT "Small icon handle:",IDC_STATIC,7,66,60,8
LTEXT "Static",IDC_SMALLICONHANDLE,77,66,149,8,SS_ENDELLIPSIS
LTEXT "Cursor handle:",IDC_STATIC,7,77,49,8
LTEXT "Static",IDC_CURSORHANDLE,77,77,149,8,SS_ENDELLIPSIS
LTEXT "Background brush:",IDC_STATIC,7,88,61,8
LTEXT "Static",IDC_BACKGROUNDBRUSH,77,88,149,8,SS_ENDELLIPSIS
LTEXT "Menu name:",IDC_STATIC,7,99,41,8
LTEXT "Static",IDC_MENUNAME,77,99,149,8,SS_ENDELLIPSIS
LTEXT "Window proc:",IDC_STATIC,7,110,45,8
EDITTEXT IDC_WINDOWPROC,75,110,151,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_WNDLIST, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 440
TOPMARGIN, 6
BOTTOMMARGIN, 302
END
IDD_WNDPROPS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 226
TOPMARGIN, 7
BOTTOMMARGIN, 145
END
IDD_WNDGENERAL, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 226
TOPMARGIN, 7
BOTTOMMARGIN, 140
END
IDD_WNDSTYLES, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 226
TOPMARGIN, 7
BOTTOMMARGIN, 133
END
IDD_WNDCLASS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 226
TOPMARGIN, 7
BOTTOMMARGIN, 125
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_WINDOW MENU
BEGIN
POPUP "Window"
BEGIN
MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT
MENUITEM "Restore", ID_WINDOW_RESTORE
MENUITEM "Minimize", ID_WINDOW_MINIMIZE
MENUITEM "Maximize", ID_WINDOW_MAXIMIZE
MENUITEM "Close", ID_WINDOW_CLOSE
MENUITEM SEPARATOR
MENUITEM "Visible", ID_WINDOW_VISIBLE
MENUITEM "Enabled", ID_WINDOW_ENABLED
MENUITEM "Always on top", ID_WINDOW_ALWAYSONTOP
POPUP "Opacity"
BEGIN
MENUITEM "10%", ID_OPACITY_10
MENUITEM "20%", ID_OPACITY_20
MENUITEM "30%", ID_OPACITY_30
MENUITEM "40%", ID_OPACITY_40
MENUITEM "50%", ID_OPACITY_50
MENUITEM "60%", ID_OPACITY_60
MENUITEM "70%", ID_OPACITY_70
MENUITEM "80%", ID_OPACITY_80
MENUITEM "90%", ID_OPACITY_90
MENUITEM "Opaque", ID_OPACITY_OPAQUE
END
MENUITEM SEPARATOR
MENUITEM "Highlight", ID_WINDOW_HIGHLIGHT
MENUITEM "Go to thread", ID_WINDOW_GOTOTHREAD
MENUITEM "Properties", ID_WINDOW_PROPERTIES
MENUITEM SEPARATOR
MENUITEM "Copy\aCtrl+C", ID_WINDOW_COPY
END
END
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_WNDGENERAL AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_WNDLIST AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_WNDCLASS AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{37488DC1-E45F-4626-A87C-3A854A153D1A}</ProjectGuid>
<RootNamespace>WindowExplorer</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>WindowExplorer</ProjectName>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Plugins.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug32</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release64</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release32</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug64</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
<DelayLoadDLLs>ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<DelayLoadDLLs>ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
<DelayLoadDLLs>ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<DelayLoadDLLs>ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="hook.c" />
<ClCompile Include="main.c" />
<ClCompile Include="utils.c" />
<ClCompile Include="wnddlg.c" />
<ClCompile Include="wndprp.c" />
<ClCompile Include="wndtree.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
<ClInclude Include="wndexp.h" />
<ClInclude Include="wndtree.h" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WindowExplorer.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wndtree.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wnddlg.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="utils.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wndprp.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hook.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="wndexp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wndtree.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WindowExplorer.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,509 @@
/*
* Process Hacker Window Explorer -
* hook procedure
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Window Explorer uses a hook procedure in order to get window procedure
* and other information that can't be retrieved using GetWindowLongPtr.
* Because WindowExplorer.dll needs to be loaded into processes other
* than Process Hacker, both ProcessHacker.exe and comctl32.dll are set as
* delay-loaded DLLs. The other DLLs that we depend on (gdi32.dll,
* kernel32.dll, ntdll.dll, user32.dll) are all guaranteed to be already
* loaded whenever WindowExplorer.dll needs to be loaded.
*/
#include "wndexp.h"
BOOLEAN WepCreateServerObjects(
VOID
);
BOOLEAN WepOpenServerObjects(
VOID
);
VOID WepCloseServerObjects(
VOID
);
VOID WepWriteClientData(
_In_ HWND hwnd
);
LRESULT CALLBACK WepCallWndProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// Shared
ULONG WeServerMessage;
HANDLE WeServerSharedSection;
PWE_HOOK_SHARED_DATA WeServerSharedData;
HANDLE WeServerSharedSectionLock;
HANDLE WeServerSharedSectionEvent;
// Server
HHOOK WeHookHandle = NULL;
// The current message ID is used to detect out-of-sync clients.
ULONG WeCurrentMessageId = 0;
// Server
VOID WeHookServerInitialization(
VOID
)
{
if (WeHookHandle)
return;
WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME);
if (!WepCreateServerObjects())
return;
WeHookHandle = SetWindowsHookEx(WH_CALLWNDPROC, WepCallWndProc, PluginInstance->DllBase, 0);
}
VOID WeHookServerUninitialization(
VOID
)
{
if (WeHookHandle)
{
UnhookWindowsHookEx(WeHookHandle);
WeHookHandle = NULL;
}
}
BOOLEAN WepCreateServerObjects(
VOID
)
{
OBJECT_ATTRIBUTES objectAttributes;
WCHAR buffer[256];
UNICODE_STRING objectName;
SECURITY_DESCRIPTOR securityDescriptor;
UCHAR saclBuffer[sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
PACL sacl;
UCHAR mandatoryLabelAceBuffer[FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
PSYSTEM_MANDATORY_LABEL_ACE mandatoryLabelAce;
PSID sid;
if (!WeServerSharedSection)
{
LARGE_INTEGER maximumSize;
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
maximumSize.QuadPart = sizeof(WE_HOOK_SHARED_DATA);
if (!NT_SUCCESS(NtCreateSection(
&WeServerSharedSection,
SECTION_ALL_ACCESS,
&objectAttributes,
&maximumSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL
)))
{
return FALSE;
}
}
if (!WeServerSharedData)
{
PVOID viewBase;
SIZE_T viewSize;
viewBase = NULL;
viewSize = sizeof(WE_HOOK_SHARED_DATA);
if (!NT_SUCCESS(NtMapViewOfSection(
WeServerSharedSection,
NtCurrentProcess(),
&viewBase,
0,
0,
NULL,
&viewSize,
ViewShare,
0,
PAGE_READWRITE
)))
{
WepCloseServerObjects();
return FALSE;
}
WeServerSharedData = viewBase;
}
if (!WeServerSharedSectionLock)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtCreateMutant(
&WeServerSharedSectionLock,
MUTANT_ALL_ACCESS,
&objectAttributes,
FALSE
)))
{
WepCloseServerObjects();
return FALSE;
}
}
if (!WeServerSharedSectionEvent)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtCreateEvent(
&WeServerSharedSectionEvent,
EVENT_ALL_ACCESS,
&objectAttributes,
NotificationEvent,
FALSE
)))
{
WepCloseServerObjects();
return FALSE;
}
}
// If mandatory labels are supported, set it to the lowest possible level.
if (WE_WindowsVersion >= WINDOWS_VISTA)
{
static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);
sacl = (PACL)saclBuffer;
RtlCreateAcl(sacl, sizeof(saclBuffer), ACL_REVISION);
mandatoryLabelAce = (PSYSTEM_MANDATORY_LABEL_ACE)mandatoryLabelAceBuffer;
mandatoryLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;
mandatoryLabelAce->Header.AceFlags = 0;
mandatoryLabelAce->Header.AceSize = sizeof(mandatoryLabelAceBuffer);
mandatoryLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;
sid = (PSID)&mandatoryLabelAce->SidStart;
RtlInitializeSid(sid, &mandatoryLabelAuthority, 1);
*RtlSubAuthoritySid(sid, 0) = SECURITY_MANDATORY_LOW_RID;
if (NT_SUCCESS(RtlAddAce(sacl, ACL_REVISION, MAXULONG32, mandatoryLabelAce, sizeof(mandatoryLabelAceBuffer))))
{
if (NT_SUCCESS(RtlSetSaclSecurityDescriptor(&securityDescriptor, TRUE, sacl, FALSE)))
{
NtSetSecurityObject(WeServerSharedSection, LABEL_SECURITY_INFORMATION, &securityDescriptor);
NtSetSecurityObject(WeServerSharedSectionLock, LABEL_SECURITY_INFORMATION, &securityDescriptor);
NtSetSecurityObject(WeServerSharedSectionEvent, LABEL_SECURITY_INFORMATION, &securityDescriptor);
}
}
}
return TRUE;
}
BOOLEAN WepOpenServerObjects(
VOID
)
{
OBJECT_ATTRIBUTES objectAttributes;
WCHAR buffer[256];
UNICODE_STRING objectName;
if (!WeServerSharedSection)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenSection(
&WeServerSharedSection,
SECTION_ALL_ACCESS,
&objectAttributes
)))
{
return FALSE;
}
}
if (!WeServerSharedData)
{
PVOID viewBase;
SIZE_T viewSize;
viewBase = NULL;
viewSize = sizeof(WE_HOOK_SHARED_DATA);
if (!NT_SUCCESS(NtMapViewOfSection(
WeServerSharedSection,
NtCurrentProcess(),
&viewBase,
0,
0,
NULL,
&viewSize,
ViewShare,
0,
PAGE_READWRITE
)))
{
WepCloseServerObjects();
return FALSE;
}
WeServerSharedData = viewBase;
}
if (!WeServerSharedSectionLock)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenMutant(
&WeServerSharedSectionLock,
MUTANT_ALL_ACCESS,
&objectAttributes
)))
{
WepCloseServerObjects();
return FALSE;
}
}
if (!WeServerSharedSectionEvent)
{
WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName);
InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenEvent(
&WeServerSharedSectionEvent,
EVENT_ALL_ACCESS,
&objectAttributes
)))
{
WepCloseServerObjects();
return FALSE;
}
}
return TRUE;
}
VOID WepCloseServerObjects(
VOID
)
{
if (WeServerSharedSection)
{
NtClose(WeServerSharedSection);
WeServerSharedSection = NULL;
}
if (WeServerSharedData)
{
NtUnmapViewOfSection(NtCurrentProcess(), WeServerSharedData);
WeServerSharedData = NULL;
}
if (WeServerSharedSectionLock)
{
NtClose(WeServerSharedSectionLock);
WeServerSharedSectionLock = NULL;
}
if (WeServerSharedSectionEvent)
{
NtClose(WeServerSharedSectionEvent);
WeServerSharedSectionEvent = NULL;
}
}
BOOLEAN WeIsServerActive(
VOID
)
{
if (WepOpenServerObjects())
{
WepCloseServerObjects();
return TRUE;
}
else
{
return FALSE;
}
}
BOOLEAN WeLockServerSharedData(
_Out_ PWE_HOOK_SHARED_DATA *Data
)
{
LARGE_INTEGER timeout;
if (!WeServerSharedSectionLock)
return FALSE;
timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS;
if (NtWaitForSingleObject(WeServerSharedSectionLock, FALSE, &timeout) != WAIT_OBJECT_0)
return FALSE;
*Data = WeServerSharedData;
return TRUE;
}
VOID WeUnlockServerSharedData(
VOID
)
{
NtReleaseMutant(WeServerSharedSectionLock, NULL);
}
BOOLEAN WeSendServerRequest(
_In_ HWND hWnd
)
{
ULONG threadId;
ULONG processId;
LARGE_INTEGER timeout;
if (!WeServerSharedData || !WeServerSharedSectionEvent)
return FALSE;
threadId = GetWindowThreadProcessId(hWnd, &processId);
if (UlongToHandle(processId) == NtCurrentProcessId())
{
// We are trying to get information about the server. Call the procedure directly.
WepWriteClientData(hWnd);
return TRUE;
}
// Call the client and wait for the client to finish.
WeCurrentMessageId++;
WeServerSharedData->MessageId = WeCurrentMessageId;
NtResetEvent(WeServerSharedSectionEvent, NULL);
if (!SendNotifyMessage(hWnd, WeServerMessage, (WPARAM)NtCurrentProcessId(), WeCurrentMessageId))
return FALSE;
timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS;
if (NtWaitForSingleObject(WeServerSharedSectionEvent, FALSE, &timeout) != STATUS_WAIT_0)
return FALSE;
return TRUE;
}
// Client
VOID WeHookClientInitialization(
VOID
)
{
WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME);
}
VOID WeHookClientUninitialization(
VOID
)
{
NOTHING;
}
VOID WepWriteClientData(
_In_ HWND hwnd
)
{
WCHAR className[256];
LOGICAL isUnicode;
memset(&WeServerSharedData->c, 0, sizeof(WeServerSharedData->c));
isUnicode = IsWindowUnicode(hwnd);
if (isUnicode)
{
WeServerSharedData->c.WndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
WeServerSharedData->c.DlgProc = GetWindowLongPtrW(hwnd, DWLP_DLGPROC);
}
else
{
WeServerSharedData->c.WndProc = GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
WeServerSharedData->c.DlgProc = GetWindowLongPtrA(hwnd, DWLP_DLGPROC);
}
if (!GetClassName(hwnd, className, sizeof(className) / sizeof(WCHAR)))
className[0] = 0;
WeServerSharedData->c.ClassInfo.cbSize = sizeof(WNDCLASSEX);
GetClassInfoEx(NULL, className, &WeServerSharedData->c.ClassInfo);
if (isUnicode)
WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrW(hwnd, GCLP_WNDPROC);
else
WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrA(hwnd, GCLP_WNDPROC);
}
LRESULT CALLBACK WepCallWndProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LRESULT result;
PCWPSTRUCT info;
result = CallNextHookEx(NULL, nCode, wParam, lParam);
info = (PCWPSTRUCT)lParam;
if (info->message == WeServerMessage)
{
HANDLE serverProcessId;
ULONG messageId;
serverProcessId = (HANDLE)info->wParam;
messageId = (ULONG)info->lParam;
if (serverProcessId != NtCurrentProcessId())
{
if (WepOpenServerObjects())
{
if (WeServerSharedData->MessageId == messageId)
{
WepWriteClientData(info->hwnd);
NtSetEvent(WeServerSharedSectionEvent, NULL);
}
WepCloseServerObjects();
}
}
}
return result;
}

View File

@@ -0,0 +1,390 @@
/*
* Process Hacker Window Explorer -
* main program
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wndexp.h"
#include "resource.h"
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI UnloadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI MainMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI ProcessPropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI ThreadMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
BOOLEAN IsHookClient;
PPH_PLUGIN PluginInstance;
PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration;
LOGICAL DllMain(
_In_ HINSTANCE Instance,
_In_ ULONG Reason,
_Reserved_ PVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
{
PPH_PLUGIN_INFORMATION info;
BOOLEAN isClient;
isClient = FALSE;
if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhLibImageBase"))
{
isClient = TRUE;
}
else
{
// WindowExplorer appears to be loading within Process Hacker. However, if there is
// already a server instance, the the hook will be active, and our DllMain routine
// will most likely be called before the plugin system is even initialized. Attempting
// to register a plugin would result in an access violation, so load as a client for now.
if (WeIsServerActive())
isClient = TRUE;
}
if (isClient)
{
// This DLL is being loaded not as a Process Hacker plugin, but as a hook.
IsHookClient = TRUE;
WeHookClientInitialization();
break;
}
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L"Window Explorer";
info->Author = L"wj32";
info->Description = L"View and manipulate windows.";
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1116";
info->HasOptions = FALSE;
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
LoadCallback,
NULL,
&PluginLoadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackUnload),
UnloadCallback,
NULL,
&PluginUnloadCallbackRegistration
);
//PhRegisterCallback(
// PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
// ShowOptionsCallback,
// NULL,
// &PluginShowOptionsCallbackRegistration
// );
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),
MenuItemCallback,
NULL,
&PluginMenuItemCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackMainMenuInitializing),
MainMenuInitializingCallback,
NULL,
&MainMenuInitializingCallbackRegistration
);
//PhRegisterCallback(
// PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing),
// ProcessPropertiesInitializingCallback,
// NULL,
// &ProcessPropertiesInitializingCallbackRegistration
// );
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing),
ProcessMenuInitializingCallback,
NULL,
&ProcessMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing),
ThreadMenuInitializingCallback,
NULL,
&ThreadMenuInitializingCallbackRegistration
);
{
static PH_SETTING_CREATE settings[] =
{
{ IntegerSettingType, SETTING_NAME_SHOW_DESKTOP_WINDOWS, L"0" },
{ StringSettingType, SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, L"" },
{ IntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_POSITION, L"100,100" },
{ ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" }
};
PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE));
}
}
break;
case DLL_PROCESS_DETACH:
{
if (IsHookClient)
{
WeHookClientUninitialization();
}
}
break;
}
return TRUE;
}
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI UnloadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
WeHookServerUninitialization();
}
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
BOOL CALLBACK WepEnumDesktopProc(
_In_ LPTSTR lpszDesktop,
_In_ LPARAM lParam
)
{
PhAddItemList((PPH_LIST)lParam, PhaCreateString(lpszDesktop)->Buffer);
return TRUE;
}
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
switch (menuItem->Id)
{
case ID_VIEW_WINDOWS:
{
WE_WINDOW_SELECTOR selector;
selector.Type = WeWindowSelectorAll;
WeShowWindowsDialog(WE_PhMainWndHandle, &selector);
}
break;
case ID_VIEW_DESKTOPWINDOWS:
{
PPH_LIST desktopNames;
PPH_STRING selectedChoice = NULL;
desktopNames = PH_AUTO(PhCreateList(4));
EnumDesktops(GetProcessWindowStation(), WepEnumDesktopProc, (LPARAM)desktopNames);
if (PhaChoiceDialog(
WE_PhMainWndHandle,
L"Desktop Windows",
L"Display windows for the following desktop:",
(PWSTR *)desktopNames->Items,
desktopNames->Count,
NULL,
PH_CHOICE_DIALOG_CHOICE,
&selectedChoice,
NULL,
NULL
))
{
WE_WINDOW_SELECTOR selector;
selector.Type = WeWindowSelectorDesktop;
PhSetReference(&selector.Desktop.DesktopName, selectedChoice);
WeShowWindowsDialog(WE_PhMainWndHandle, &selector);
}
}
break;
case ID_PROCESS_WINDOWS:
{
WE_WINDOW_SELECTOR selector;
selector.Type = WeWindowSelectorProcess;
selector.Process.ProcessId = ((PPH_PROCESS_ITEM)menuItem->Context)->ProcessId;
WeShowWindowsDialog(WE_PhMainWndHandle, &selector);
}
break;
case ID_THREAD_WINDOWS:
{
WE_WINDOW_SELECTOR selector;
selector.Type = WeWindowSelectorThread;
selector.Thread.ThreadId = ((PPH_THREAD_ITEM)menuItem->Context)->ThreadId;
WeShowWindowsDialog(WE_PhMainWndHandle, &selector);
}
break;
}
}
VOID NTAPI MainMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
ULONG insertIndex;
PPH_EMENU_ITEM menuItem;
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_VIEW)
return;
if (menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"System Information", 0))
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1;
else
insertIndex = 0;
PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_WINDOWS, L"Windows", NULL), insertIndex);
if (PhGetIntegerSetting(SETTING_NAME_SHOW_DESKTOP_WINDOWS))
{
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1;
PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_DESKTOPWINDOWS, L"Desktop Windows...", NULL), insertIndex);
}
}
VOID NTAPI ProcessPropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_PROCESS_ITEM processItem;
ULONG flags;
PPH_EMENU_ITEM miscMenu;
if (menuInfo->u.Process.NumberOfProcesses == 1)
processItem = menuInfo->u.Process.Processes[0];
else
processItem = NULL;
flags = 0;
if (!processItem)
flags = PH_EMENU_DISABLED;
miscMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0);
if (miscMenu)
{
PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WINDOWS, L"Windows", processItem), -1);
}
}
VOID NTAPI ThreadMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_THREAD_ITEM threadItem;
ULONG insertIndex;
PPH_EMENU_ITEM menuItem;
if (menuInfo->u.Thread.NumberOfThreads == 1)
threadItem = menuInfo->u.Thread.Threads[0];
else
threadItem = NULL;
if (menuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Token", 0))
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1;
else
insertIndex = 0;
PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_WINDOWS,
L"Windows", threadItem), insertIndex);
if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED;
}

View File

@@ -0,0 +1,81 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by WindowExplorer.rc
//
#define IDD_WNDPROPS 9
#define IDD_WNDLIST 101
#define ID_VIEW_WINDOWS 101
#define ID_THREAD_WINDOWS 102
#define ID_PROCESS_WINDOWS 103
#define IDR_WINDOW 103
#define ID_SHOWCONTEXTMENU 104
#define IDD_WNDGENERAL 104
#define ID_VIEW_DESKTOPWINDOWS 105
#define IDD_WNDSTYLES 105
#define IDD_WNDCLASS 106
#define IDD_WNDGENERAL1 106
#define IDC_LIST 1001
#define IDC_REFRESH 1002
#define IDC_TEXT 1009
#define IDC_RECTANGLE 1010
#define IDC_NORMALRECTANGLE 1011
#define IDC_CLIENTRECTANGLE 1012
#define IDC_THREAD 1016
#define IDC_STYLESLIST 1017
#define IDC_STYLES 1018
#define IDC_EXTENDEDSTYLES 1019
#define IDC_EXTENDEDSTYLESLIST 1020
#define IDC_INSTANCEHANDLE 1021
#define IDC_MENUHANDLE 1022
#define IDC_WINDOWPROC 1023
#define IDC_WINDOWPROC2 1024
#define IDC_DIALOGPROC 1024
#define IDC_USERDATA 1025
#define IDC_NAME 1026
#define IDC_ATOM 1028
#define IDC_CURSORHANDLE 1029
#define IDC_ICONHANDLE 1030
#define IDC_ICONHANDLE2 1031
#define IDC_SMALLICONHANDLE 1031
#define IDC_BACKGROUNDBRUSH 1032
#define IDC_MENUNAME 1033
#define IDC_UNICODE 1034
#define IDC_CTRLID 1035
#define ID_WINDOW_GOTOTHREAD 40001
#define ID_WINDOW_COPY 40002
#define ID_WINDOW_PROPERTIES 40003
#define ID_WINDOW_BRINGTOFRONT 40004
#define ID_WINDOW_RESTORE 40005
#define ID_WINDOW_MINIMIZE 40006
#define ID_WINDOW_MAXIMIZE 40007
#define ID_WINDOW_CLOSE 40008
#define ID_WINDOW_SHOW 40009
#define ID_WINDOW_HIGHLIGHT 40010
#define ID_WINDOW_SHOWHIDE 40011
#define ID_WINDOW_ENABLE 40012
#define ID_WINDOW_ENABLEDISABLE 40013
#define ID_WINDOW_ALWAYSONTOP 40014
#define ID_WINDOW_OPACITY 40015
#define ID_OPACITY_10 40016
#define ID_OPACITY_20 40017
#define ID_OPACITY_30 40018
#define ID_OPACITY_40 40019
#define ID_OPACITY_50 40020
#define ID_OPACITY_60 40021
#define ID_OPACITY_70 40022
#define ID_OPACITY_80 40023
#define ID_OPACITY_90 40024
#define ID_OPACITY_OPAQUE 40025
#define ID_WINDOW_VISIBLE 40026
#define ID_WINDOW_ENABLED 40027
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 108
#define _APS_NEXT_COMMAND_VALUE 40028
#define _APS_NEXT_CONTROL_VALUE 1035
#define _APS_NEXT_SYMED_VALUE 106
#endif
#endif

View File

@@ -0,0 +1,104 @@
/*
* Process Hacker Window Explorer -
* utility functions
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wndexp.h"
// WARNING: No functions from ProcessHacker.exe should be used in this file!
PVOID WeGetProcedureAddress(
_In_ PSTR Name
)
{
static PVOID imageBase = NULL;
if (!imageBase)
imageBase = GetModuleHandle(L"ProcessHacker.exe");
return (PVOID)GetProcAddress(imageBase, Name);
}
VOID WeFormatLocalObjectName(
_In_ PWSTR OriginalName,
_Inout_updates_(256) PWCHAR Buffer,
_Out_ PUNICODE_STRING ObjectName
)
{
SIZE_T length;
SIZE_T originalNameLength;
// Sessions other than session 0 require SeCreateGlobalPrivilege.
if (NtCurrentPeb()->SessionId != 0)
{
memcpy(Buffer, L"\\Sessions\\", 10 * sizeof(WCHAR));
_ultow(NtCurrentPeb()->SessionId, Buffer + 10, 10);
length = wcslen(Buffer);
originalNameLength = wcslen(OriginalName);
memcpy(Buffer + length, OriginalName, (originalNameLength + 1) * sizeof(WCHAR));
length += originalNameLength;
ObjectName->Buffer = Buffer;
ObjectName->MaximumLength = (ObjectName->Length = (USHORT)(length * sizeof(WCHAR))) + sizeof(WCHAR);
}
else
{
RtlInitUnicodeString(ObjectName, OriginalName);
}
}
VOID WeInvertWindowBorder(
_In_ HWND hWnd
)
{
RECT rect;
HDC hdc;
GetWindowRect(hWnd, &rect);
hdc = GetWindowDC(hWnd);
if (hdc)
{
ULONG penWidth = GetSystemMetrics(SM_CXBORDER) * 3;
INT oldDc;
HPEN pen;
HBRUSH brush;
oldDc = SaveDC(hdc);
// Get an inversion effect.
SetROP2(hdc, R2_NOT);
pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00));
SelectObject(hdc, pen);
brush = GetStockObject(NULL_BRUSH);
SelectObject(hdc, brush);
// Draw the rectangle.
Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
// Cleanup.
DeleteObject(pen);
RestoreDC(hdc, oldDc);
ReleaseDC(hWnd, hdc);
}
}

View File

@@ -0,0 +1,729 @@
/*
* Process Hacker Window Explorer -
* window tree dialog
*
* Copyright (C) 2016 dmex
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wndexp.h"
#include "resource.h"
#include <windowsx.h>
typedef struct _WINDOWS_CONTEXT
{
HWND TreeNewHandle;
WE_WINDOW_TREE_CONTEXT TreeContext;
WE_WINDOW_SELECTOR Selector;
PH_LAYOUT_MANAGER LayoutManager;
HWND HighlightingWindow;
ULONG HighlightingWindowCount;
} WINDOWS_CONTEXT, *PWINDOWS_CONTEXT;
VOID WepShowWindowsDialogCallback(
_In_ PVOID Parameter
);
INT_PTR CALLBACK WepWindowsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
static RECT MinimumSize = { -1, -1, -1, -1 };
VOID WeShowWindowsDialog(
_In_ HWND ParentWindowHandle,
_In_ PWE_WINDOW_SELECTOR Selector
)
{
PWINDOWS_CONTEXT context;
context = PhAllocate(sizeof(WINDOWS_CONTEXT));
memset(context, 0, sizeof(WINDOWS_CONTEXT));
memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR));
ProcessHacker_Invoke(WE_PhMainWndHandle, WepShowWindowsDialogCallback, context);
}
VOID WepShowWindowsDialogCallback(
_In_ PVOID Parameter
)
{
HWND hwnd;
PWINDOWS_CONTEXT context = Parameter;
hwnd = CreateDialogParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_WNDLIST),
NULL,
WepWindowsDlgProc,
(LPARAM)context
);
ShowWindow(hwnd, SW_SHOW);
}
VOID WepDeleteWindowSelector(
_In_ PWE_WINDOW_SELECTOR Selector
)
{
switch (Selector->Type)
{
case WeWindowSelectorDesktop:
PhDereferenceObject(Selector->Desktop.DesktopName);
break;
}
}
VOID WepFillWindowInfo(
_In_ PWE_WINDOW_NODE Node
)
{
HWND hwnd;
ULONG threadId;
ULONG processId;
hwnd = Node->WindowHandle;
GetClassName(hwnd, Node->WindowClass, sizeof(Node->WindowClass) / sizeof(WCHAR));
Node->WindowText = PhGetWindowText(hwnd);
if (!Node->WindowText)
Node->WindowText = PhReferenceEmptyString();
threadId = GetWindowThreadProcessId(hwnd, &processId);
Node->ClientId.UniqueProcess = UlongToHandle(processId);
Node->ClientId.UniqueThread = UlongToHandle(threadId);
Node->WindowVisible = !!IsWindowVisible(hwnd);
Node->HasChildren = !!FindWindowEx(hwnd, NULL, NULL, NULL);
}
VOID WepAddChildWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_In_opt_ PWE_WINDOW_NODE ParentNode,
_In_ HWND hwnd
)
{
PWE_WINDOW_NODE childNode;
childNode = WeAddWindowNode(Context);
childNode->WindowHandle = hwnd;
WepFillWindowInfo(childNode);
childNode->Node.Expanded = FALSE;
if (ParentNode)
{
// This is a child node.
childNode->Parent = ParentNode;
PhAddItemList(ParentNode->Children, childNode);
}
else
{
// This is a root node.
PhAddItemList(Context->NodeRootList, childNode);
}
}
VOID WepAddChildWindows(
_In_ PWINDOWS_CONTEXT Context,
_In_opt_ PWE_WINDOW_NODE ParentNode,
_In_ HWND hwnd,
_In_opt_ HANDLE FilterProcessId,
_In_opt_ HANDLE FilterThreadId
)
{
HWND childWindow = NULL;
ULONG i = 0;
// We use FindWindowEx because EnumWindows doesn't return Metro app windows.
// Set a reasonable limit to prevent infinite loops.
while (i < 0x800 && (childWindow = FindWindowEx(hwnd, childWindow, NULL, NULL)))
{
ULONG processId;
ULONG threadId;
threadId = GetWindowThreadProcessId(childWindow, &processId);
if (
(!FilterProcessId || UlongToHandle(processId) == FilterProcessId) &&
(!FilterThreadId || UlongToHandle(threadId) == FilterThreadId)
)
{
WepAddChildWindowNode(&Context->TreeContext, ParentNode, childWindow);
}
i++;
}
}
BOOL CALLBACK WepEnumDesktopWindowsProc(
_In_ HWND hwnd,
_In_ LPARAM lParam
)
{
PWINDOWS_CONTEXT context = (PWINDOWS_CONTEXT)lParam;
WepAddChildWindowNode(&context->TreeContext, NULL, hwnd);
return TRUE;
}
VOID WepAddDesktopWindows(
_In_ PWINDOWS_CONTEXT Context,
_In_ PWSTR DesktopName
)
{
HDESK desktopHandle;
if (desktopHandle = OpenDesktop(DesktopName, 0, FALSE, DESKTOP_ENUMERATE))
{
EnumDesktopWindows(desktopHandle, WepEnumDesktopWindowsProc, (LPARAM)Context);
CloseDesktop(desktopHandle);
}
}
VOID WepRefreshWindows(
_In_ PWINDOWS_CONTEXT Context
)
{
TreeNew_SetRedraw(Context->TreeNewHandle, FALSE);
WeClearWindowTree(&Context->TreeContext);
TreeNew_NodesStructured(Context->TreeNewHandle);
switch (Context->Selector.Type)
{
case WeWindowSelectorAll:
{
PWE_WINDOW_NODE desktopNode;
desktopNode = WeAddWindowNode(&Context->TreeContext);
desktopNode->WindowHandle = GetDesktopWindow();
WepFillWindowInfo(desktopNode);
PhAddItemList(Context->TreeContext.NodeRootList, desktopNode);
WepAddChildWindows(Context, desktopNode, desktopNode->WindowHandle, NULL, NULL);
desktopNode->HasChildren = TRUE;
desktopNode->Opened = TRUE;
}
break;
case WeWindowSelectorThread:
{
WepAddChildWindows(Context, NULL, GetDesktopWindow(), NULL, Context->Selector.Thread.ThreadId);
}
break;
case WeWindowSelectorProcess:
{
WepAddChildWindows(Context, NULL, GetDesktopWindow(), Context->Selector.Process.ProcessId, NULL);
}
break;
case WeWindowSelectorDesktop:
{
WepAddDesktopWindows(Context, Context->Selector.Desktop.DesktopName->Buffer);
}
break;
}
TreeNew_SetRedraw(Context->TreeNewHandle, TRUE);
}
PPH_STRING WepGetWindowTitleForSelector(
_In_ PWE_WINDOW_SELECTOR Selector
)
{
switch (Selector->Type)
{
case WeWindowSelectorAll:
{
return PhCreateString(L"Windows - All");
}
break;
case WeWindowSelectorThread:
{
return PhFormatString(L"Windows - Thread %lu", HandleToUlong(Selector->Thread.ThreadId));
}
break;
case WeWindowSelectorProcess:
{
CLIENT_ID clientId;
clientId.UniqueProcess = Selector->Process.ProcessId;
clientId.UniqueThread = NULL;
return PhConcatStrings2(L"Windows - ", PH_AUTO_T(PH_STRING, PhGetClientIdName(&clientId))->Buffer);
}
break;
case WeWindowSelectorDesktop:
{
return PhFormatString(L"Windows - Desktop \"%s\"", Selector->Desktop.DesktopName->Buffer);
}
break;
default:
return PhCreateString(L"Windows");
}
}
INT_PTR CALLBACK WepWindowsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PWINDOWS_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PWINDOWS_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PWINDOWS_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_STRING windowTitle;
PH_RECTANGLE windowRectangle;
context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST);
WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext);
PhRegisterDialog(hwndDlg);
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL);
if (MinimumSize.left == -1)
{
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 160;
rect.bottom = 100;
MapDialogRect(hwndDlg, &rect);
MinimumSize = rect;
MinimumSize.left = 0;
}
// Set up the window position and size.
windowRectangle.Position = PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION);
windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_SIZE, TRUE).Pair;
PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);
MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top,
windowRectangle.Width, windowRectangle.Height, FALSE);
// Implement cascading by saving an offsetted rectangle.
windowRectangle.Left += 20;
windowRectangle.Top += 20;
PhSetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, windowRectangle.Position);
windowTitle = PH_AUTO(WepGetWindowTitleForSelector(&context->Selector));
SetWindowText(hwndDlg, windowTitle->Buffer);
WepRefreshWindows(context);
}
break;
case WM_DESTROY:
{
PhSaveWindowPlacementToSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, SETTING_NAME_WINDOWS_WINDOW_SIZE, hwndDlg);
PhDeleteLayoutManager(&context->LayoutManager);
PhUnregisterDialog(hwndDlg);
WeDeleteWindowTree(&context->TreeContext);
WepDeleteWindowSelector(&context->Selector);
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
//case IDOK:
DestroyWindow(hwndDlg);
break;
case IDC_REFRESH:
WepRefreshWindows(context);
break;
case ID_SHOWCONTEXTMENU:
{
POINT point;
PWE_WINDOW_NODE *windows;
ULONG numberOfWindows;
PPH_EMENU menu;
point.x = (SHORT)LOWORD(lParam);
point.y = (SHORT)HIWORD(lParam);
WeGetSelectedWindowNodes(
&context->TreeContext,
&windows,
&numberOfWindows
);
if (numberOfWindows != 0)
{
menu = PhCreateEMenu();
PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0);
PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
if (numberOfWindows == 1)
{
WINDOWPLACEMENT placement = { sizeof(placement) };
BYTE alpha;
ULONG flags;
ULONG i;
ULONG id;
// State
GetWindowPlacement(windows[0]->WindowHandle, &placement);
if (placement.showCmd == SW_MINIMIZE)
PhSetFlagsEMenuItem(menu, ID_WINDOW_MINIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
else if (placement.showCmd == SW_MAXIMIZE)
PhSetFlagsEMenuItem(menu, ID_WINDOW_MAXIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
else if (placement.showCmd == SW_NORMAL)
PhSetFlagsEMenuItem(menu, ID_WINDOW_RESTORE, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
// Visible
PhSetFlagsEMenuItem(menu, ID_WINDOW_VISIBLE, PH_EMENU_CHECKED,
(GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_VISIBLE) ? PH_EMENU_CHECKED : 0);
// Enabled
PhSetFlagsEMenuItem(menu, ID_WINDOW_ENABLED, PH_EMENU_CHECKED,
!(GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_DISABLED) ? PH_EMENU_CHECKED : 0);
// Always on Top
PhSetFlagsEMenuItem(menu, ID_WINDOW_ALWAYSONTOP, PH_EMENU_CHECKED,
(GetWindowLong(windows[0]->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST) ? PH_EMENU_CHECKED : 0);
// Opacity
if (GetLayeredWindowAttributes(windows[0]->WindowHandle, NULL, &alpha, &flags))
{
if (!(flags & LWA_ALPHA))
alpha = 255;
}
else
{
alpha = 255;
}
if (alpha == 255)
{
id = ID_OPACITY_OPAQUE;
}
else
{
id = 0;
// Due to integer division, we cannot use simple arithmetic to calculate which menu item to check.
for (i = 0; i < 10; i++)
{
if (alpha == (BYTE)(255 * (i + 1) / 10))
{
id = ID_OPACITY_10 + i;
break;
}
}
}
if (id != 0)
{
PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);
}
}
else
{
PhSetFlagsAllEMenuItems(menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0);
}
PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y);
PhDestroyEMenu(menu);
}
}
break;
case ID_WINDOW_BRINGTOFRONT:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
WINDOWPLACEMENT placement = { sizeof(placement) };
GetWindowPlacement(selectedNode->WindowHandle, &placement);
if (placement.showCmd == SW_MINIMIZE)
ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE);
else
SetForegroundWindow(selectedNode->WindowHandle);
}
}
break;
case ID_WINDOW_RESTORE:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE);
}
}
break;
case ID_WINDOW_MINIMIZE:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
ShowWindowAsync(selectedNode->WindowHandle, SW_MINIMIZE);
}
}
break;
case ID_WINDOW_MAXIMIZE:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
ShowWindowAsync(selectedNode->WindowHandle, SW_MAXIMIZE);
}
}
break;
case ID_WINDOW_CLOSE:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
PostMessage(selectedNode->WindowHandle, WM_CLOSE, 0, 0);
}
}
break;
case ID_WINDOW_VISIBLE:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
if (IsWindowVisible(selectedNode->WindowHandle))
{
selectedNode->WindowVisible = FALSE;
ShowWindowAsync(selectedNode->WindowHandle, SW_HIDE);
}
else
{
selectedNode->WindowVisible = TRUE;
ShowWindowAsync(selectedNode->WindowHandle, SW_SHOW);
}
PhInvalidateTreeNewNode(&selectedNode->Node, TN_CACHE_COLOR);
TreeNew_InvalidateNode(context->TreeNewHandle, &selectedNode->Node);
}
}
break;
case ID_WINDOW_ENABLED:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
EnableWindow(selectedNode->WindowHandle, !IsWindowEnabled(selectedNode->WindowHandle));
}
}
break;
case ID_WINDOW_ALWAYSONTOP:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
LOGICAL topMost;
topMost = GetWindowLong(selectedNode->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST;
SetWindowPos(selectedNode->WindowHandle, topMost ? HWND_NOTOPMOST : HWND_TOPMOST,
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
}
break;
case ID_OPACITY_10:
case ID_OPACITY_20:
case ID_OPACITY_30:
case ID_OPACITY_40:
case ID_OPACITY_50:
case ID_OPACITY_60:
case ID_OPACITY_70:
case ID_OPACITY_80:
case ID_OPACITY_90:
case ID_OPACITY_OPAQUE:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
ULONG opacity;
opacity = ((ULONG)LOWORD(wParam) - ID_OPACITY_10) + 1;
if (opacity == 10)
{
// Remove the WS_EX_LAYERED bit since it is not needed.
PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, 0);
RedrawWindow(selectedNode->WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
}
else
{
// Add the WS_EX_LAYERED bit so opacity will work.
PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED);
SetLayeredWindowAttributes(selectedNode->WindowHandle, 0, (BYTE)(255 * opacity / 10), LWA_ALPHA);
}
}
}
break;
case ID_WINDOW_HIGHLIGHT:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
if (context->HighlightingWindow)
{
if (context->HighlightingWindowCount & 1)
WeInvertWindowBorder(context->HighlightingWindow);
}
context->HighlightingWindow = selectedNode->WindowHandle;
context->HighlightingWindowCount = 10;
SetTimer(hwndDlg, 9, 100, NULL);
}
}
break;
case ID_WINDOW_GOTOTHREAD:
{
PWE_WINDOW_NODE selectedNode;
PPH_PROCESS_ITEM processItem;
PPH_PROCESS_PROPCONTEXT propContext;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
{
if (processItem = PhReferenceProcessItem(selectedNode->ClientId.UniqueProcess))
{
if (propContext = PhCreateProcessPropContext(WE_PhMainWndHandle, processItem))
{
PhSetSelectThreadIdProcessPropContext(propContext, selectedNode->ClientId.UniqueThread);
PhShowProcessProperties(propContext);
PhDereferenceObject(propContext);
}
PhDereferenceObject(processItem);
}
else
{
PhShowError(hwndDlg, L"The process does not exist.");
}
}
}
break;
case ID_WINDOW_PROPERTIES:
{
PWE_WINDOW_NODE selectedNode;
if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext))
WeShowWindowProperties(hwndDlg, selectedNode->WindowHandle);
}
break;
case ID_WINDOW_COPY:
{
PPH_STRING text;
text = PhGetTreeNewText(context->TreeNewHandle, 0);
PhSetClipboardString(hwndDlg, &text->sr);
PhDereferenceObject(text);
}
break;
}
}
break;
case WM_TIMER:
{
switch (wParam)
{
case 9:
{
WeInvertWindowBorder(context->HighlightingWindow);
if (--context->HighlightingWindowCount == 0)
KillTimer(hwndDlg, 9);
}
break;
}
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&context->LayoutManager);
}
break;
case WM_SIZING:
{
PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
}
break;
case WM_WE_PLUSMINUS:
{
PWE_WINDOW_NODE node = (PWE_WINDOW_NODE)lParam;
if (!node->Opened)
{
TreeNew_SetRedraw(context->TreeNewHandle, FALSE);
WepAddChildWindows(context, node, node->WindowHandle, NULL, NULL);
node->Opened = TRUE;
TreeNew_SetRedraw(context->TreeNewHandle, TRUE);
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,131 @@
#ifndef WNDEXP_H
#define WNDEXP_H
#include <phdk.h>
#include "wndtree.h"
extern BOOLEAN IsHookClient;
extern PPH_PLUGIN PluginInstance;
#define PLUGIN_NAME L"ProcessHacker.WindowExplorer"
#define SETTING_NAME_SHOW_DESKTOP_WINDOWS (PLUGIN_NAME L".ShowDesktopWindows")
#define SETTING_NAME_WINDOW_TREE_LIST_COLUMNS (PLUGIN_NAME L".WindowTreeListColumns")
#define SETTING_NAME_WINDOWS_WINDOW_POSITION (PLUGIN_NAME L".WindowsWindowPosition")
#define SETTING_NAME_WINDOWS_WINDOW_SIZE (PLUGIN_NAME L".WindowsWindowSize")
// hook
#define WE_SERVER_MESSAGE_NAME L"WE_ServerMessage"
#define WE_SERVER_SHARED_SECTION_NAME L"\\BaseNamedObjects\\WeSharedSection"
#define WE_SERVER_SHARED_SECTION_LOCK_NAME L"\\BaseNamedObjects\\WeSharedSectionLock"
#define WE_SERVER_SHARED_SECTION_EVENT_NAME L"\\BaseNamedObjects\\WeSharedSectionEvent"
#define WE_CLIENT_MESSAGE_TIMEOUT 2000
typedef struct _WE_HOOK_SHARED_DATA
{
ULONG MessageId;
struct
{
ULONG_PTR WndProc;
ULONG_PTR DlgProc;
WNDCLASSEX ClassInfo;
} c;
} WE_HOOK_SHARED_DATA, *PWE_HOOK_SHARED_DATA;
VOID WeHookServerInitialization(
VOID
);
VOID WeHookServerUninitialization(
VOID
);
BOOLEAN WeIsServerActive(
VOID
);
BOOLEAN WeLockServerSharedData(
_Out_ PWE_HOOK_SHARED_DATA *Data
);
VOID WeUnlockServerSharedData(
VOID
);
BOOLEAN WeSendServerRequest(
_In_ HWND hWnd
);
VOID WeHookClientInitialization(
VOID
);
VOID WeHookClientUninitialization(
VOID
);
// wnddlg
typedef enum _WE_WINDOW_SELECTOR_TYPE
{
WeWindowSelectorAll,
WeWindowSelectorProcess,
WeWindowSelectorThread,
WeWindowSelectorDesktop
} WE_WINDOW_SELECTOR_TYPE;
typedef struct _WE_WINDOW_SELECTOR
{
WE_WINDOW_SELECTOR_TYPE Type;
union
{
struct
{
HANDLE ProcessId;
} Process;
struct
{
HANDLE ThreadId;
} Thread;
struct
{
PPH_STRING DesktopName;
} Desktop;
};
} WE_WINDOW_SELECTOR, *PWE_WINDOW_SELECTOR;
VOID WeShowWindowsDialog(
_In_ HWND ParentWindowHandle,
_In_ PWE_WINDOW_SELECTOR Selector
);
#define WM_WE_PLUSMINUS (WM_APP + 1)
// wndprp
VOID WeShowWindowProperties(
_In_ HWND ParentWindowHandle,
_In_ HWND WindowHandle
);
// utils
#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhMainWndHandle"))
#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("WindowsVersion"))
PVOID WeGetProcedureAddress(
_In_ PSTR Name
);
VOID WeFormatLocalObjectName(
_In_ PWSTR OriginalName,
_Inout_updates_(256) PWCHAR Buffer,
_Out_ PUNICODE_STRING ObjectName
);
VOID WeInvertWindowBorder(
_In_ HWND hWnd
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,461 @@
/*
* Process Hacker Window Explorer -
* window treelist
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wndexp.h"
#include "resource.h"
BOOLEAN WepWindowNodeHashtableEqualFunction(
_In_ PVOID Entry1,
_In_ PVOID Entry2
);
ULONG WepWindowNodeHashtableHashFunction(
_In_ PVOID Entry
);
VOID WepDestroyWindowNode(
_In_ PWE_WINDOW_NODE WindowNode
);
BOOLEAN NTAPI WepWindowTreeNewCallback(
_In_ HWND hwnd,
_In_ PH_TREENEW_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2,
_In_opt_ PVOID Context
);
VOID WeInitializeWindowTree(
_In_ HWND ParentWindowHandle,
_In_ HWND TreeNewHandle,
_Out_ PWE_WINDOW_TREE_CONTEXT Context
)
{
HWND hwnd;
PPH_STRING settings;
memset(Context, 0, sizeof(WE_WINDOW_TREE_CONTEXT));
Context->NodeHashtable = PhCreateHashtable(
sizeof(PWE_WINDOW_NODE),
WepWindowNodeHashtableEqualFunction,
WepWindowNodeHashtableHashFunction,
100
);
Context->NodeList = PhCreateList(100);
Context->NodeRootList = PhCreateList(30);
Context->ParentWindowHandle = ParentWindowHandle;
Context->TreeNewHandle = TreeNewHandle;
hwnd = TreeNewHandle;
PhSetControlTheme(hwnd, L"explorer");
TreeNew_SetCallback(hwnd, WepWindowTreeNewCallback, Context);
PhAddTreeNewColumn(hwnd, WEWNTLC_CLASS, TRUE, L"Class", 180, PH_ALIGN_LEFT, 0, 0);
PhAddTreeNewColumn(hwnd, WEWNTLC_HANDLE, TRUE, L"Handle", 70, PH_ALIGN_LEFT, 1, 0);
PhAddTreeNewColumn(hwnd, WEWNTLC_TEXT, TRUE, L"Text", 220, PH_ALIGN_LEFT, 2, 0);
PhAddTreeNewColumn(hwnd, WEWNTLC_THREAD, TRUE, L"Thread", 150, PH_ALIGN_LEFT, 3, 0);
TreeNew_SetTriState(hwnd, TRUE);
TreeNew_SetSort(hwnd, 0, NoSortOrder);
settings = PhGetStringSetting(SETTING_NAME_WINDOW_TREE_LIST_COLUMNS);
PhCmLoadSettings(hwnd, &settings->sr);
PhDereferenceObject(settings);
}
VOID WeDeleteWindowTree(
_In_ PWE_WINDOW_TREE_CONTEXT Context
)
{
PPH_STRING settings;
ULONG i;
settings = PhCmSaveSettings(Context->TreeNewHandle);
PhSetStringSetting2(SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, &settings->sr);
PhDereferenceObject(settings);
for (i = 0; i < Context->NodeList->Count; i++)
WepDestroyWindowNode(Context->NodeList->Items[i]);
PhDereferenceObject(Context->NodeHashtable);
PhDereferenceObject(Context->NodeList);
PhDereferenceObject(Context->NodeRootList);
}
BOOLEAN WepWindowNodeHashtableEqualFunction(
_In_ PVOID Entry1,
_In_ PVOID Entry2
)
{
PWE_WINDOW_NODE windowNode1 = *(PWE_WINDOW_NODE *)Entry1;
PWE_WINDOW_NODE windowNode2 = *(PWE_WINDOW_NODE *)Entry2;
return windowNode1->WindowHandle == windowNode2->WindowHandle;
}
ULONG WepWindowNodeHashtableHashFunction(
_In_ PVOID Entry
)
{
return PhHashIntPtr((ULONG_PTR)(*(PWE_WINDOW_NODE *)Entry)->WindowHandle);
}
PWE_WINDOW_NODE WeAddWindowNode(
_Inout_ PWE_WINDOW_TREE_CONTEXT Context
)
{
PWE_WINDOW_NODE windowNode;
windowNode = PhAllocate(sizeof(WE_WINDOW_NODE));
memset(windowNode, 0, sizeof(WE_WINDOW_NODE));
PhInitializeTreeNewNode(&windowNode->Node);
memset(windowNode->TextCache, 0, sizeof(PH_STRINGREF) * WEWNTLC_MAXIMUM);
windowNode->Node.TextCache = windowNode->TextCache;
windowNode->Node.TextCacheSize = WEWNTLC_MAXIMUM;
windowNode->Children = PhCreateList(1);
PhAddEntryHashtable(Context->NodeHashtable, &windowNode);
PhAddItemList(Context->NodeList, windowNode);
TreeNew_NodesStructured(Context->TreeNewHandle);
return windowNode;
}
PWE_WINDOW_NODE WeFindWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_In_ HWND WindowHandle
)
{
WE_WINDOW_NODE lookupWindowNode;
PWE_WINDOW_NODE lookupWindowNodePtr = &lookupWindowNode;
PWE_WINDOW_NODE *windowNode;
lookupWindowNode.WindowHandle = WindowHandle;
windowNode = (PWE_WINDOW_NODE *)PhFindEntryHashtable(
Context->NodeHashtable,
&lookupWindowNodePtr
);
if (windowNode)
return *windowNode;
else
return NULL;
}
VOID WeRemoveWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_In_ PWE_WINDOW_NODE WindowNode
)
{
ULONG index;
// Remove from hashtable/list and cleanup.
PhRemoveEntryHashtable(Context->NodeHashtable, &WindowNode);
if ((index = PhFindItemList(Context->NodeList, WindowNode)) != -1)
PhRemoveItemList(Context->NodeList, index);
WepDestroyWindowNode(WindowNode);
TreeNew_NodesStructured(Context->TreeNewHandle);
}
VOID WepDestroyWindowNode(
_In_ PWE_WINDOW_NODE WindowNode
)
{
PhDereferenceObject(WindowNode->Children);
if (WindowNode->WindowText) PhDereferenceObject(WindowNode->WindowText);
if (WindowNode->ThreadString) PhDereferenceObject(WindowNode->ThreadString);
PhFree(WindowNode);
}
#define SORT_FUNCTION(Column) WepWindowTreeNewCompare##Column
#define BEGIN_SORT_FUNCTION(Column) static int __cdecl WepWindowTreeNewCompare##Column( \
_In_ void *_context, \
_In_ const void *_elem1, \
_In_ const void *_elem2 \
) \
{ \
PWE_WINDOW_NODE node1 = *(PWE_WINDOW_NODE *)_elem1; \
PWE_WINDOW_NODE node2 = *(PWE_WINDOW_NODE *)_elem2; \
int sortResult = 0;
#define END_SORT_FUNCTION \
return PhModifySort(sortResult, ((PWE_WINDOW_TREE_CONTEXT)_context)->TreeNewSortOrder); \
}
BEGIN_SORT_FUNCTION(Class)
{
sortResult = _wcsicmp(node1->WindowClass, node2->WindowClass);
}
END_SORT_FUNCTION
BEGIN_SORT_FUNCTION(Handle)
{
sortResult = uintptrcmp((ULONG_PTR)node1->WindowHandle, (ULONG_PTR)node2->WindowHandle);
}
END_SORT_FUNCTION
BEGIN_SORT_FUNCTION(Text)
{
sortResult = PhCompareString(node1->WindowText, node2->WindowText, TRUE);
}
END_SORT_FUNCTION
BEGIN_SORT_FUNCTION(Thread)
{
sortResult = uintptrcmp((ULONG_PTR)node1->ClientId.UniqueProcess, (ULONG_PTR)node2->ClientId.UniqueProcess);
if (sortResult == 0)
sortResult = uintptrcmp((ULONG_PTR)node1->ClientId.UniqueThread, (ULONG_PTR)node2->ClientId.UniqueThread);
}
END_SORT_FUNCTION
BOOLEAN NTAPI WepWindowTreeNewCallback(
_In_ HWND hwnd,
_In_ PH_TREENEW_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2,
_In_opt_ PVOID Context
)
{
PWE_WINDOW_TREE_CONTEXT context;
PWE_WINDOW_NODE node;
context = Context;
switch (Message)
{
case TreeNewGetChildren:
{
PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
node = (PWE_WINDOW_NODE)getChildren->Node;
if (context->TreeNewSortOrder == NoSortOrder)
{
if (!node)
{
getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items;
getChildren->NumberOfChildren = context->NodeRootList->Count;
}
else
{
getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;
getChildren->NumberOfChildren = node->Children->Count;
}
}
else
{
if (!node)
{
static PVOID sortFunctions[] =
{
SORT_FUNCTION(Class),
SORT_FUNCTION(Handle),
SORT_FUNCTION(Text),
SORT_FUNCTION(Thread)
};
int (__cdecl *sortFunction)(void *, const void *, const void *);
if (context->TreeNewSortColumn < WEWNTLC_MAXIMUM)
sortFunction = sortFunctions[context->TreeNewSortColumn];
else
sortFunction = NULL;
if (sortFunction)
{
qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context);
}
getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items;
getChildren->NumberOfChildren = context->NodeList->Count;
}
}
}
return TRUE;
case TreeNewIsLeaf:
{
PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
node = (PWE_WINDOW_NODE)isLeaf->Node;
if (context->TreeNewSortOrder == NoSortOrder)
isLeaf->IsLeaf = !node->HasChildren;
else
isLeaf->IsLeaf = TRUE;
}
return TRUE;
case TreeNewGetCellText:
{
PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
node = (PWE_WINDOW_NODE)getCellText->Node;
switch (getCellText->Id)
{
case WEWNTLC_CLASS:
PhInitializeStringRef(&getCellText->Text, node->WindowClass);
break;
case WEWNTLC_HANDLE:
PhPrintPointer(node->WindowHandleString, node->WindowHandle);
PhInitializeStringRef(&getCellText->Text, node->WindowHandleString);
break;
case WEWNTLC_TEXT:
getCellText->Text = PhGetStringRef(node->WindowText);
break;
case WEWNTLC_THREAD:
if (!node->ThreadString)
node->ThreadString = PhGetClientIdName(&node->ClientId);
getCellText->Text = PhGetStringRef(node->ThreadString);
break;
default:
return FALSE;
}
getCellText->Flags = TN_CACHE;
}
return TRUE;
case TreeNewGetNodeColor:
{
PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;
node = (PWE_WINDOW_NODE)getNodeColor->Node;
if (!node->WindowVisible)
getNodeColor->ForeColor = RGB(0x55, 0x55, 0x55);
getNodeColor->Flags = TN_CACHE;
}
return TRUE;
case TreeNewSortChanged:
{
TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder);
// Force a rebuild to sort the items.
TreeNew_NodesStructured(hwnd);
}
return TRUE;
case TreeNewKeyDown:
{
PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
switch (keyEvent->VirtualKey)
{
case 'C':
if (GetKeyState(VK_CONTROL) < 0)
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WINDOW_COPY, 0);
break;
}
}
return TRUE;
case TreeNewLeftDoubleClick:
{
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WINDOW_PROPERTIES, 0);
}
return TRUE;
case TreeNewNodeExpanding:
{
SendMessage(context->ParentWindowHandle, WM_WE_PLUSMINUS, 0, (LPARAM)Parameter1);
}
return FALSE;
case TreeNewContextMenu:
{
PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;
SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y));
}
return TRUE;
}
return FALSE;
}
VOID WeClearWindowTree(
_In_ PWE_WINDOW_TREE_CONTEXT Context
)
{
ULONG i;
for (i = 0; i < Context->NodeList->Count; i++)
WepDestroyWindowNode(Context->NodeList->Items[i]);
PhClearHashtable(Context->NodeHashtable);
PhClearList(Context->NodeList);
PhClearList(Context->NodeRootList);
}
PWE_WINDOW_NODE WeGetSelectedWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context
)
{
PWE_WINDOW_NODE windowNode = NULL;
ULONG i;
for (i = 0; i < Context->NodeList->Count; i++)
{
windowNode = Context->NodeList->Items[i];
if (windowNode->Node.Selected)
return windowNode;
}
return NULL;
}
VOID WeGetSelectedWindowNodes(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_Out_ PWE_WINDOW_NODE **Windows,
_Out_ PULONG NumberOfWindows
)
{
PPH_LIST list;
ULONG i;
list = PhCreateList(2);
for (i = 0; i < Context->NodeList->Count; i++)
{
PWE_WINDOW_NODE node = Context->NodeList->Items[i];
if (node->Node.Selected)
{
PhAddItemList(list, node);
}
}
*Windows = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);
*NumberOfWindows = list->Count;
PhDereferenceObject(list);
}

View File

@@ -0,0 +1,90 @@
#ifndef WNDTREE_H
#define WNDTREE_H
#define WEWNTLC_CLASS 0
#define WEWNTLC_HANDLE 1
#define WEWNTLC_TEXT 2
#define WEWNTLC_THREAD 3
#define WEWNTLC_MAXIMUM 4
typedef struct _WE_WINDOW_NODE
{
PH_TREENEW_NODE Node;
struct _WE_WINDOW_NODE *Parent;
PPH_LIST Children;
union
{
ULONG Flags;
struct
{
ULONG HasChildren : 1;
ULONG Opened : 1;
ULONG WindowVisible : 1;
ULONG Spare : 29;
};
};
PH_STRINGREF TextCache[WEWNTLC_MAXIMUM];
HWND WindowHandle;
WCHAR WindowClass[64];
PPH_STRING WindowText;
CLIENT_ID ClientId;
WCHAR WindowHandleString[PH_PTR_STR_LEN_1];
PPH_STRING ThreadString;
} WE_WINDOW_NODE, *PWE_WINDOW_NODE;
typedef struct _WE_WINDOW_TREE_CONTEXT
{
HWND ParentWindowHandle;
HWND TreeNewHandle;
ULONG TreeNewSortColumn;
PH_SORT_ORDER TreeNewSortOrder;
PPH_HASHTABLE NodeHashtable;
PPH_LIST NodeList;
PPH_LIST NodeRootList;
} WE_WINDOW_TREE_CONTEXT, *PWE_WINDOW_TREE_CONTEXT;
VOID WeInitializeWindowTree(
_In_ HWND ParentWindowHandle,
_In_ HWND TreeNewHandle,
_Out_ PWE_WINDOW_TREE_CONTEXT Context
);
VOID WeDeleteWindowTree(
_In_ PWE_WINDOW_TREE_CONTEXT Context
);
PWE_WINDOW_NODE WeAddWindowNode(
_Inout_ PWE_WINDOW_TREE_CONTEXT Context
);
PWE_WINDOW_NODE WeFindWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_In_ HWND WindowHandle
);
VOID WeRemoveWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_In_ PWE_WINDOW_NODE WindowNode
);
VOID WeClearWindowTree(
_In_ PWE_WINDOW_TREE_CONTEXT Context
);
PWE_WINDOW_NODE WeGetSelectedWindowNode(
_In_ PWE_WINDOW_TREE_CONTEXT Context
);
VOID WeGetSelectedWindowNodes(
_In_ PWE_WINDOW_TREE_CONTEXT Context,
_Out_ PWE_WINDOW_NODE **Windows,
_Out_ PULONG NumberOfWindows
);
#endif