HRESULT CALLBACK TaskDialogResultFoundProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ LONG_PTR dwRefData ) { PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; switch (uMsg) { case TDN_NAVIGATED: { if (context->TaskbarListClass) { ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); } } break; case TDN_BUTTON_CLICKED: { INT buttonID = (INT)wParam; if (buttonID == IDOK) { ShowVirusTotalProgressDialog(context); return S_FALSE; } else if (buttonID == IDRETRY) { if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) PhShellExecute(hwndDlg, PhGetString(context->ReAnalyseUrl), NULL); } else if (buttonID == IDYES) { if (!PhIsNullOrEmptyString(context->LaunchCommand)) { PhShellExecute(hwndDlg, PhGetString(context->LaunchCommand), NULL); } } } break; case TDN_VERIFICATION_CLICKED: { BOOL verification = (BOOL)wParam; } break; } return S_OK; }
VOID NTAPI MenuItemCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ) { PPH_PLUGIN_MENU_ITEM menuItem = Parameter; PPH_NETWORK_ITEM networkItem; switch (menuItem->Id) { case ID_TOOLS_PING: networkItem = menuItem->Context; PerformNetworkAction(PhMainWndHandle, NETWORK_ACTION_PING, &networkItem->RemoteEndpoint.Address); break; case ID_TOOLS_TRACEROUTE: networkItem = menuItem->Context; PerformNetworkAction(PhMainWndHandle, NETWORK_ACTION_TRACEROUTE, &networkItem->RemoteEndpoint.Address); break; case ID_TOOLS_WHOIS: networkItem = menuItem->Context; // TODO: Integrate WHOIS with the GUI. PhShellExecute( PhMainWndHandle, PhaConcatStrings2(L"http://wq.apnic.net/apnic-bin/whois.pl?searchtext=", networkItem->RemoteAddressString)->Buffer, NULL ); break; } }
INT_PTR CALLBACK UpdaterWndProc( __in HWND hwndDlg, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { LOGFONT lHeaderFont = { 0 }; // load the PH main icon using the 'magic' resource id. HANDLE hPhIcon = LoadImage( GetModuleHandle(NULL), MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_SHARED ); // Set our initial state as download PhUpdaterState = Download; // Set the window icon. SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hPhIcon); lHeaderFont.lfHeight = -15; lHeaderFont.lfWeight = FW_MEDIUM; lHeaderFont.lfQuality = CLEARTYPE_QUALITY | ANTIALIASED_QUALITY; // We don't check if Segoe exists, CreateFontIndirect does this for us. wcscpy_s( lHeaderFont.lfFaceName, _countof(lHeaderFont.lfFaceName), L"Segoe UI" ); // Create the font handle. FontHandle = CreateFontIndirectW(&lHeaderFont); // Set the header font. SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), WM_SETFONT, (WPARAM)FontHandle, FALSE); // Center the update window on PH if visible and not mimimized else center on desktop. PhCenterWindow(hwndDlg, (IsWindowVisible(GetParent(hwndDlg)) && !IsIconic(GetParent(hwndDlg))) ? GetParent(hwndDlg) : NULL); // Create our update check thread. UpdateCheckThreadHandle = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)CheckUpdateThreadStart, hwndDlg); } break; case WM_SHOWDIALOG: { if (IsIconic(hwndDlg)) ShowWindow(hwndDlg, SW_RESTORE); else ShowWindow(hwndDlg, SW_SHOW); SetForegroundWindow(hwndDlg); } break; case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: { HDC hDC = (HDC)wParam; HWND hwndChild = (HWND)lParam; // Check for our static label and change the color. if (GetDlgCtrlID(hwndChild) == IDC_MESSAGE) { SetTextColor(hDC, RGB(19, 112, 171)); } // Set a transparent background for the control backcolor. SetBkMode(hDC, TRANSPARENT); // set window background color. return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: { PostQuitMessage(0); } break; case IDC_DOWNLOAD: { switch (PhUpdaterState) { case Download: { if (PhInstalledUsingSetup()) { // Start our Downloader thread DownloadThreadHandle = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)DownloadUpdateThreadStart, hwndDlg); } else { // Let the user handle non-setup installation, show the homepage and close this dialog. PhShellExecute(hwndDlg, L"http://processhacker.sourceforge.net/downloads.php", NULL); PostQuitMessage(0); } } break; case Install: { SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; info.lpFile = SetupFilePath->Buffer; info.lpVerb = L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); if (!ShellExecuteEx(&info)) { // Install failed, cancel the shutdown. ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); // Set button text for next action Button_SetText(GetDlgItem(hwndDlg, IDC_DOWNLOAD), L"Retry"); } else { ProcessHacker_Destroy(PhMainWndHandle); } } break; } } break; } break; } break; case WM_UPDATE: { if (IsUpdating) { DWORD time_taken; DWORD download_speed; //DWORD time_remain = (MulDiv(time_taken, contentLength, bytesDownloaded) - time_taken); int percent; PPH_STRING dlRemaningBytes; PPH_STRING dlLength; PPH_STRING dlSpeed; PPH_STRING statusText; PhAcquireQueuedLockExclusive(&Lock); time_taken = (GetTickCount() - timeTransferred); download_speed = (bytesDownloaded / max(time_taken, 1)); percent = MulDiv(100, bytesDownloaded, contentLength); dlRemaningBytes = PhFormatSize(bytesDownloaded, -1); dlLength = PhFormatSize(contentLength, -1); dlSpeed = PhFormatSize(download_speed * 1024, -1); LastUpdateTime = GetTickCount(); PhReleaseQueuedLockExclusive(&Lock); statusText = PhFormatString( L"%s (%d%%) of %s @ %s/s", dlRemaningBytes->Buffer, percent, dlLength->Buffer, dlSpeed->Buffer ); SetDlgItemText(hwndDlg, IDC_STATUS, statusText->Buffer); SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, percent, 0); PhDereferenceObject(statusText); PhDereferenceObject(dlSpeed); PhDereferenceObject(dlLength); PhDereferenceObject(dlRemaningBytes); IsUpdating = FALSE; } } break; } return FALSE; }
static INT_PTR CALLBACK NetworkOutputDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { PNETWORK_OUTPUT_CONTEXT context; if (uMsg == WM_INITDIALOG) { context = (PNETWORK_OUTPUT_CONTEXT)lParam; SetProp(hwndDlg, L"Context", (HANDLE)context); } else { context = (PNETWORK_OUTPUT_CONTEXT)GetProp(hwndDlg, L"Context"); if (uMsg == WM_DESTROY) { PhSaveWindowPlacementToSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); PhDeleteLayoutManager(&context->LayoutManager); if (context->ProcessHandle) { // Terminate the child process. PhTerminateProcess(context->ProcessHandle, STATUS_SUCCESS); // Close the child process handle. NtClose(context->ProcessHandle); } // Close the pipe handle. if (context->PipeReadHandle) NtClose(context->PipeReadHandle); RemoveProp(hwndDlg, L"Context"); PhFree(context); } } if (!context) return FALSE; switch (uMsg) { case WM_INITDIALOG: { PH_RECTANGLE windowRectangle; context->WindowHandle = hwndDlg; context->OutputHandle = GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->OutputHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MORE_INFO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); windowRectangle.Position = PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION); windowRectangle.Size = PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_SIZE); if (MinimumSize.left == -1) { RECT rect; rect.left = 0; rect.top = 0; rect.right = 190; rect.bottom = 120; MapDialogRect(hwndDlg, &rect); MinimumSize = rect; MinimumSize.left = 0; } // Check for first-run default position. if (windowRectangle.Position.X == 0 || windowRectangle.Position.Y == 0) { PhCenterWindow(hwndDlg, GetParent(hwndDlg)); } else { PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); } if (context->IpAddress.Type == PH_IPV4_NETWORK_TYPE) { RtlIpv4AddressToString(&context->IpAddress.InAddr, context->IpAddressString); } else { RtlIpv6AddressToString(&context->IpAddress.In6Addr, context->IpAddressString); } switch (context->Action) { case NETWORK_ACTION_TRACEROUTE: { HANDLE dialogThread = INVALID_HANDLE_VALUE; Static_SetText(context->WindowHandle, PhaFormatString(L"Tracing route to %s...", context->IpAddressString)->Buffer ); if (dialogThread = PhCreateThread(0, NetworkTracertThreadStart, (PVOID)context)) NtClose(dialogThread); } break; case NETWORK_ACTION_WHOIS: { HANDLE dialogThread = INVALID_HANDLE_VALUE; Static_SetText(context->WindowHandle, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer ); ShowWindow(GetDlgItem(hwndDlg, IDC_MORE_INFO), SW_SHOW); if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) NtClose(dialogThread); } break; } } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: PostQuitMessage(0); break; } } break; case WM_SIZE: PhLayoutManagerLayout(&context->LayoutManager); break; case WM_SIZING: PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); break; case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: { HDC hDC = (HDC)wParam; HWND hwndChild = (HWND)lParam; // Check if old graph colors are enabled. if (!PhGetIntegerSetting(L"GraphColorMode")) break; // Set a transparent background for the control backcolor. SetBkMode(hDC, TRANSPARENT); // Check for our edit control and change the color. if (hwndChild == context->OutputHandle) { // Set text color as the Green PH graph text color. SetTextColor(hDC, RGB(124, 252, 0)); // Set a black control backcolor. return (INT_PTR)GetStockBrush(BLACK_BRUSH); } } break; case WM_NOTIFY: { switch (((LPNMHDR)lParam)->code) { case NM_CLICK: case NM_RETURN: { PNMLINK syslink = (PNMLINK)lParam; if (syslink->hdr.idFrom == IDC_MORE_INFO) { PhShellExecute( PhMainWndHandle, PhaConcatStrings2(L"http://wq.apnic.net/apnic-bin/whois.pl?searchtext=", context->IpAddressString)->Buffer, NULL ); } } break; } } break; case NTM_RECEIVEDTRACE: { OEM_STRING inputString; UNICODE_STRING convertedString; PH_STRING_BUILDER receivedString; if (wParam != 0) { inputString.Buffer = (PCHAR)lParam; inputString.Length = (USHORT)wParam; if (NT_SUCCESS(RtlOemStringToUnicodeString(&convertedString, &inputString, TRUE))) { PPH_STRING windowText = NULL; PhInitializeStringBuilder(&receivedString, PAGE_SIZE); // Get the current output text. windowText = PhGetWindowText(context->OutputHandle); // Append the current output text to the New string. if (!PhIsNullOrEmptyString(windowText)) PhAppendStringBuilder(&receivedString, &windowText->sr); PhAppendFormatStringBuilder(&receivedString, L"%s", convertedString.Buffer); // Remove leading newlines. if (receivedString.String->Length >= 2 * 2 && receivedString.String->Buffer[0] == '\r' && receivedString.String->Buffer[1] == '\n') { PhRemoveStringBuilder(&receivedString, 0, 2); } SetWindowText(context->OutputHandle, receivedString.String->Buffer); SendMessage( context->OutputHandle, EM_SETSEL, receivedString.String->Length / 2 - 1, receivedString.String->Length / 2 - 1 ); SendMessage(context->OutputHandle, WM_VSCROLL, SB_BOTTOM, 0); PhDereferenceObject(windowText); PhDeleteStringBuilder(&receivedString); RtlFreeUnicodeString(&convertedString); } } } break; case NTM_RECEIVEDWHOIS: { OEM_STRING inputString; UNICODE_STRING convertedString; PH_STRING_BUILDER receivedString; if (lParam != 0) { inputString.Buffer = (PCHAR)lParam; inputString.Length = (USHORT)wParam; if (NT_SUCCESS(RtlOemStringToUnicodeString(&convertedString, &inputString, TRUE))) { USHORT i; PhInitializeStringBuilder(&receivedString, PAGE_SIZE); // Convert carriage returns. for (i = 0; i < convertedString.Length; i++) { if (convertedString.Buffer[i] == '\n') { PhAppendStringBuilder2(&receivedString, L"\r\n"); } else { PhAppendCharStringBuilder(&receivedString, convertedString.Buffer[i]); } } // Remove leading newlines. if (receivedString.String->Length >= 2 * 2 && receivedString.String->Buffer[0] == '\r' && receivedString.String->Buffer[1] == '\n') { PhRemoveStringBuilder(&receivedString, 0, 2); } SetWindowText(context->OutputHandle, receivedString.String->Buffer); SendMessage( context->OutputHandle, EM_SETSEL, receivedString.String->Length / 2 - 1, receivedString.String->Length / 2 - 1 ); SendMessage(context->OutputHandle, WM_VSCROLL, SB_TOP, 0); PhDeleteStringBuilder(&receivedString); RtlFreeUnicodeString(&convertedString); } PhFree((PVOID)lParam); } } break; case NTM_RECEIVEDFINISH: { PPH_STRING windowText = PhGetWindowText(context->WindowHandle); if (windowText) { Static_SetText( context->WindowHandle, PhaFormatString(L"%s Finished.", windowText->Buffer)->Buffer ); PhDereferenceObject(windowText); } } break; } return FALSE; }
VOID PhShellExecuteUserString( __in HWND hWnd, __in PWSTR Setting, __in PWSTR String, __in BOOLEAN UseShellExecute, __in_opt PWSTR ErrorMessage ) { static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L"%s"); PPH_STRING executeString; PH_STRINGREF stringBefore; PH_STRINGREF stringMiddle; PH_STRINGREF stringAfter; PPH_STRING newString; PPH_STRING ntMessage; executeString = PhGetStringSetting(Setting); // Make sure the user executable string is absolute. // We can't use RtlDetermineDosPathNameType_U here because the string // may be a URL. if (PhFindCharInString(executeString, 0, ':') == -1) { newString = PhConcatStringRef2(&PhApplicationDirectory->sr, &executeString->sr); PhDereferenceObject(executeString); executeString = newString; } // Replace "%s" with the string, or use the original string if "%s" is not present. if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter)) { PhInitializeStringRef(&stringMiddle, String); newString = PhConcatStringRef3(&stringBefore, &stringMiddle, &stringAfter); } else { newString = executeString; PhReferenceObject(newString); } PhDereferenceObject(executeString); if (UseShellExecute) { PhShellExecute(hWnd, newString->Buffer, NULL); } else { NTSTATUS status; status = PhCreateProcessWin32(NULL, newString->Buffer, NULL, NULL, 0, NULL, NULL, NULL); if (!NT_SUCCESS(status)) { if (ErrorMessage) { ntMessage = PhGetNtMessage(status); PhShowError(hWnd, L"Unable to execute the command: %s\n%s", PhGetStringOrDefault(ntMessage, L"An unknown error occurred."), ErrorMessage); PhDereferenceObject(ntMessage); } else { PhShowStatus(hWnd, L"Unable to execute the command", status, 0); } } } PhDereferenceObject(newString); }
INT_PTR CALLBACK PhpPluginsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { PPH_AVL_LINKS links; PhCenterWindow(hwndDlg, PhMainWndHandle); PluginsLv = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(PluginsLv, FALSE, TRUE); PhSetControlTheme(PluginsLv, L"explorer"); PhAddListViewColumn(PluginsLv, 0, 0, 0, LVCFMT_LEFT, 280, L"Name"); PhAddListViewColumn(PluginsLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Author"); PhSetExtendedListView(PluginsLv); ExtendedListView_SetItemColorFunction(PluginsLv, PhpPluginColorFunction); DisabledPluginLookup = PhCreateSimpleHashtable(10); for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) { PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); INT lvItemIndex; PH_STRINGREF baseNameSr; lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, plugin->Information.DisplayName ? plugin->Information.DisplayName : plugin->Name.Buffer, plugin); if (plugin->Information.Author) PhSetListViewSubItem(PluginsLv, lvItemIndex, 1, plugin->Information.Author); PhInitializeStringRefLongHint(&baseNameSr, PhpGetPluginBaseName(plugin)); if (PhIsPluginDisabled(&baseNameSr)) PhAddItemSimpleHashtable(DisabledPluginLookup, plugin, NULL); } DisabledPluginInstances = PhCreateList(10); PhpAddDisabledPlugins(); ExtendedListView_SortItems(PluginsLv); SelectedPlugin = NULL; PhpRefreshPluginDetails(hwndDlg); } break; case WM_DESTROY: { ULONG i; for (i = 0; i < DisabledPluginInstances->Count; i++) PhpFreeDisabledPlugin(DisabledPluginInstances->Items[i]); PhDereferenceObject(DisabledPluginInstances); PhDereferenceObject(DisabledPluginLookup); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hwndDlg, IDOK); break; case IDC_DISABLE: { if (SelectedPlugin) { PWSTR baseName; PH_STRINGREF baseNameRef; BOOLEAN newDisabledState; baseName = PhpGetPluginBaseName(SelectedPlugin); PhInitializeStringRef(&baseNameRef, baseName); newDisabledState = !PhIsPluginDisabled(&baseNameRef); PhSetPluginDisabled(&baseNameRef, newDisabledState); PhpUpdateDisabledPlugin(hwndDlg, PhFindListViewItemByFlags(PluginsLv, -1, LVNI_SELECTED), SelectedPlugin, newDisabledState); SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(baseName)); } } break; case IDC_OPTIONS: { if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) { PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); } } break; case IDC_CLEANUP: { if (PhShowMessage(hwndDlg, MB_ICONQUESTION | MB_YESNO, L"Do you want to clean up unused plugin settings?") == IDYES) { PhClearIgnoredSettings(); } } break; case IDC_OPENURL: { NOTHING; } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case LVN_ITEMCHANGED: { if (header->hwndFrom == PluginsLv) { if (ListView_GetSelectedCount(PluginsLv) == 1) SelectedPlugin = PhGetSelectedListViewItemParam(PluginsLv); else SelectedPlugin = NULL; PhpRefreshPluginDetails(hwndDlg); } } break; case NM_CLICK: { if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_OPENURL)) { if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) PhShellExecute(hwndDlg, SelectedPlugin->Information.Url, NULL); } } break; case NM_DBLCLK: { if (header->hwndFrom == PluginsLv) { if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) { PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); } } } break; } } break; } REFLECT_MESSAGE_DLG(hwndDlg, PluginsLv, uMsg, wParam, lParam); return FALSE; }
static INT_PTR CALLBACK PhpAboutDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { PPH_STRING appName; #if (PHAPP_VERSION_REVISION != 0) appName = PhFormatString( L"Process Hacker %u.%u.%u", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION ); #else appName = PhFormatString( L"Process Hacker %u.%u", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR ); #endif SetDlgItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer); PhDereferenceObject(appName); SetDlgItemText(hwndDlg, IDC_CREDITS, L" Installer by XhmikosR\n" L"Thanks to:\n" L" dmex\n" L" Donors - thank you for your support!\n" L" <a href=\"http://forum.sysinternals.com\">Sysinternals Forums</a>\n" L" <a href=\"http://www.reactos.org\">ReactOS</a>\n" L"Process Hacker uses the following components:\n" L" <a href=\"http://www.minixml.org\">Mini-XML</a> by Michael Sweet\n" L" <a href=\"http://www.pcre.org\">PCRE</a>\n" L" MD5 code by Jouni Malinen\n" L" SHA1 code by Filip Navara, based on code by Steve Reid\n" L" <a href=\"http://www.famfamfam.com/lab/icons/silk\">Silk icons</a>\n" ); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hwndDlg, IDOK); break; case IDC_DIAGNOSTICS: { PhShowInformationDialog(hwndDlg, PH_AUTO_T(PH_STRING, PhGetDiagnosticsString())->Buffer); } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case NM_CLICK: { switch (header->idFrom) { case IDC_CREDITS: case IDC_LINK_SF: PhShellExecute(hwndDlg, ((PNMLINK)header)->item.szUrl, NULL); break; } } break; } } break; } return FALSE; }