static VOID Test_ellipsis( VOID ) { PPH_STRING input; PPH_STRING output; // Normal input = PhCreateString(L"asdf 1234"); output = PhEllipsisString(input, 9); assert(wcscmp(output->Buffer, L"asdf 1234") == 0); output = PhEllipsisString(input, 999); assert(wcscmp(output->Buffer, L"asdf 1234") == 0); output = PhEllipsisString(input, 8); assert(wcscmp(output->Buffer, L"asdf ...") == 0); output = PhEllipsisString(input, 7); assert(wcscmp(output->Buffer, L"asdf...") == 0); output = PhEllipsisString(input, 5); assert(wcscmp(output->Buffer, L"as...") == 0); output = PhEllipsisString(input, 4); assert(wcscmp(output->Buffer, L"a...") == 0); output = PhEllipsisString(input, 3); assert(wcscmp(output->Buffer, L"...") == 0); output = PhEllipsisString(input, 2); assert(wcscmp(output->Buffer, L"asdf 1234") == 0); output = PhEllipsisString(input, 1); assert(wcscmp(output->Buffer, L"asdf 1234") == 0); output = PhEllipsisString(input, 0); assert(wcscmp(output->Buffer, L"asdf 1234") == 0); // Path input = PhCreateString(L"C:\\abcdef\\1234.abc"); output = PhEllipsisStringPath(input, 18); assert(wcscmp(output->Buffer, L"C:\\abcdef\\1234.abc") == 0); output = PhEllipsisStringPath(input, 999); assert(wcscmp(output->Buffer, L"C:\\abcdef\\1234.abc") == 0); output = PhEllipsisStringPath(input, 17); assert(wcscmp(output->Buffer, L"C:\\ab...\\1234.abc") == 0); // last part is kept output = PhEllipsisStringPath(input, 16); assert(wcscmp(output->Buffer, L"C:\\a...\\1234.abc") == 0); output = PhEllipsisStringPath(input, 15); assert(wcscmp(output->Buffer, L"C:\\...\\1234.abc") == 0); output = PhEllipsisStringPath(input, 14); assert(wcscmp(output->Buffer, L"C:...\\1234.abc") == 0); output = PhEllipsisStringPath(input, 13); assert(wcscmp(output->Buffer, L"C...\\1234.abc") == 0); output = PhEllipsisStringPath(input, 12); assert(wcscmp(output->Buffer, L"...\\1234.abc") == 0); output = PhEllipsisStringPath(input, 11); assert(wcscmp(output->Buffer, L"C:\\a....abc") == 0); // the two sides are split as evenly as possible output = PhEllipsisStringPath(input, 10); assert(wcscmp(output->Buffer, L"C:\\....abc") == 0); output = PhEllipsisStringPath(input, 9); assert(wcscmp(output->Buffer, L"C:\\...abc") == 0); output = PhEllipsisStringPath(input, 8); assert(wcscmp(output->Buffer, L"C:...abc") == 0); output = PhEllipsisStringPath(input, 7); assert(wcscmp(output->Buffer, L"C:...bc") == 0); output = PhEllipsisStringPath(input, 6); assert(wcscmp(output->Buffer, L"C...bc") == 0); output = PhEllipsisStringPath(input, 5); assert(wcscmp(output->Buffer, L"C...c") == 0); output = PhEllipsisStringPath(input, 4); assert(wcscmp(output->Buffer, L"...c") == 0); output = PhEllipsisStringPath(input, 3); assert(wcscmp(output->Buffer, L"...") == 0); output = PhEllipsisStringPath(input, 2); assert(wcscmp(output->Buffer, L"C:\\abcdef\\1234.abc") == 0); output = PhEllipsisStringPath(input, 1); assert(wcscmp(output->Buffer, L"C:\\abcdef\\1234.abc") == 0); output = PhEllipsisStringPath(input, 0); assert(wcscmp(output->Buffer, L"C:\\abcdef\\1234.abc") == 0); }
PPH_STRING PhGetProcessTooltipText( _In_ PPH_PROCESS_ITEM Process, _Out_opt_ PULONG ValidToTickCount ) { PH_STRING_BUILDER stringBuilder; ULONG validForMs = 60 * 60 * 1000; // 1 hour PPH_STRING tempString; PH_KNOWN_PROCESS_TYPE knownProcessType = UnknownProcessType; PhInitializeStringBuilder(&stringBuilder, 200); // Command line if (Process->CommandLine) { tempString = PhEllipsisString(Process->CommandLine, 100 * 10); // This is necessary because the tooltip control seems to use some kind of O(n^9999) word-wrapping // algorithm. PhpAppendStringWithLineBreaks(&stringBuilder, &tempString->sr, 100, NULL); PhAppendCharStringBuilder(&stringBuilder, '\n'); PhDereferenceObject(tempString); } // File information tempString = PhFormatImageVersionInfo( Process->FileName, &Process->VersionInfo, &StandardIndent, 0 ); if (!PhIsNullOrEmptyString(tempString)) { PhAppendStringBuilder2(&stringBuilder, L"File:\n"); PhAppendStringBuilder(&stringBuilder, &tempString->sr); PhAppendCharStringBuilder(&stringBuilder, '\n'); } if (tempString) PhDereferenceObject(tempString); // Known command line information if (Process->QueryHandle) PhGetProcessKnownType(Process->QueryHandle, &knownProcessType); if (Process->CommandLine && Process->QueryHandle) { PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine; if (knownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine( Process->CommandLine, knownProcessType, &knownCommandLine )) { switch (knownProcessType & KnownProcessTypeMask) { case ServiceHostProcessType: PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n "); PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ServiceHost.GroupName->sr); PhAppendCharStringBuilder(&stringBuilder, '\n'); break; case RunDllAsAppProcessType: { PH_IMAGE_VERSION_INFO versionInfo; if (PhInitializeImageVersionInfo( &versionInfo, knownCommandLine.RunDllAsApp.FileName->Buffer )) { tempString = PhFormatImageVersionInfo( knownCommandLine.RunDllAsApp.FileName, &versionInfo, &StandardIndent, 0 ); if (!PhIsNullOrEmptyString(tempString)) { PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n"); PhAppendStringBuilder(&stringBuilder, &tempString->sr); PhAppendCharStringBuilder(&stringBuilder, '\n'); } if (tempString) PhDereferenceObject(tempString); PhDeleteImageVersionInfo(&versionInfo); } } break; case ComSurrogateProcessType: { PH_IMAGE_VERSION_INFO versionInfo; PPH_STRING guidString; PhAppendStringBuilder2(&stringBuilder, L"COM target:\n"); if (knownCommandLine.ComSurrogate.Name) { PhAppendStringBuilder(&stringBuilder, &StandardIndent); PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ComSurrogate.Name->sr); PhAppendCharStringBuilder(&stringBuilder, '\n'); } if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid)) { PhAppendStringBuilder(&stringBuilder, &StandardIndent); PhAppendStringBuilder(&stringBuilder, &guidString->sr); PhDereferenceObject(guidString); PhAppendCharStringBuilder(&stringBuilder, '\n'); } if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo( &versionInfo, knownCommandLine.ComSurrogate.FileName->Buffer )) { tempString = PhFormatImageVersionInfo( knownCommandLine.ComSurrogate.FileName, &versionInfo, &StandardIndent, 0 ); if (!PhIsNullOrEmptyString(tempString)) { PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n"); PhAppendStringBuilder(&stringBuilder, &tempString->sr); PhAppendCharStringBuilder(&stringBuilder, '\n'); } if (tempString) PhDereferenceObject(tempString); PhDeleteImageVersionInfo(&versionInfo); } } break; } } } // Services if (Process->ServiceList && Process->ServiceList->Count != 0) { ULONG enumerationKey = 0; PPH_SERVICE_ITEM serviceItem; PPH_LIST serviceList; ULONG i; // Copy the service list into our own list so we can sort it. serviceList = PhCreateList(Process->ServiceList->Count); PhAcquireQueuedLockShared(&Process->ServiceListLock); while (PhEnumPointerList( Process->ServiceList, &enumerationKey, &serviceItem )) { PhReferenceObject(serviceItem); PhAddItemList(serviceList, serviceItem); } PhReleaseQueuedLockShared(&Process->ServiceListLock); qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare); PhAppendStringBuilder2(&stringBuilder, L"Services:\n"); // Add the services. for (i = 0; i < serviceList->Count; i++) { serviceItem = serviceList->Items[i]; PhAppendStringBuilder(&stringBuilder, &StandardIndent); PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr); PhAppendStringBuilder2(&stringBuilder, L" ("); PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr); PhAppendStringBuilder2(&stringBuilder, L")\n"); } PhDereferenceObjects(serviceList->Items, serviceList->Count); PhDereferenceObject(serviceList); } // Tasks, Drivers switch (knownProcessType & KnownProcessTypeMask) { case TaskHostProcessType: { PH_STRING_BUILDER tasks; PhInitializeStringBuilder(&tasks, 40); PhpFillRunningTasks(Process, &tasks); if (tasks.String->Length != 0) { PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n"); PhAppendStringBuilder(&stringBuilder, &tasks.String->sr); } PhDeleteStringBuilder(&tasks); } break; case UmdfHostProcessType: { PH_STRING_BUILDER drivers; PhInitializeStringBuilder(&drivers, 40); PhpFillUmdfDrivers(Process, &drivers); if (drivers.String->Length != 0) { PhAppendStringBuilder2(&stringBuilder, L"Drivers:\n"); PhAppendStringBuilder(&stringBuilder, &drivers.String->sr); } PhDeleteStringBuilder(&drivers); validForMs = 10 * 1000; // 10 seconds } break; } // Plugin if (PhPluginsEnabled) { PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText; getTooltipText.Parameter = Process; getTooltipText.StringBuilder = &stringBuilder; getTooltipText.ValidForMs = validForMs; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText); validForMs = getTooltipText.ValidForMs; } // Notes { PH_STRING_BUILDER notes; PhInitializeStringBuilder(¬es, 40); if (Process->FileName) { if (Process->VerifyResult == VrTrusted) { if (!PhIsNullOrEmptyString(Process->VerifySignerName)) PhAppendFormatStringBuilder(¬es, L" Signer: %s\n", Process->VerifySignerName->Buffer); else PhAppendStringBuilder2(¬es, L" Signed.\n"); } else if (Process->VerifyResult == VrUnknown) { // Nothing } else if (Process->VerifyResult != VrNoSignature) { PhAppendStringBuilder2(¬es, L" Signature invalid.\n"); } } if (Process->IsPacked) { PhAppendFormatStringBuilder( ¬es, L" Image is probably packed (%u imports over %u modules).\n", Process->ImportFunctions, Process->ImportModules ); } if ((ULONG_PTR)Process->ConsoleHostProcessId & ~3) { CLIENT_ID clientId; PWSTR description = L"Console host"; PPH_STRING clientIdString; clientId.UniqueProcess = (HANDLE)((ULONG_PTR)Process->ConsoleHostProcessId & ~3); clientId.UniqueThread = NULL; if ((ULONG_PTR)Process->ConsoleHostProcessId & 2) description = L"Console application"; clientIdString = PhGetClientIdName(&clientId); PhAppendFormatStringBuilder(¬es, L" %s: %s\n", description, clientIdString->Buffer); PhDereferenceObject(clientIdString); } if (Process->PackageFullName) { PhAppendFormatStringBuilder(¬es, L" Package name: %s\n", Process->PackageFullName->Buffer); } if (Process->IsDotNet) PhAppendStringBuilder2(¬es, L" Process is managed (.NET).\n"); if (Process->IsElevated) PhAppendStringBuilder2(¬es, L" Process is elevated.\n"); if (Process->IsImmersive) PhAppendStringBuilder2(¬es, L" Process is a Modern UI app.\n"); if (Process->IsInJob) PhAppendStringBuilder2(¬es, L" Process is in a job.\n"); if (Process->IsPosix) PhAppendStringBuilder2(¬es, L" Process is POSIX.\n"); if (Process->IsWow64) PhAppendStringBuilder2(¬es, L" Process is 32-bit (WOW64).\n"); if (notes.String->Length != 0) { PhAppendStringBuilder2(&stringBuilder, L"Notes:\n"); PhAppendStringBuilder(&stringBuilder, ¬es.String->sr); } PhDeleteStringBuilder(¬es); } if (ValidToTickCount) *ValidToTickCount = GetTickCount() + validForMs; // Remove the trailing newline. if (stringBuilder.String->Length != 0) PhRemoveEndStringBuilder(&stringBuilder, 1); return PhFinalStringBuilderString(&stringBuilder); }