diff --git a/2.x/trunk/plugins/NetworkTools/NetworkTools.rc b/2.x/trunk/plugins/NetworkTools/NetworkTools.rc index c870a4e24..f54c73dbb 100644 --- a/2.x/trunk/plugins/NetworkTools/NetworkTools.rc +++ b/2.x/trunk/plugins/NetworkTools/NetworkTools.rc @@ -111,6 +111,21 @@ BEGIN LTEXT "Timeout:",IDC_STATIC,67,22,29,8 END +IDD_PINGDIALOG DIALOGEX 0, 0, 351, 187 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,295,166,50,14 + CONTROL "Custom1",IDC_CUSTOM1,"PhGraph",WS_BORDER,7,27,337,90 + LTEXT "Pinging X with 32 bytes of data:",IDC_MAINTEXT,7,7,337,16 + GROUPBOX "Ping statistics",IDC_STATIC3,7,119,109,60 + LTEXT "Lost: 0",IDC_STATIC5,13,166,73,8 + LTEXT "Minimum: 0ms",IDC_STATIC6,13,142,73,8 + LTEXT "Maximum: 0ms",IDC_STATIC7,13,154,73,8 + LTEXT "Average: 0ms",IDC_STATIC8,13,130,73,8 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -135,6 +150,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 69 END + + IDD_PINGDIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 344 + TOPMARGIN, 7 + BOTTOMMARGIN, 180 + END END #endif // APSTUDIO_INVOKED diff --git a/2.x/trunk/plugins/NetworkTools/main.c b/2.x/trunk/plugins/NetworkTools/main.c index 022aa9991..d771906d2 100644 --- a/2.x/trunk/plugins/NetworkTools/main.c +++ b/2.x/trunk/plugins/NetworkTools/main.c @@ -115,7 +115,9 @@ LOGICAL DllMain( PH_SETTING_CREATE settings[] = { { IntegerPairSettingType, L"ProcessHacker.NetTools.NetToolsWindowPosition", L"0,0" }, - { IntegerPairSettingType, L"ProcessHacker.NetTools.NetToolsWindowSize", L"600,365" }, + { IntegerPairSettingType, L"ProcessHacker.NetTools.NetToolsWindowSize", L"600,365" }, + { IntegerPairSettingType, L"ProcessHacker.NetTools.NetToolsPingWindowPosition", L"0,0" }, + { IntegerPairSettingType, L"ProcessHacker.NetTools.NetToolsPingWindowSize", L"600,365" }, { IntegerSettingType, L"ProcessHacker.NetTools.MaxPingCount", L"4" }, { IntegerSettingType, L"ProcessHacker.NetTools.MaxPingTimeout", L"5" }, { IntegerSettingType, L"ProcessHacker.NetTools.EnableHostnameLookup", L"1" }, diff --git a/2.x/trunk/plugins/NetworkTools/nettools.h b/2.x/trunk/plugins/NetworkTools/nettools.h index 5c6a53262..dd0d09509 100644 --- a/2.x/trunk/plugins/NetworkTools/nettools.h +++ b/2.x/trunk/plugins/NetworkTools/nettools.h @@ -52,15 +52,29 @@ typedef struct _NETWORK_OUTPUT_CONTEXT PH_LAYOUT_MANAGER LayoutManager; HWND WindowHandle; BOOLEAN UseOldColors; - PH_QUEUED_LOCK TextBufferLock; HANDLE ThreadHandle; HANDLE PipeReadHandle; HANDLE ProcessHandle; WCHAR addressString[65]; PH_STRING_BUILDER ReceivedString; + + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + ULONG CurrentPingMs; + ULONG PingMinMs; + ULONG PingMaxMs; + ULONG PingAvgMs; + ULONG PingSentCount; + ULONG PingRecvCount; + ULONG PingLossCount; + PH_CIRCULAR_BUFFER_ULONG PingHistory; + PH_GRAPH_STATE PingGraphState; } NETWORK_OUTPUT_CONTEXT, *PNETWORK_OUTPUT_CONTEXT; +NTSTATUS PhNetworkPingDialogThreadStart( + __in PVOID Parameter + ); + VOID PerformNetworkAction( __in ULONG Action, __in PPH_NETWORK_ITEM NetworkItem diff --git a/2.x/trunk/plugins/NetworkTools/output.c b/2.x/trunk/plugins/NetworkTools/output.c index baa681b25..795ca90b0 100644 --- a/2.x/trunk/plugins/NetworkTools/output.c +++ b/2.x/trunk/plugins/NetworkTools/output.c @@ -25,90 +25,7 @@ static RECT MinimumSize = { -1, -1, -1, -1 }; -static NTSTATUS PhNetworkOutputDialogThreadStart( - __in PVOID Parameter - ) -{ - BOOL result; - MSG message; - PH_AUTO_POOL autoPool; - PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; - - PhInitializeAutoPool(&autoPool); - - context->WindowHandle = CreateDialogParam( - (HINSTANCE)PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OUTPUT), - PhMainWndHandle, - NetworkOutputDlgProc, - (LPARAM)Parameter - ); - - ShowWindow(context->WindowHandle, SW_SHOW); - SetForegroundWindow(context->WindowHandle); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!IsDialogMessage(context->WindowHandle, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - DestroyWindow(context->WindowHandle); - PhFree(context); - return STATUS_SUCCESS; -} - -static HFONT InitializeFont( - __in HWND hwndDlg - ) -{ - LOGFONT logFont = { 0 }; - HFONT fontHandle = NULL; - - logFont.lfHeight = 14; - logFont.lfWeight = FW_NORMAL;//FW_MEDIUM; - logFont.lfQuality = CLEARTYPE_QUALITY | ANTIALIASED_QUALITY; - - // GDI uses the first font that matches the above attributes. - fontHandle = CreateFontIndirect(&logFont); - - if (fontHandle) - { - SendMessage(hwndDlg, WM_SETFONT, (WPARAM)fontHandle, FALSE); - return fontHandle; - } - - return NULL; -} - -VOID PerformNetworkAction( - __in ULONG Action, - __in PPH_NETWORK_ITEM NetworkItem - ) -{ - HANDLE dialogThread = INVALID_HANDLE_VALUE; - PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)PhAllocate( - sizeof(NETWORK_OUTPUT_CONTEXT) - ); - memset(context, 0, sizeof(NETWORK_OUTPUT_CONTEXT)); - - context->Action = Action; - context->NetworkItem = NetworkItem; - - if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)PhNetworkOutputDialogThreadStart, (PVOID)context)) - NtClose(dialogThread); -} - -INT_PTR CALLBACK NetworkOutputDlgProc( +static INT_PTR CALLBACK NetworkOutputDlgProc( __in HWND hwndDlg, __in UINT uMsg, __in WPARAM wParam, @@ -129,19 +46,6 @@ INT_PTR CALLBACK NetworkOutputDlgProc( if (uMsg == WM_NCDESTROY) { PhSaveWindowPlacementToSetting(L"ProcessHacker.NetTools.NetToolsWindowPosition", L"ProcessHacker.NetTools.NetToolsWindowSize", hwndDlg); - - if (context->ProcessHandle) - { - NtClose(context->ProcessHandle); - context->ProcessHandle = NULL; - } - - if (context->ThreadHandle) - { - NtClose(context->ThreadHandle); - context->ThreadHandle = NULL; - } - PhDeleteStringBuilder(&context->ReceivedString); RemoveProp(hwndDlg, L"Context"); } @@ -157,9 +61,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( PH_RECTANGLE windowRectangle; HANDLE dialogThread = INVALID_HANDLE_VALUE; - PhInitializeQueuedLock(&context->TextBufferLock); PhInitializeStringBuilder(&context->ReceivedString, PAGE_SIZE); - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT), NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_NETRETRY), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); @@ -203,12 +105,6 @@ INT_PTR CALLBACK NetworkOutputDlgProc( switch (context->Action) { - case NETWORK_ACTION_PING: - { - if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)NetworkPingThreadStart, (PVOID)context)) - NtClose(dialogThread); - } - break; case NETWORK_ACTION_TRACEROUTE: { if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)NetworkTracertThreadStart, (PVOID)context)) @@ -229,17 +125,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( switch (LOWORD(wParam)) { case IDC_NETRETRY: - { - HANDLE dialogThread = NULL; - - Button_Enable(GetDlgItem(hwndDlg, IDC_NETRETRY), FALSE); - - if (context->Action == NETWORK_ACTION_PING) - { - if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)NetworkPingThreadStart, (PVOID)context)) - NtClose(dialogThread); - } - } + Button_Enable(GetDlgItem(hwndDlg, IDC_NETRETRY), FALSE); break; case IDCANCEL: case IDOK: @@ -409,4 +295,95 @@ INT_PTR CALLBACK NetworkOutputDlgProc( } return FALSE; +} + +static NTSTATUS PhNetworkOutputDialogThreadStart( + __in PVOID Parameter + ) +{ + BOOL result; + MSG message; + PH_AUTO_POOL autoPool; + PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; + + PhInitializeAutoPool(&autoPool); + + context->WindowHandle = CreateDialogParam( + (HINSTANCE)PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OUTPUT), + PhMainWndHandle, + NetworkOutputDlgProc, + (LPARAM)Parameter + ); + + ShowWindow(context->WindowHandle, SW_SHOW); + SetForegroundWindow(context->WindowHandle); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(context->WindowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + DestroyWindow(context->WindowHandle); + PhFree(context); + return STATUS_SUCCESS; +} + +static HFONT InitializeFont( + __in HWND hwndDlg + ) +{ + LOGFONT logFont = { 0 }; + HFONT fontHandle = NULL; + + logFont.lfHeight = 14; + logFont.lfWeight = FW_NORMAL;//FW_MEDIUM; + logFont.lfQuality = CLEARTYPE_QUALITY | ANTIALIASED_QUALITY; + + // GDI uses the first font that matches the above attributes. + fontHandle = CreateFontIndirect(&logFont); + + if (fontHandle) + { + SendMessage(hwndDlg, WM_SETFONT, (WPARAM)fontHandle, FALSE); + return fontHandle; + } + + return NULL; +} + +VOID PerformNetworkAction( + __in ULONG Action, + __in PPH_NETWORK_ITEM NetworkItem + ) +{ + HANDLE dialogThread = INVALID_HANDLE_VALUE; + PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)PhAllocate( + sizeof(NETWORK_OUTPUT_CONTEXT) + ); + memset(context, 0, sizeof(NETWORK_OUTPUT_CONTEXT)); + + context->Action = Action; + context->NetworkItem = NetworkItem; + + if (context->Action == NETWORK_ACTION_PING) + { + if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)PhNetworkPingDialogThreadStart, (PVOID)context)) + NtClose(dialogThread); + } + else + { + if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)PhNetworkOutputDialogThreadStart, (PVOID)context)) + NtClose(dialogThread); + } } \ No newline at end of file diff --git a/2.x/trunk/plugins/NetworkTools/ping.c b/2.x/trunk/plugins/NetworkTools/ping.c index ce1972e1c..cb9449ad3 100644 --- a/2.x/trunk/plugins/NetworkTools/ping.c +++ b/2.x/trunk/plugins/NetworkTools/ping.c @@ -20,9 +20,6 @@ * along with Process Hacker. If not, see . */ -#pragma comment(lib, "IPHLPAPI.lib") -#pragma comment(lib, "Ws2_32.lib") - #include "nettools.h" #include @@ -30,139 +27,69 @@ #include #include -ULONG64 PhGetAverage( - __in PULONG64 Buffer, - __in ULONG BufferSize, - __in ULONG BufferPosition, - __in ULONG BufferCount, - __in ULONG NumberToConsider +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "ws2_32.lib") + +#define WM_PING_UPDATE (WM_APP + 151) +static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; +static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; + +static HFONT InitializeFont( + __in HWND hwndDlg ) { - ULONG64 sum; - ULONG i; - ULONG count; + LOGFONT logFont = { 0 }; + HFONT fontHandle = NULL; - sum = 0; - i = BufferPosition; + logFont.lfHeight = 20; + logFont.lfWeight = FW_MEDIUM; + logFont.lfQuality = CLEARTYPE_QUALITY | ANTIALIASED_QUALITY; - if (NumberToConsider > BufferCount) - NumberToConsider = BufferCount; + wcscpy_s(logFont.lfFaceName, _countof(logFont.lfFaceName), + WindowsVersion > WINDOWS_XP ? L"Segoe UI" : L"MS Shell Dlg 2" + ); - if (NumberToConsider == 0) - return 0; + fontHandle = CreateFontIndirect(&logFont); - count = NumberToConsider; - - do + if (fontHandle) { - sum += Buffer[i]; - i++; + SendMessage(hwndDlg, WM_SETFONT, (WPARAM)fontHandle, FALSE); + return fontHandle; + } - if (i == BufferSize) - i = 0; - } while (--count != 0); - - return sum / NumberToConsider; + return NULL; } -NTSTATUS NetworkPingThreadStart( +static NTSTATUS PhPingNetworkPingThreadStart( __in PVOID Parameter ) -{ - PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; - - ULONG i = 0; - WSADATA wsaData = { 0 }; - PPH_ANSI_STRING addrString; - SOCKADDR_IN sock_in; - - HANDLE icmpHandle = INVALID_HANDLE_VALUE; - PVOID icmpReplyBuffer = NULL; +{ ULONG icmpReplyLength = 0; - ULONG icmpPingReplyCount = 0; - - ULONG pingFirstMs = 0; - ULONG pingSecondMs = 0; - ULONG pingTotalMs = 0; - ULONG pingReplyCount = 0; - ULONG pingLossCount = 0; - ULONG pingSpeed = 0; + ULONG icmpReplyCount = 0; + PVOID icmpReplyBuffer = NULL; PICMP_ECHO_REPLY icmpReplyStruct = NULL; + HANDLE icmpHandle = INVALID_HANDLE_VALUE; IP_OPTION_INFORMATION pingOptions = { 0 }; - WCHAR hostname[NI_MAXHOST]; - WCHAR servInfo[NI_MAXSERV]; + PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; BOOLEAN isLookupEnabled = !!PhGetIntegerSetting(L"ProcessHacker.NetTools.EnableHostnameLookup"); - ULONG maxPingCount = max(PhGetIntegerSetting(L"ProcessHacker.NetTools.MaxPingCount"), 1); - ULONG maxPingTimeout = max(PhGetIntegerSetting(L"ProcessHacker.NetTools.MaxPingTimeout"), 1); + ULONG maxPingCount = __max(PhGetIntegerSetting(L"ProcessHacker.NetTools.MaxPingCount"), 1); + ULONG maxPingTimeout = __max(PhGetIntegerSetting(L"ProcessHacker.NetTools.MaxPingTimeout"), 1); - Static_SetText(context->WindowHandle, - PhFormatString(L"Pinging %s...", context->addressString)->Buffer); - - addrString = PhCreateAnsiStringFromUnicode(context->addressString); - WSAStartup(WINSOCK_VERSION, &wsaData); - - // This value indicates that the packet should not be fragmented. - //pingOptions.Flags = IP_FLAG_DF; - // Set the TTL field if we are doing a traceroute step. - pingOptions.Ttl = 128; - - if (context->NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + __try { + pingOptions.Flags = IP_FLAG_DF; + pingOptions.Ttl = 128; + icmpHandle = IcmpCreateFile(); - - sock_in.sin_family = AF_INET; - sock_in.sin_addr.s_addr = inet_addr(addrString->Buffer); - sock_in.sin_port = (USHORT)context->NetworkItem->RemoteEndpoint.Port; - } - else - { - icmpHandle = Icmp6CreateFile(); - - sock_in.sin_family = AF_INET6; - } - - //Pinging 74.125.31.125 with 32 bytes of data: - //Reply from 74.125.31.125: bytes=32 time=207ms TTL=37 - //Reply from 74.125.31.125: bytes=32 time=202ms TTL=38 - //Reply from 74.125.31.125: bytes=32 time=206ms TTL=37 - //Reply from 74.125.31.125: bytes=32 time=204ms TTL=38 - - if (isLookupEnabled && GetNameInfo( - (const PSOCKADDR)&sock_in, sizeof(SOCKADDR_IN), - hostname, _countof(hostname), - servInfo, _countof(servInfo), - 0 - ) == 0) - { - PPH_STRING buffer = PhFormatString( - L"Pinging %s:%s [%s] with 32 bytes of data...\r\n\r\n", - context->addressString, - servInfo, - hostname - ); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer, 0); - } - else - { - PPH_STRING buffer = PhFormatString( - L"Pinging %s with 32 bytes of data...\r\n\r\n", - context->addressString - ); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer, 0); - } - - // Loop through the 3 sets of pings - for (i = 0; i < maxPingCount; i++) - { icmpReplyLength = sizeof(ICMP_ECHO_REPLY); icmpReplyBuffer = PhAllocate(icmpReplyLength); - memset(icmpReplyBuffer, 0, icmpReplyLength); - // First ping with no data - if ((icmpPingReplyCount = IcmpSendEcho( + context->PingSentCount++; + + icmpReplyCount = IcmpSendEcho( icmpHandle, context->NetworkItem->RemoteEndpoint.Address.InAddr.S_un.S_addr, NULL, 0, @@ -170,86 +97,400 @@ NTSTATUS NetworkPingThreadStart( icmpReplyBuffer, icmpReplyLength, maxPingTimeout * 1000 - )) == 0) - { - if (WSAGetLastError() != IP_REQ_TIMED_OUT) - { - PPH_STRING buffer = PhFormatString(L"IcmpSendEcho failed: %d\r\n", WSAGetLastError()); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer, 0); - continue; - } - } + ); icmpReplyStruct = (PICMP_ECHO_REPLY)icmpReplyBuffer; + if (icmpReplyCount > 0 && icmpReplyStruct) + { + //Ping statistics for %s: + // Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), + //Approximate round trip times in milli-seconds: + // Minimum = 202ms, Maximum = 207ms, Average = 204ms - if (icmpReplyStruct) - { - // Reply from different address?? - // if (icmpReplyStruct->Address == context->Address.InAddr.S_un.S_addr) - // if (icmpReplyStruct->DataSize < max_size - //if (!icmpReplyStruct->RoundTripTime) PPH_STRING buffer = PhFormatString(L"<1 ms "); - pingFirstMs = icmpReplyStruct->RoundTripTime; + //if (icmpReplyStruct->Address == context->Address.InAddr.S_un.S_addr) + //if (icmpReplyStruct->DataSize < max_size) + //if (icmpReplyStruct->RoundTripTime < 1) - switch (icmpReplyStruct->Status) + InterlockedIncrement(&context->PingRecvCount); + + if (icmpReplyStruct->Status != IP_SUCCESS) { - case IP_SUCCESS: + InterlockedIncrement(&context->PingLossCount); + } + + context->CurrentPingMs = icmpReplyStruct->RoundTripTime; + + if (context->CurrentPingMs < context->PingMinMs) + context->PingMinMs = context->CurrentPingMs; + if (context->CurrentPingMs > context->PingMaxMs) + context->PingMaxMs = context->CurrentPingMs; + + PhAddItemCircularBuffer_ULONG(&context->PingHistory, context->CurrentPingMs); + } + else + { + InterlockedIncrement(&context->PingLossCount); + + PhAddItemCircularBuffer_ULONG(&context->PingHistory, 0); + } + } + __finally + { + if (icmpReplyBuffer) + { + PhFree(icmpReplyBuffer); + } + + if (icmpHandle) + { + IcmpCloseHandle(icmpHandle); + } + } + + return STATUS_SUCCESS; +} + +static VOID NTAPI NetworkPingUpdateHandler( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Context; + HANDLE dialogThread = INVALID_HANDLE_VALUE; + + // Queue up the next ping... + // This needs to be done to prevent slow-links from blocking the interval update. + if (dialogThread = PhCreateThread(0, (PUSER_THREAD_START_ROUTINE)PhPingNetworkPingThreadStart, (PVOID)context)) + NtClose(dialogThread); + + PostMessage(context->WindowHandle, WM_PING_UPDATE, 0, 0); +} + +static INT_PTR CALLBACK NetworkPingWndProc( + __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_NCDESTROY) + { + PhSaveWindowPlacementToSetting( + L"ProcessHacker.NetTools.NetToolsPingWindowPosition", + L"ProcessHacker.NetTools.NetToolsPingWindowSize", + hwndDlg + ); + RemoveProp(hwndDlg, L"Context"); + } + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PH_RECTANGLE windowRectangle; + + // Convert IP Address to string format. + if (context->NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + RtlIpv4AddressToString( + &context->NetworkItem->RemoteEndpoint.Address.InAddr, + context->addressString + ); + } + else + { + RtlIpv6AddressToString( + &context->NetworkItem->RemoteEndpoint.Address.In6Addr, + context->addressString + ); + } + + SetWindowText(hwndDlg, PhaFormatString(L"Ping (%s)", context->addressString)->Buffer); + SetWindowText(GetDlgItem(hwndDlg, IDC_MAINTEXT), PhaFormatString(L"Pinging %s with 32 bytes of data:", context->addressString)->Buffer); + + InitializeFont(GetDlgItem(hwndDlg, IDC_MAINTEXT)); + PhInitializeGraphState(&context->PingGraphState); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhInitializeCircularBuffer_ULONG(&context->PingHistory, PhGetIntegerSetting(L"SampleCount")); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_CUSTOM1), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATIC3), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATIC5), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATIC6), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATIC7), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATIC8), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + Graph_SetTooltip(GetDlgItem(hwndDlg, IDC_CUSTOM1), TRUE); + + context->UseOldColors = !!PhGetIntegerSetting(L"GraphColorMode"); + windowRectangle.Position = PhGetIntegerPairSetting(L"ProcessHacker.NetTools.NetToolsPingWindowPosition"); + windowRectangle.Size = PhGetIntegerPairSetting(L"ProcessHacker.NetTools.NetToolsPingWindowSize"); + + // Load window settings. + if (windowRectangle.Position.X == 0 || windowRectangle.Position.Y == 0) + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + else + { + PhLoadWindowPlacementFromSetting( + L"ProcessHacker.NetTools.NetToolsPingWindowPosition", + L"ProcessHacker.NetTools.NetToolsPingWindowSize", + hwndDlg + ); + } + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + NetworkPingUpdateHandler, + context, + &context->ProcessesUpdatedRegistration + ); + } + return TRUE; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + PostQuitMessage(0); + break; + } + } + break; + case WM_DESTROY: + { + PhUnregisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + &context->ProcessesUpdatedRegistration + ); + + PhDeleteLayoutManager(&context->LayoutManager); + } + break; + case WM_SIZE: + PhLayoutManagerLayout(&context->LayoutManager); + break; + case WM_SIZING: + PhResizingMinimumSize((PRECT)lParam, wParam, 100, 100); + 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_MAINTEXT) + { + 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); + } + break; + case WM_PING_UPDATE: + { + context->PingGraphState.Valid = FALSE; + context->PingGraphState.TooltipIndex = -1; + Graph_MoveGrid(GetDlgItem(hwndDlg, IDC_CUSTOM1), 1); + Graph_Draw(GetDlgItem(hwndDlg, IDC_CUSTOM1)); + Graph_UpdateTooltip(GetDlgItem(hwndDlg, IDC_CUSTOM1)); + InvalidateRect(GetDlgItem(hwndDlg, IDC_CUSTOM1), NULL, FALSE); + + //SetDlgItemText(hwndDlg, IDC_STATIC2, PhaFormatString( + // L"Sent: %I64u", context->PingSentCount)->Buffer); + SetDlgItemText(hwndDlg, IDC_STATIC5, PhaFormatString( + L"Loss: %I64u (0%% loss)", context->PingLossCount)->Buffer); + SetDlgItemText(hwndDlg, IDC_STATIC6, PhaFormatString( + L"Minimum: %I64ums", context->PingMinMs)->Buffer); + SetDlgItemText(hwndDlg, IDC_STATIC7, PhaFormatString( + L"Maximum: %I64ums", context->PingMaxMs)->Buffer); + SetDlgItemText(hwndDlg, IDC_STATIC8, PhaFormatString( + L"Average: %I64ums", context->PingAvgMs)->Buffer); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case GCN_GETDRAWINFO: { - PPH_STRING buffer = PhFormatString( - L"Reply from %s: Time=%dms TTL=%u\r\n", - context->addressString, - icmpReplyStruct->RoundTripTime, - icmpReplyStruct->Options.Ttl - ); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer, 0); + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + //drawInfo->Flags = ~PH_GRAPH_USE_GRID; + + if (context->UseOldColors) + { + drawInfo->BackColor = RGB(0x00, 0x00, 0x00); + drawInfo->LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel"); + drawInfo->LineBackColor1 = PhHalveColorBrightness(drawInfo->LineColor1); + drawInfo->LineColor2 = PhGetIntegerSetting(L"ColorCpuUser"); + drawInfo->LineBackColor2 = PhHalveColorBrightness(drawInfo->LineColor2); + drawInfo->GridColor = RGB(0x00, 0x57, 0x00); + drawInfo->TextColor = RGB(0x00, 0xff, 0x00); + drawInfo->TextBoxColor = RGB(0x00, 0x22, 0x00); + } + else + { + drawInfo->BackColor = RGB(0xef, 0xef, 0xef); + drawInfo->LineColor1 = PhHalveColorBrightness(PhGetIntegerSetting(L"ColorCpuKernel")); + drawInfo->LineBackColor1 = PhMakeColorBrighter(drawInfo->LineColor1, 125); + drawInfo->LineColor2 = PhHalveColorBrightness(PhGetIntegerSetting(L"ColorCpuUser")); + drawInfo->LineBackColor2 = PhMakeColorBrighter(drawInfo->LineColor2, 125); + drawInfo->GridColor = RGB(0xc7, 0xc7, 0xc7); + drawInfo->TextColor = RGB(0x00, 0x00, 0x00); + drawInfo->TextBoxColor = RGB(0xe7, 0xe7, 0xe7); + } + + if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_CUSTOM1)) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc = Graph_GetBufferedContext(GetDlgItem(hwndDlg, IDC_CUSTOM1)); + + PhSwapReference2(&context->PingGraphState.TooltipText, + PhFormatString(L"Ping: %I64ums", context->CurrentPingMs) + ); + + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->PingGraphState.TooltipText->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + PhGraphStateGetDrawInfo( + &context->PingGraphState, + getDrawInfo, + context->PingHistory.Count + ); + + if (!context->PingGraphState.Valid) + { + ULONG i = 0; + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + context->PingGraphState.Data1[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG(&context->PingHistory, i); + } + + // Scale the data. + PhxfDivideSingle2U( + context->PingGraphState.Data1, + (FLOAT)context->PingMaxMs + 5, + drawInfo->LineDataCount + ); + + context->PingGraphState.Valid = TRUE; + } + } } break; - default: // case IP_REQ_TIMED_OUT: + case GCN_GETTOOLTIPTEXT: { - PPH_STRING buffer = PhFormatString(L"Reply from %s: Timed out...\r\n" , context->addressString); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer, 0); + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; - pingLossCount++; + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_CUSTOM1)) + { + if (context->PingGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG usage = PhGetItemCircularBuffer_ULONG( + &context->PingHistory, + getTooltipText->Index + ); + + PhSwapReference2(&context->PingGraphState.TooltipText, PhFormatString(L"Ping: %I64ums", usage)); + } + + getTooltipText->Text = context->PingGraphState.TooltipText->sr; + } + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)lParam; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK) + { + if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_CUSTOM1)) + { + PhShowInformation(hwndDlg, L"Double clicked!"); + } + } } break; } } - - pingTotalMs += (pingSecondMs - pingFirstMs); - pingSecondMs = pingFirstMs; - pingReplyCount++; + break; } + return FALSE; +} + +NTSTATUS PhNetworkPingDialogThreadStart( + __in PVOID Parameter + ) +{ + BOOL result; + MSG message; + PH_AUTO_POOL autoPool; + PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; + + PhInitializeAutoPool(&autoPool); + + context->WindowHandle = CreateDialogParam( + (HINSTANCE)PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_PINGDIALOG), + PhMainWndHandle, + NetworkPingWndProc, + (LPARAM)Parameter + ); + + ShowWindow(context->WindowHandle, SW_SHOW); + SetForegroundWindow(context->WindowHandle); + + while (result = GetMessage(&message, NULL, 0, 0)) { - //Ping statistics for %s: - // Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), - //Approximate round trip times in milli-seconds: - // Minimum = 202ms, Maximum = 207ms, Average = 204ms - PPH_STRING buffer = PhFormatString( - L"\r\nPing statistics for %s:\r\n" - L" Packets: Sent = %d, Received = %d, Lost = %d (%.0f%% loss)\r\n", - context->addressString, - maxPingCount, - pingReplyCount, - pingLossCount, - (FLOAT)(pingLossCount / maxPingCount) * 100.0f - ); - PPH_STRING buffer2 = PhFormatString( - L"Approximate round trip times in milliseconds:\r\n" - L" Minimum = 0ms, Maximum = 0ms, Average = 0ms\r\n\r\n" - ); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer, 0); - SendMessage(context->WindowHandle, NTM_RECEIVEDPING, (WPARAM)buffer2, 0); + if (result == -1) + break; + + if (!IsDialogMessage(context->WindowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); } - if (icmpReplyBuffer) - { - PhFree(icmpReplyBuffer); - icmpReplyBuffer = NULL; - } - - IcmpCloseHandle(icmpHandle); - WSACleanup(); - - Button_Enable(GetDlgItem(context->WindowHandle, IDC_NETRETRY), TRUE); + PhDeleteAutoPool(&autoPool); + DestroyWindow(context->WindowHandle); + PhFree(context); return STATUS_SUCCESS; } \ No newline at end of file diff --git a/2.x/trunk/plugins/NetworkTools/resource.h b/2.x/trunk/plugins/NetworkTools/resource.h index 0e4c7e06e..e43431dca 100644 --- a/2.x/trunk/plugins/NetworkTools/resource.h +++ b/2.x/trunk/plugins/NetworkTools/resource.h @@ -5,6 +5,7 @@ #define ID_TOOLS_PING 101 #define IDD_OUTPUT 101 #define ID_TOOLS_TRACEROUTE 102 +#define IDD_PINGDIALOG 102 #define ID_TOOLS_WHOIS 103 #define IDD_OPTIONS 109 #define IDC_NETRESOLVECHECK 1001 @@ -12,16 +13,21 @@ #define IDC_MAXPINGTEXT 1007 #define IDC_MAXTIMEOUTTEXT 1008 #define IDC_NETOUTPUTEDIT 1008 -#define IDC_COMBOBOXEX1 1009 -#define IDC_COMBOCMD 1009 +#define IDC_CUSTOM1 1010 +#define IDC_STATIC3 1012 +#define IDC_STATIC5 1014 +#define IDC_STATIC6 1015 +#define IDC_STATIC7 1016 +#define IDC_STATIC8 1017 +#define IDC_MAINTEXT 1018 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_CONTROL_VALUE 1019 #define _APS_NEXT_SYMED_VALUE 104 #endif #endif