Skip to content

Commit

Permalink
Add PH v1.x exit status to window title winsiderss#911
Browse files Browse the repository at this point in the history
  • Loading branch information
dmex committed Jun 26, 2021
1 parent ca6a3bc commit 01ba1d2
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 3 deletions.
11 changes: 11 additions & 0 deletions ProcessHacker/include/procprp.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
#ifndef PH_PROCPRP_H
#define PH_PROCPRP_H

typedef struct _PH_PROCESS_WAITPROPCONTEXT
{
SLIST_ENTRY ListEntry;
HANDLE PropSheetWindowHandle;
HANDLE ProcessWaitHandle;
PPH_PROCESS_ITEM ProcessItem;
} PH_PROCESS_WAITPROPCONTEXT, *PPH_PROCESS_WAITPROPCONTEXT;

#define PH_PROCESS_PROPCONTEXT_MAXPAGES 20

typedef struct _PH_PROCESS_PROPCONTEXT
Expand All @@ -11,6 +19,9 @@ typedef struct _PH_PROCESS_PROPCONTEXT
HPROPSHEETPAGE *PropSheetPages;

HANDLE SelectThreadId;

PPH_PROCESS_WAITPROPCONTEXT ProcessWaitContext;
BOOLEAN WaitInitialized;
} PH_PROCESS_PROPCONTEXT, *PPH_PROCESS_PROPCONTEXT;

// begin_phapppub
Expand Down
19 changes: 19 additions & 0 deletions ProcessHacker/include/procprpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ INT CALLBACK PhpStandardPropPageProc(
_In_ LPPROPSHEETPAGE ppsp
);

VOID NTAPI PhpProcessPropPageWaitContextDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
);

VOID PhpCreateProcessPropSheetWaitContext(
_In_ PPH_PROCESS_PROPCONTEXT PropContext,
_In_ HWND WindowHandle
);

VOID PhpFlushProcessPropSheetWaitContextData(
VOID
);

VOID CALLBACK PhpProcessPropertiesWaitCallback(
_In_ PVOID Context,
_In_ BOOLEAN TimerOrWaitFired
);

#define SET_BUTTON_ICON(Id, Icon) \
SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon))

Expand Down
161 changes: 158 additions & 3 deletions ProcessHacker/procprp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@

PPH_OBJECT_TYPE PhpProcessPropContextType = NULL;
PPH_OBJECT_TYPE PhpProcessPropPageContextType = NULL;
PPH_OBJECT_TYPE PhpProcessPropPageWaitContextType = NULL;
PH_STRINGREF PhpLoadingText = PH_STRINGREF_INIT(L"Loading...");
static RECT MinimumSize = { -1, -1, -1, -1 };
SLIST_HEADER WaitContextQueryListHead;

PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext(
_In_opt_ HWND ParentWindowHandle,
Expand All @@ -50,6 +52,8 @@ PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext(
{
PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure);
PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure);
PhpProcessPropPageWaitContextType = PhCreateObjectType(L"ProcessPropPageWaitContext", 0, PhpProcessPropPageWaitContextDeleteProcedure);
RtlInitializeSListHead(&WaitContextQueryListHead);
PhEndInitOnce(&initOnce);
}

Expand Down Expand Up @@ -215,6 +219,11 @@ LRESULT CALLBACK PhpPropSheetWndProc(

oldWndProc = propSheetContext->PropSheetWindowHookProc;

if (RtlQueryDepthSList(&WaitContextQueryListHead))
{
PhpFlushProcessPropSheetWaitContextData();
}

switch (uMsg)
{
case WM_DESTROY:
Expand Down Expand Up @@ -475,6 +484,132 @@ INT CALLBACK PhpStandardPropPageProc(
return 1;
}

VOID NTAPI PhpProcessPropPageWaitContextDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
)
{
PPH_PROCESS_WAITPROPCONTEXT context = (PPH_PROCESS_WAITPROPCONTEXT)Object;

if (context->ProcessWaitHandle)
RtlDeregisterWait(context->ProcessWaitHandle);
if (context->ProcessItem)
PhDereferenceObject(context->ProcessItem);
}

VOID PhpCreateProcessPropSheetWaitContext(
_In_ PPH_PROCESS_PROPCONTEXT PropContext,
_In_ HWND WindowHandle
)
{
PPH_PROCESS_ITEM processItem = PropContext->ProcessItem;
PPH_PROCESS_WAITPROPCONTEXT waitContext;
HANDLE processHandle;

if (!processItem->QueryHandle)
return;
if (processItem->ProcessId == NtCurrentProcessId())
return;

if (!NT_SUCCESS(PhOpenProcess(
&processHandle,
SYNCHRONIZE,
processItem->ProcessId
)))
{
return;
}

waitContext = PhCreateObjectZero(sizeof(PH_PROCESS_WAITPROPCONTEXT), PhpProcessPropPageWaitContextType);
waitContext->ProcessItem = PhReferenceObject(processItem);
waitContext->PropSheetWindowHandle = GetParent(WindowHandle);

if (NT_SUCCESS(RtlRegisterWait(
&waitContext->ProcessWaitHandle,
processHandle,
PhpProcessPropertiesWaitCallback,
waitContext,
INFINITE,
WT_EXECUTEONLYONCE | WT_EXECUTEINIOTHREAD
)))
{
PropContext->ProcessWaitContext = waitContext;
}
else
{
PhDereferenceObject(waitContext->ProcessItem);
PhDereferenceObject(waitContext);
}

NtClose(processHandle);
}

VOID PhpFlushProcessPropSheetWaitContextData(
VOID
)
{
PSLIST_ENTRY entry;
PPH_PROCESS_WAITPROPCONTEXT data;
PROCESS_BASIC_INFORMATION basicInfo;

//if (!RtlFirstEntrySList(&QueryListHead))
// return;

entry = RtlInterlockedFlushSList(&WaitContextQueryListHead);

while (entry)
{
data = CONTAINING_RECORD(entry, PH_PROCESS_WAITPROPCONTEXT, ListEntry);
entry = entry->Next;

if (NT_SUCCESS(PhGetProcessBasicInformation(data->ProcessItem->QueryHandle, &basicInfo)))
{
PPH_STRING statusMessage;
PPH_STRING errorMessage;
PH_FORMAT format[5];

PhInitFormatSR(&format[0], data->ProcessItem->ProcessName->sr);
PhInitFormatS(&format[1], L" (");
PhInitFormatU(&format[2], HandleToUlong(data->ProcessItem->ProcessId));

if (errorMessage = PhGetStatusMessage(basicInfo.ExitStatus, 0))
{
PhInitFormatS(&format[3], L") exited with ");
PhInitFormatSR(&format[4], errorMessage->sr);

statusMessage = PhFormat(format, RTL_NUMBER_OF(format), 0);
PhDereferenceObject(errorMessage);
}
else
{
PhInitFormatS(&format[3], L") exited with 0x");
PhInitFormatX(&format[4], basicInfo.ExitStatus);

statusMessage = PhFormat(format, RTL_NUMBER_OF(format), 0);
}

if (statusMessage)
{
PhSetWindowText(data->PropSheetWindowHandle, PhGetString(statusMessage));
PhDereferenceObject(statusMessage);
}
}

//PostMessage(data->PropSheetWindowHandle, WM_PH_PROPPAGE_EXITSTATUS, 0, (LPARAM)data);
}
}

VOID CALLBACK PhpProcessPropertiesWaitCallback(
_In_ PVOID Context,
_In_ BOOLEAN TimerOrWaitFired
)
{
PPH_PROCESS_WAITPROPCONTEXT waitContext = Context;

// This avoids blocking the workqueue and avoids converting the workqueue to GUI threads. (dmex)
RtlInterlockedPushEntrySList(&WaitContextQueryListHead, &waitContext->ListEntry);
}

_Success_(return)
BOOLEAN PhPropPageDlgProcHeader(
_In_ HWND hwndDlg,
Expand All @@ -490,10 +625,24 @@ BOOLEAN PhPropPageDlgProcHeader(

if (uMsg == WM_INITDIALOG)
{
PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, (PVOID)lParam);
}
PPH_PROCESS_PROPCONTEXT propContext;

propSheetPage = (LPPROPSHEETPAGE)lParam;
propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;
propContext = propPageContext->PropContext;

if (!propContext->WaitInitialized)
{
PhpCreateProcessPropSheetWaitContext(propContext, hwndDlg);
propContext->WaitInitialized = TRUE;
}

propSheetPage = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, propSheetPage);
}
else
{
propSheetPage = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
}

if (!propSheetPage)
return FALSE;
Expand All @@ -510,6 +659,12 @@ BOOLEAN PhPropPageDlgProcHeader(
if (uMsg == WM_DESTROY)
{
PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);

if (propPageContext->PropContext->ProcessWaitContext)
{
PhDereferenceObject(propPageContext->PropContext->ProcessWaitContext);
propPageContext->PropContext->ProcessWaitContext = NULL;
}
}

return TRUE;
Expand Down

0 comments on commit 01ba1d2

Please sign in to comment.