1208 lines
36 KiB
C
1208 lines
36 KiB
C
/*
|
|
* Process Hacker Window Explorer -
|
|
* window properties
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
// Since the main message loop doesn't support property sheets, we need a separate thread to run
|
|
// property sheets on.
|
|
|
|
#include "wndexp.h"
|
|
#include "resource.h"
|
|
#include <workqueue.h>
|
|
#include <symprv.h>
|
|
#include <windowsx.h>
|
|
|
|
#define NUMBER_OF_PAGES 4
|
|
#define WEM_RESOLVE_DONE (WM_APP + 1234)
|
|
|
|
typedef struct _WINDOW_PROPERTIES_CONTEXT
|
|
{
|
|
LONG RefCount;
|
|
|
|
HWND ParentWindowHandle;
|
|
|
|
HWND WindowHandle;
|
|
CLIENT_ID ClientId;
|
|
PH_INITONCE SymbolProviderInitOnce;
|
|
PPH_SYMBOL_PROVIDER SymbolProvider;
|
|
LIST_ENTRY ResolveListHead;
|
|
PH_QUEUED_LOCK ResolveListLock;
|
|
|
|
PPH_STRING WndProcSymbol;
|
|
ULONG WndProcResolving;
|
|
PPH_STRING DlgProcSymbol;
|
|
ULONG DlgProcResolving;
|
|
PPH_STRING ClassWndProcSymbol;
|
|
ULONG ClassWndProcResolving;
|
|
|
|
BOOLEAN HookDataValid;
|
|
BOOLEAN HookDataSuccess;
|
|
ULONG_PTR WndProc;
|
|
ULONG_PTR DlgProc;
|
|
WNDCLASSEX ClassInfo;
|
|
} WINDOW_PROPERTIES_CONTEXT, *PWINDOW_PROPERTIES_CONTEXT;
|
|
|
|
typedef struct _SYMBOL_RESOLVE_CONTEXT
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
ULONG64 Address;
|
|
PPH_STRING Symbol;
|
|
PH_SYMBOL_RESOLVE_LEVEL ResolveLevel;
|
|
HWND NotifyWindow;
|
|
PWINDOW_PROPERTIES_CONTEXT Context;
|
|
ULONG Id;
|
|
} SYMBOL_RESOLVE_CONTEXT, *PSYMBOL_RESOLVE_CONTEXT;
|
|
|
|
typedef struct _STRING_INTEGER_PAIR
|
|
{
|
|
PWSTR String;
|
|
ULONG Integer;
|
|
} STRING_INTEGER_PAIR, *PSTRING_INTEGER_PAIR;
|
|
|
|
VOID WepReferenceWindowPropertiesContext(
|
|
_Inout_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
);
|
|
|
|
VOID WepDereferenceWindowPropertiesContext(
|
|
_Inout_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
);
|
|
|
|
HWND WepCreateWindowProperties(
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
);
|
|
|
|
INT CALLBACK WepPropSheetProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
LRESULT CALLBACK WepPropSheetWndProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
HPROPSHEETPAGE WepCommonCreatePage(
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context,
|
|
_In_ PWSTR Template,
|
|
_In_ DLGPROC DlgProc
|
|
);
|
|
|
|
INT CALLBACK WepCommonPropPageProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ LPPROPSHEETPAGE ppsp
|
|
);
|
|
|
|
NTSTATUS WepPropertiesThreadStart(
|
|
_In_ PVOID Parameter
|
|
);
|
|
|
|
INT_PTR CALLBACK WepWindowGeneralDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK WepWindowStylesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK WepWindowClassDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
INT_PTR CALLBACK WepWindowPropertiesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
);
|
|
|
|
#define DEFINE_PAIR(Symbol) { L#Symbol, Symbol }
|
|
|
|
static STRING_INTEGER_PAIR WepStylePairs[] =
|
|
{
|
|
DEFINE_PAIR(WS_POPUP),
|
|
DEFINE_PAIR(WS_CHILD),
|
|
DEFINE_PAIR(WS_MINIMIZE),
|
|
DEFINE_PAIR(WS_VISIBLE),
|
|
DEFINE_PAIR(WS_DISABLED),
|
|
DEFINE_PAIR(WS_CLIPSIBLINGS),
|
|
DEFINE_PAIR(WS_CLIPCHILDREN),
|
|
DEFINE_PAIR(WS_MAXIMIZE),
|
|
DEFINE_PAIR(WS_BORDER),
|
|
DEFINE_PAIR(WS_DLGFRAME),
|
|
DEFINE_PAIR(WS_VSCROLL),
|
|
DEFINE_PAIR(WS_HSCROLL),
|
|
DEFINE_PAIR(WS_SYSMENU),
|
|
DEFINE_PAIR(WS_THICKFRAME),
|
|
DEFINE_PAIR(WS_GROUP),
|
|
DEFINE_PAIR(WS_TABSTOP),
|
|
DEFINE_PAIR(WS_MINIMIZEBOX),
|
|
DEFINE_PAIR(WS_MAXIMIZEBOX)
|
|
};
|
|
|
|
static STRING_INTEGER_PAIR WepExtendedStylePairs[] =
|
|
{
|
|
DEFINE_PAIR(WS_EX_DLGMODALFRAME),
|
|
DEFINE_PAIR(WS_EX_NOPARENTNOTIFY),
|
|
DEFINE_PAIR(WS_EX_TOPMOST),
|
|
DEFINE_PAIR(WS_EX_ACCEPTFILES),
|
|
DEFINE_PAIR(WS_EX_TRANSPARENT),
|
|
DEFINE_PAIR(WS_EX_MDICHILD),
|
|
DEFINE_PAIR(WS_EX_TOOLWINDOW),
|
|
DEFINE_PAIR(WS_EX_WINDOWEDGE),
|
|
DEFINE_PAIR(WS_EX_CLIENTEDGE),
|
|
DEFINE_PAIR(WS_EX_CONTEXTHELP),
|
|
DEFINE_PAIR(WS_EX_RIGHT),
|
|
DEFINE_PAIR(WS_EX_RTLREADING),
|
|
DEFINE_PAIR(WS_EX_LEFTSCROLLBAR),
|
|
DEFINE_PAIR(WS_EX_CONTROLPARENT),
|
|
DEFINE_PAIR(WS_EX_STATICEDGE),
|
|
DEFINE_PAIR(WS_EX_APPWINDOW),
|
|
DEFINE_PAIR(WS_EX_LAYERED),
|
|
DEFINE_PAIR(WS_EX_NOINHERITLAYOUT),
|
|
DEFINE_PAIR(WS_EX_LAYOUTRTL),
|
|
DEFINE_PAIR(WS_EX_COMPOSITED),
|
|
DEFINE_PAIR(WS_EX_NOACTIVATE)
|
|
};
|
|
|
|
static STRING_INTEGER_PAIR WepClassStylePairs[] =
|
|
{
|
|
DEFINE_PAIR(CS_VREDRAW),
|
|
DEFINE_PAIR(CS_HREDRAW),
|
|
DEFINE_PAIR(CS_DBLCLKS),
|
|
DEFINE_PAIR(CS_OWNDC),
|
|
DEFINE_PAIR(CS_CLASSDC),
|
|
DEFINE_PAIR(CS_PARENTDC),
|
|
DEFINE_PAIR(CS_NOCLOSE),
|
|
DEFINE_PAIR(CS_SAVEBITS),
|
|
DEFINE_PAIR(CS_BYTEALIGNCLIENT),
|
|
DEFINE_PAIR(CS_BYTEALIGNWINDOW),
|
|
DEFINE_PAIR(CS_GLOBALCLASS),
|
|
DEFINE_PAIR(CS_IME),
|
|
DEFINE_PAIR(CS_DROPSHADOW)
|
|
};
|
|
|
|
HANDLE WePropertiesThreadHandle = NULL;
|
|
CLIENT_ID WePropertiesThreadClientId;
|
|
PH_EVENT WePropertiesThreadReadyEvent = PH_EVENT_INIT;
|
|
PPH_LIST WePropertiesCreateList;
|
|
PPH_LIST WePropertiesWindowList;
|
|
PH_QUEUED_LOCK WePropertiesCreateLock = PH_QUEUED_LOCK_INIT;
|
|
|
|
VOID WeShowWindowProperties(
|
|
_In_ HWND ParentWindowHandle,
|
|
_In_ HWND WindowHandle
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
ULONG threadId;
|
|
ULONG processId;
|
|
|
|
if (!WePropertiesCreateList)
|
|
WePropertiesCreateList = PhCreateList(4);
|
|
if (!WePropertiesWindowList)
|
|
WePropertiesWindowList = PhCreateList(4);
|
|
|
|
if (!WePropertiesThreadHandle)
|
|
{
|
|
WePropertiesThreadHandle = PhCreateThread(0, WepPropertiesThreadStart, NULL);
|
|
PhWaitForEvent(&WePropertiesThreadReadyEvent, NULL);
|
|
}
|
|
|
|
context = PhAllocate(sizeof(WINDOW_PROPERTIES_CONTEXT));
|
|
memset(context, 0, sizeof(WINDOW_PROPERTIES_CONTEXT));
|
|
context->RefCount = 1;
|
|
context->ParentWindowHandle = ParentWindowHandle;
|
|
context->WindowHandle = WindowHandle;
|
|
|
|
processId = 0;
|
|
threadId = GetWindowThreadProcessId(WindowHandle, &processId);
|
|
context->ClientId.UniqueProcess = UlongToHandle(processId);
|
|
context->ClientId.UniqueThread = UlongToHandle(threadId);
|
|
PhInitializeInitOnce(&context->SymbolProviderInitOnce);
|
|
InitializeListHead(&context->ResolveListHead);
|
|
PhInitializeQueuedLock(&context->ResolveListLock);
|
|
|
|
// Queue the window for creation and wake up the host thread.
|
|
PhAcquireQueuedLockExclusive(&WePropertiesCreateLock);
|
|
PhAddItemList(WePropertiesCreateList, context);
|
|
PhReleaseQueuedLockExclusive(&WePropertiesCreateLock);
|
|
PostThreadMessage(HandleToUlong(WePropertiesThreadClientId.UniqueThread), WM_NULL, 0, 0);
|
|
}
|
|
|
|
VOID WepReferenceWindowPropertiesContext(
|
|
_Inout_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
_InterlockedIncrement(&Context->RefCount);
|
|
}
|
|
|
|
VOID WepDereferenceWindowPropertiesContext(
|
|
_Inout_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
if (_InterlockedDecrement(&Context->RefCount) == 0)
|
|
{
|
|
PLIST_ENTRY listEntry;
|
|
|
|
PhClearReference(&Context->SymbolProvider);
|
|
|
|
// Destroy results that have not been processed by any property pages.
|
|
|
|
listEntry = Context->ResolveListHead.Flink;
|
|
|
|
while (listEntry != &Context->ResolveListHead)
|
|
{
|
|
PSYMBOL_RESOLVE_CONTEXT resolveContext;
|
|
|
|
resolveContext = CONTAINING_RECORD(listEntry, SYMBOL_RESOLVE_CONTEXT, ListEntry);
|
|
listEntry = listEntry->Flink;
|
|
|
|
PhClearReference(&resolveContext->Symbol);
|
|
PhFree(resolveContext);
|
|
}
|
|
|
|
PhClearReference(&Context->WndProcSymbol);
|
|
PhClearReference(&Context->DlgProcSymbol);
|
|
PhClearReference(&Context->ClassWndProcSymbol);
|
|
|
|
PhFree(Context);
|
|
}
|
|
}
|
|
|
|
static HWND WepCreateWindowProperties(
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
|
|
HPROPSHEETPAGE pages[NUMBER_OF_PAGES];
|
|
|
|
propSheetHeader.dwFlags =
|
|
PSH_MODELESS |
|
|
PSH_NOAPPLYNOW |
|
|
PSH_NOCONTEXTHELP |
|
|
PSH_PROPTITLE |
|
|
PSH_USECALLBACK;
|
|
propSheetHeader.hwndParent = Context->ParentWindowHandle;
|
|
propSheetHeader.pszCaption = PhaFormatString(L"Window %Ix", Context->WindowHandle)->Buffer;
|
|
propSheetHeader.nPages = 0;
|
|
propSheetHeader.nStartPage = 0;
|
|
propSheetHeader.phpage = pages;
|
|
propSheetHeader.pfnCallback = WepPropSheetProc;
|
|
|
|
// General
|
|
pages[propSheetHeader.nPages++] = WepCommonCreatePage(
|
|
Context,
|
|
MAKEINTRESOURCE(IDD_WNDGENERAL),
|
|
WepWindowGeneralDlgProc
|
|
);
|
|
// Styles
|
|
pages[propSheetHeader.nPages++] = WepCommonCreatePage(
|
|
Context,
|
|
MAKEINTRESOURCE(IDD_WNDSTYLES),
|
|
WepWindowStylesDlgProc
|
|
);
|
|
// Class
|
|
pages[propSheetHeader.nPages++] = WepCommonCreatePage(
|
|
Context,
|
|
MAKEINTRESOURCE(IDD_WNDCLASS),
|
|
WepWindowClassDlgProc
|
|
);
|
|
// Properties
|
|
pages[propSheetHeader.nPages++] = WepCommonCreatePage(
|
|
Context,
|
|
MAKEINTRESOURCE(IDD_WNDPROPS),
|
|
WepWindowPropertiesDlgProc
|
|
);
|
|
|
|
return (HWND)PropertySheet(&propSheetHeader);
|
|
}
|
|
|
|
static INT CALLBACK WepPropSheetProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case PSCB_INITIALIZED:
|
|
{
|
|
WNDPROC oldWndProc;
|
|
HWND refreshButtonHandle;
|
|
|
|
oldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC);
|
|
SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc);
|
|
SetProp(hwndDlg, L"OldWndProc", (HANDLE)oldWndProc);
|
|
|
|
// Hide the Cancel button.
|
|
ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE);
|
|
// Set the OK button's text to "Close".
|
|
SetDlgItemText(hwndDlg, IDOK, L"Close");
|
|
// Add the Refresh button.
|
|
refreshButtonHandle = CreateWindow(L"BUTTON", L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH,
|
|
PluginInstance->DllBase, NULL);
|
|
SendMessage(refreshButtonHandle, WM_SETFONT, (WPARAM)SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0), FALSE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CALLBACK WepPropSheetWndProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
WNDPROC oldWndProc = (WNDPROC)GetProp(hwnd, L"OldWndProc");
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
|
|
RemoveProp(hwnd, L"OldWndProc");
|
|
RemoveProp(hwnd, L"Moved");
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!GetProp(hwnd, L"Moved"))
|
|
{
|
|
// Move the Refresh button to where the OK button is, and move the OK button to
|
|
// where the Cancel button is.
|
|
// This must be done here because in the prop sheet callback the buttons are not
|
|
// in the right places.
|
|
PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDOK), GetDlgItem(hwnd, IDC_REFRESH));
|
|
PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDCANCEL), GetDlgItem(hwnd, IDOK));
|
|
SetProp(hwnd, L"Moved", (HANDLE)1);
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_REFRESH:
|
|
{
|
|
ULONG i;
|
|
HWND pageHandle;
|
|
|
|
// Broadcast the message to all property pages.
|
|
for (i = 0; i < NUMBER_OF_PAGES; i++)
|
|
{
|
|
if (pageHandle = PropSheet_IndexToHwnd(hwnd, i))
|
|
SendMessage(pageHandle, WM_COMMAND, IDC_REFRESH, 0);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
static HPROPSHEETPAGE WepCommonCreatePage(
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context,
|
|
_In_ PWSTR Template,
|
|
_In_ DLGPROC DlgProc
|
|
)
|
|
{
|
|
HPROPSHEETPAGE propSheetPageHandle;
|
|
PROPSHEETPAGE propSheetPage;
|
|
|
|
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
|
|
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propSheetPage.dwFlags = PSP_USECALLBACK;
|
|
propSheetPage.hInstance = PluginInstance->DllBase;
|
|
propSheetPage.pszTemplate = Template;
|
|
propSheetPage.pfnDlgProc = DlgProc;
|
|
propSheetPage.lParam = (LPARAM)Context;
|
|
propSheetPage.pfnCallback = WepCommonPropPageProc;
|
|
|
|
propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);
|
|
|
|
return propSheetPageHandle;
|
|
}
|
|
|
|
static INT CALLBACK WepCommonPropPageProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ LPPROPSHEETPAGE ppsp
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
|
|
context = (PWINDOW_PROPERTIES_CONTEXT)ppsp->lParam;
|
|
|
|
if (uMsg == PSPCB_ADDREF)
|
|
WepReferenceWindowPropertiesContext(context);
|
|
else if (uMsg == PSPCB_RELEASE)
|
|
WepDereferenceWindowPropertiesContext(context);
|
|
|
|
return 1;
|
|
}
|
|
|
|
NTSTATUS WepPropertiesThreadStart(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
PH_AUTO_POOL autoPool;
|
|
BOOL result;
|
|
MSG message;
|
|
BOOLEAN processed;
|
|
ULONG i;
|
|
|
|
PhInitializeAutoPool(&autoPool);
|
|
|
|
WePropertiesThreadClientId = NtCurrentTeb()->ClientId;
|
|
|
|
// Force the creation of the message queue so PostThreadMessage works.
|
|
PeekMessage(&message, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
|
PhSetEvent(&WePropertiesThreadReadyEvent);
|
|
|
|
while (result = GetMessage(&message, NULL, 0, 0))
|
|
{
|
|
if (result == -1)
|
|
break;
|
|
|
|
if (WePropertiesCreateList->Count != 0)
|
|
{
|
|
PhAcquireQueuedLockExclusive(&WePropertiesCreateLock);
|
|
|
|
for (i = 0; i < WePropertiesCreateList->Count; i++)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
HWND hwnd;
|
|
|
|
context = WePropertiesCreateList->Items[i];
|
|
hwnd = WepCreateWindowProperties(context);
|
|
WepDereferenceWindowPropertiesContext(context);
|
|
PhAddItemList(WePropertiesWindowList, hwnd);
|
|
}
|
|
|
|
PhClearList(WePropertiesCreateList);
|
|
PhReleaseQueuedLockExclusive(&WePropertiesCreateLock);
|
|
}
|
|
|
|
processed = FALSE;
|
|
|
|
for (i = 0; i < WePropertiesWindowList->Count; i++)
|
|
{
|
|
if (PropSheet_IsDialogMessage(WePropertiesWindowList->Items[i], &message))
|
|
{
|
|
processed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!processed)
|
|
{
|
|
TranslateMessage(&message);
|
|
DispatchMessage(&message);
|
|
}
|
|
|
|
// Destroy properties windows when necessary.
|
|
for (i = 0; i < WePropertiesWindowList->Count; i++)
|
|
{
|
|
if (!PropSheet_GetCurrentPageHwnd(WePropertiesWindowList->Items[i]))
|
|
{
|
|
DestroyWindow(WePropertiesWindowList->Items[i]);
|
|
PhRemoveItemList(WePropertiesWindowList, i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
PhDrainAutoPool(&autoPool);
|
|
}
|
|
|
|
PhDeleteAutoPool(&autoPool);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN WepPropPageDlgProcHeader(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ LPARAM lParam,
|
|
_Out_opt_ LPPROPSHEETPAGE *PropSheetPage,
|
|
_Out_opt_ PWINDOW_PROPERTIES_CONTEXT *Context
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
propSheetPage = (LPPROPSHEETPAGE)lParam;
|
|
// Save the context.
|
|
SetProp(hwndDlg, L"PropSheetPage", (HANDLE)lParam);
|
|
}
|
|
else
|
|
{
|
|
propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, L"PropSheetPage");
|
|
|
|
if (uMsg == WM_DESTROY)
|
|
RemoveProp(hwndDlg, L"PropSheetPage");
|
|
}
|
|
|
|
if (!propSheetPage)
|
|
return FALSE;
|
|
|
|
if (PropSheetPage)
|
|
*PropSheetPage = propSheetPage;
|
|
if (Context)
|
|
*Context = (PWINDOW_PROPERTIES_CONTEXT)propSheetPage->lParam;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID WepEnsureHookDataValid(
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
if (!Context->HookDataValid)
|
|
{
|
|
PWE_HOOK_SHARED_DATA data;
|
|
#ifdef _WIN64
|
|
HANDLE processHandle;
|
|
BOOLEAN isWow64 = FALSE;
|
|
#endif
|
|
|
|
// The desktop window is owned by CSR. The hook will never work on the desktop window.
|
|
if (Context->WindowHandle == GetDesktopWindow())
|
|
{
|
|
Context->HookDataValid = TRUE;
|
|
return;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
// We can't use the hook on WOW64 processes.
|
|
if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess)))
|
|
{
|
|
PhGetProcessIsWow64(processHandle, &isWow64);
|
|
NtClose(processHandle);
|
|
}
|
|
|
|
if (isWow64)
|
|
return;
|
|
#endif
|
|
|
|
WeHookServerInitialization();
|
|
|
|
Context->HookDataSuccess = FALSE;
|
|
|
|
if (WeLockServerSharedData(&data))
|
|
{
|
|
if (WeSendServerRequest(Context->WindowHandle))
|
|
{
|
|
Context->WndProc = data->c.WndProc;
|
|
Context->DlgProc = data->c.DlgProc;
|
|
memcpy(&Context->ClassInfo, &data->c.ClassInfo, sizeof(WNDCLASSEX));
|
|
Context->HookDataSuccess = TRUE;
|
|
}
|
|
|
|
WeUnlockServerSharedData();
|
|
}
|
|
|
|
Context->HookDataValid = TRUE;
|
|
}
|
|
}
|
|
|
|
static BOOLEAN NTAPI EnumGenericModulesCallback(
|
|
_In_ PPH_MODULE_INFO Module,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context = Context;
|
|
|
|
PhLoadModuleSymbolProvider(context->SymbolProvider, Module->FileName->Buffer,
|
|
(ULONG64)Module->BaseAddress, Module->Size);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static NTSTATUS WepResolveSymbolFunction(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
PSYMBOL_RESOLVE_CONTEXT context = Parameter;
|
|
|
|
if (PhBeginInitOnce(&context->Context->SymbolProviderInitOnce))
|
|
{
|
|
PhEnumGenericModules(context->Context->ClientId.UniqueProcess, NULL, 0, EnumGenericModulesCallback, context->Context);
|
|
PhEndInitOnce(&context->Context->SymbolProviderInitOnce);
|
|
}
|
|
|
|
context->Symbol = PhGetSymbolFromAddress(
|
|
context->Context->SymbolProvider,
|
|
(ULONG64)context->Address,
|
|
&context->ResolveLevel,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
// Fail if we don't have a symbol.
|
|
if (!context->Symbol)
|
|
{
|
|
WepDereferenceWindowPropertiesContext(context->Context);
|
|
PhFree(context);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PhAcquireQueuedLockExclusive(&context->Context->ResolveListLock);
|
|
InsertHeadList(&context->Context->ResolveListHead, &context->ListEntry);
|
|
PhReleaseQueuedLockExclusive(&context->Context->ResolveListLock);
|
|
|
|
PostMessage(context->NotifyWindow, WEM_RESOLVE_DONE, 0, (LPARAM)context);
|
|
|
|
WepDereferenceWindowPropertiesContext(context->Context);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static VOID WepQueueResolveSymbol(
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context,
|
|
_In_ HWND NotifyWindow,
|
|
_In_ ULONG64 Address,
|
|
_In_ ULONG Id
|
|
)
|
|
{
|
|
PSYMBOL_RESOLVE_CONTEXT resolveContext;
|
|
|
|
if (!Context->SymbolProvider)
|
|
{
|
|
Context->SymbolProvider = PhCreateSymbolProvider(Context->ClientId.UniqueProcess);
|
|
PhLoadSymbolProviderOptions(Context->SymbolProvider);
|
|
}
|
|
|
|
resolveContext = PhAllocate(sizeof(SYMBOL_RESOLVE_CONTEXT));
|
|
resolveContext->Address = Address;
|
|
resolveContext->Symbol = NULL;
|
|
resolveContext->ResolveLevel = PhsrlInvalid;
|
|
resolveContext->NotifyWindow = NotifyWindow;
|
|
resolveContext->Context = Context;
|
|
WepReferenceWindowPropertiesContext(Context);
|
|
resolveContext->Id = Id;
|
|
|
|
PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), WepResolveSymbolFunction, resolveContext);
|
|
}
|
|
|
|
static PPH_STRING WepFormatRect(
|
|
_In_ PRECT Rect
|
|
)
|
|
{
|
|
return PhaFormatString(L"(%d, %d) - (%d, %d) [%dx%d]",
|
|
Rect->left, Rect->top, Rect->right, Rect->bottom,
|
|
Rect->right - Rect->left, Rect->bottom - Rect->top);
|
|
}
|
|
|
|
static VOID WepRefreshWindowGeneralInfoSymbols(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
if (Context->WndProcResolving != 0)
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer);
|
|
else if (Context->WndProcSymbol)
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer);
|
|
else if (Context->WndProc != 0)
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer);
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown");
|
|
|
|
if (Context->DlgProcResolving != 0)
|
|
SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer);
|
|
else if (Context->DlgProcSymbol)
|
|
SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer);
|
|
else if (Context->DlgProc != 0)
|
|
SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer);
|
|
else if (Context->WndProc != 0)
|
|
SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"N/A");
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"Unknown");
|
|
}
|
|
|
|
static VOID WepRefreshWindowGeneralInfo(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
WINDOWINFO windowInfo = { sizeof(WINDOWINFO) };
|
|
WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT) };
|
|
MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
|
|
|
|
SetDlgItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle))));
|
|
|
|
if (GetWindowInfo(Context->WindowHandle, &windowInfo))
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_RECTANGLE, WepFormatRect(&windowInfo.rcWindow)->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, WepFormatRect(&windowInfo.rcClient)->Buffer);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_RECTANGLE, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, L"N/A");
|
|
}
|
|
|
|
if (GetWindowPlacement(Context->WindowHandle, &windowPlacement))
|
|
{
|
|
// The rectangle is in workspace coordinates. Convert the values back to screen coordinates.
|
|
if (GetMonitorInfo(MonitorFromRect(&windowPlacement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo))
|
|
{
|
|
windowPlacement.rcNormalPosition.left += monitorInfo.rcWork.left;
|
|
windowPlacement.rcNormalPosition.top += monitorInfo.rcWork.top;
|
|
windowPlacement.rcNormalPosition.right += monitorInfo.rcWork.left;
|
|
windowPlacement.rcNormalPosition.bottom += monitorInfo.rcWork.top;
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A");
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE))->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", GetMenu(Context->WindowHandle))->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA))->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No");
|
|
SetDlgItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", GetDlgCtrlID(Context->WindowHandle))->Buffer);
|
|
|
|
WepEnsureHookDataValid(Context);
|
|
|
|
if (Context->WndProc != 0)
|
|
{
|
|
Context->WndProcResolving++;
|
|
WepQueueResolveSymbol(Context, hwndDlg, Context->WndProc, 1);
|
|
}
|
|
|
|
if (Context->DlgProc != 0)
|
|
{
|
|
Context->DlgProcResolving++;
|
|
WepQueueResolveSymbol(Context, hwndDlg, Context->DlgProc, 2);
|
|
}
|
|
|
|
WepRefreshWindowGeneralInfoSymbols(hwndDlg, Context);
|
|
}
|
|
|
|
INT_PTR CALLBACK WepWindowGeneralDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
|
|
if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context))
|
|
return FALSE;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
WepRefreshWindowGeneralInfo(hwndDlg, context);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_REFRESH:
|
|
context->HookDataValid = FALSE;
|
|
PhClearReference(&context->WndProcSymbol);
|
|
WepRefreshWindowGeneralInfo(hwndDlg, context);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WEM_RESOLVE_DONE:
|
|
{
|
|
PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam;
|
|
|
|
if (resolveContext->Id == 1)
|
|
{
|
|
PhAcquireQueuedLockExclusive(&context->ResolveListLock);
|
|
RemoveEntryList(&resolveContext->ListEntry);
|
|
PhReleaseQueuedLockExclusive(&context->ResolveListLock);
|
|
|
|
if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction)
|
|
PhClearReference(&resolveContext->Symbol);
|
|
|
|
PhMoveReference(&context->WndProcSymbol, resolveContext->Symbol);
|
|
PhFree(resolveContext);
|
|
|
|
context->WndProcResolving--;
|
|
}
|
|
else if (resolveContext->Id == 2)
|
|
{
|
|
PhAcquireQueuedLockExclusive(&context->ResolveListLock);
|
|
RemoveEntryList(&resolveContext->ListEntry);
|
|
PhReleaseQueuedLockExclusive(&context->ResolveListLock);
|
|
|
|
if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction)
|
|
PhClearReference(&resolveContext->Symbol);
|
|
|
|
PhMoveReference(&context->DlgProcSymbol, resolveContext->Symbol);
|
|
PhFree(resolveContext);
|
|
|
|
context->DlgProcResolving--;
|
|
}
|
|
|
|
WepRefreshWindowGeneralInfoSymbols(hwndDlg, context);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID WepRefreshWindowStyles(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
WINDOWINFO windowInfo = { sizeof(WINDOWINFO) };
|
|
HWND stylesListBox;
|
|
HWND extendedStylesListBox;
|
|
ULONG i;
|
|
|
|
stylesListBox = GetDlgItem(hwndDlg, IDC_STYLESLIST);
|
|
extendedStylesListBox = GetDlgItem(hwndDlg, IDC_EXTENDEDSTYLESLIST);
|
|
|
|
ListBox_ResetContent(stylesListBox);
|
|
ListBox_ResetContent(extendedStylesListBox);
|
|
|
|
if (GetWindowInfo(Context->WindowHandle, &windowInfo))
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_STYLES, PhaFormatString(L"0x%x", windowInfo.dwStyle)->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, PhaFormatString(L"0x%x", windowInfo.dwExStyle)->Buffer);
|
|
|
|
for (i = 0; i < sizeof(WepStylePairs) / sizeof(STRING_INTEGER_PAIR); i++)
|
|
{
|
|
if (windowInfo.dwStyle & WepStylePairs[i].Integer)
|
|
{
|
|
// Skip irrelevant styles.
|
|
|
|
if (WepStylePairs[i].Integer == WS_MAXIMIZEBOX ||
|
|
WepStylePairs[i].Integer == WS_MINIMIZEBOX)
|
|
{
|
|
if (windowInfo.dwStyle & WS_CHILD)
|
|
continue;
|
|
}
|
|
|
|
if (WepStylePairs[i].Integer == WS_TABSTOP ||
|
|
WepStylePairs[i].Integer == WS_GROUP)
|
|
{
|
|
if (!(windowInfo.dwStyle & WS_CHILD))
|
|
continue;
|
|
}
|
|
|
|
ListBox_AddString(stylesListBox, WepStylePairs[i].String);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < sizeof(WepExtendedStylePairs) / sizeof(STRING_INTEGER_PAIR); i++)
|
|
{
|
|
if (windowInfo.dwExStyle & WepExtendedStylePairs[i].Integer)
|
|
{
|
|
ListBox_AddString(extendedStylesListBox, WepExtendedStylePairs[i].String);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_STYLES, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, L"N/A");
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK WepWindowStylesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
|
|
if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context))
|
|
return FALSE;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
WepRefreshWindowStyles(hwndDlg, context);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_REFRESH:
|
|
WepRefreshWindowStyles(hwndDlg, context);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID WepRefreshWindowClassInfoSymbols(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
if (Context->ClassWndProcResolving != 0)
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->ClassInfo.lpfnWndProc)->Buffer);
|
|
else if (Context->ClassWndProcSymbol)
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->ClassInfo.lpfnWndProc, Context->ClassWndProcSymbol->Buffer)->Buffer);
|
|
else if (Context->ClassInfo.lpfnWndProc)
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpfnWndProc)->Buffer);
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown");
|
|
}
|
|
|
|
static VOID WepRefreshWindowClassInfo(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
WCHAR className[256];
|
|
PH_STRING_BUILDER stringBuilder;
|
|
ULONG i;
|
|
|
|
if (!GetClassName(Context->WindowHandle, className, sizeof(className) / sizeof(WCHAR)))
|
|
className[0] = 0;
|
|
|
|
WepEnsureHookDataValid(Context);
|
|
|
|
if (!Context->HookDataSuccess)
|
|
{
|
|
Context->ClassInfo.cbSize = sizeof(WNDCLASSEX);
|
|
GetClassInfoEx(NULL, className, &Context->ClassInfo);
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_NAME, className);
|
|
SetDlgItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE))->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer);
|
|
|
|
PhInitializeStringBuilder(&stringBuilder, 100);
|
|
PhAppendFormatStringBuilder(&stringBuilder, L"0x%x (", Context->ClassInfo.style);
|
|
|
|
for (i = 0; i < sizeof(WepClassStylePairs) / sizeof(STRING_INTEGER_PAIR); i++)
|
|
{
|
|
if (Context->ClassInfo.style & WepClassStylePairs[i].Integer)
|
|
{
|
|
PhAppendStringBuilder2(&stringBuilder, WepClassStylePairs[i].String);
|
|
PhAppendStringBuilder2(&stringBuilder, L" | ");
|
|
}
|
|
}
|
|
|
|
if (PhEndsWithString2(stringBuilder.String, L" | ", FALSE))
|
|
{
|
|
PhRemoveEndStringBuilder(&stringBuilder, 3);
|
|
PhAppendCharStringBuilder(&stringBuilder, ')');
|
|
}
|
|
else
|
|
{
|
|
// No styles. Remove the brackets.
|
|
PhRemoveEndStringBuilder(&stringBuilder, 1);
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_STYLES, stringBuilder.String->Buffer);
|
|
PhDeleteStringBuilder(&stringBuilder);
|
|
|
|
// TODO: Add symbols for these values.
|
|
SetDlgItemText(hwndDlg, IDC_CURSORHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer);
|
|
SetDlgItemText(hwndDlg, IDC_BACKGROUNDBRUSH, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer);
|
|
|
|
if (Context->ClassInfo.lpfnWndProc)
|
|
{
|
|
Context->ClassWndProcResolving++;
|
|
WepQueueResolveSymbol(Context, hwndDlg, (ULONG_PTR)Context->ClassInfo.lpfnWndProc, 0);
|
|
}
|
|
|
|
WepRefreshWindowClassInfoSymbols(hwndDlg, Context);
|
|
}
|
|
|
|
INT_PTR CALLBACK WepWindowClassDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
|
|
if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context))
|
|
return FALSE;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
WepRefreshWindowClassInfo(hwndDlg, context);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_REFRESH:
|
|
context->HookDataValid = FALSE;
|
|
PhClearReference(&context->ClassWndProcSymbol);
|
|
WepRefreshWindowClassInfo(hwndDlg, context);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WEM_RESOLVE_DONE:
|
|
{
|
|
PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam;
|
|
|
|
PhAcquireQueuedLockExclusive(&context->ResolveListLock);
|
|
RemoveEntryList(&resolveContext->ListEntry);
|
|
PhReleaseQueuedLockExclusive(&context->ResolveListLock);
|
|
|
|
if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction)
|
|
PhClearReference(&resolveContext->Symbol);
|
|
|
|
PhMoveReference(&context->ClassWndProcSymbol, resolveContext->Symbol);
|
|
PhFree(resolveContext);
|
|
|
|
context->ClassWndProcResolving--;
|
|
WepRefreshWindowClassInfoSymbols(hwndDlg, context);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL CALLBACK EnumPropsExCallback(
|
|
_In_ HWND hwnd,
|
|
_In_ LPTSTR lpszString,
|
|
_In_ HANDLE hData,
|
|
_In_ ULONG_PTR dwData
|
|
)
|
|
{
|
|
INT lvItemIndex;
|
|
PWSTR propName;
|
|
WCHAR value[PH_PTR_STR_LEN_1];
|
|
|
|
propName = lpszString;
|
|
|
|
if ((ULONG_PTR)lpszString < USHRT_MAX)
|
|
{
|
|
// This is an integer atom.
|
|
propName = PhaFormatString(L"#%lu", (ULONG_PTR)lpszString)->Buffer;
|
|
}
|
|
|
|
lvItemIndex = PhAddListViewItem((HWND)dwData, MAXINT, propName, NULL);
|
|
|
|
PhPrintPointer(value, (PVOID)hData);
|
|
PhSetListViewSubItem((HWND)dwData, lvItemIndex, 1, value);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID WepRefreshWindowProps(
|
|
_In_ HWND hwndDlg,
|
|
_In_ HWND ListViewHandle,
|
|
_In_ PWINDOW_PROPERTIES_CONTEXT Context
|
|
)
|
|
{
|
|
ExtendedListView_SetRedraw(ListViewHandle, FALSE);
|
|
ListView_DeleteAllItems(ListViewHandle);
|
|
EnumPropsEx(Context->WindowHandle, EnumPropsExCallback, (LPARAM)ListViewHandle);
|
|
ExtendedListView_SortItems(ListViewHandle);
|
|
ExtendedListView_SetRedraw(ListViewHandle, TRUE);
|
|
}
|
|
|
|
INT_PTR CALLBACK WepWindowPropertiesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
PWINDOW_PROPERTIES_CONTEXT context;
|
|
|
|
if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context))
|
|
return FALSE;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND lvHandle;
|
|
|
|
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
PhSetListViewStyle(lvHandle, FALSE, TRUE);
|
|
PhSetControlTheme(lvHandle, L"explorer");
|
|
|
|
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name");
|
|
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Value");
|
|
PhSetExtendedListView(lvHandle);
|
|
|
|
WepRefreshWindowProps(hwndDlg, lvHandle, context);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_REFRESH:
|
|
WepRefreshWindowProps(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), context);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|