static VOID NTAPI MenuItemCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_ITEM menuItem = (PPH_PLUGIN_MENU_ITEM)Parameter; switch (menuItem->Id) { case BOOT_ENTRIES_MENUITEM: { if (!PhElevated) { PhShowInformation(menuItem->OwnerWindow, L"This option requires elevation."); break; } DialogBox( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_BOOT), NULL, BootEntriesDlgProc ); } break; } }
VOID MenuItemCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ) { PPH_PLUGIN_MENU_ITEM menuItem = Parameter; switch (menuItem->Id) { case ID_SAMPLE_MENU_ITEM: { PhShowInformation(PhMainWndHandle, L"You clicked the sample menu item!"); } break; case ID_SHOW_ME_SOME_OBJECTS: { NTSTATUS status; HANDLE directoryHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING name; // Use the Native API seamlessly alongside Win32. RtlInitUnicodeString(&name, L"\\"); InitializeObjectAttributes(&oa, &name, 0, NULL, NULL); if (NT_SUCCESS(status = NtOpenDirectoryObject(&directoryHandle, DIRECTORY_QUERY, &oa))) { PhEnumDirectoryObjects(directoryHandle, EnumDirectoryObjectsCallback, NULL); NtClose(directoryHandle); } } break; } }
VOID PhShowPluginsDialog( _In_ HWND ParentWindowHandle ) { if (PhPluginsEnabled) { DialogBox( PhInstanceHandle, MAKEINTRESOURCE(IDD_PLUGINS), ParentWindowHandle, PhpPluginsDlgProc ); } else { PhShowInformation(ParentWindowHandle, L"Plugins are not enabled. To use plugins enable them in Options and restart Process Hacker."); } }
BOOLEAN EtUiCancelIoThread( __in HWND hWnd, __in PPH_THREAD_ITEM Thread ) { NTSTATUS status; BOOLEAN cont = FALSE; HANDLE threadHandle; IO_STATUS_BLOCK isb; if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( hWnd, L"end", L"I/O for the selected thread", NULL, FALSE )) cont = TRUE; if (!cont) return FALSE; if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, Thread->ThreadId))) { status = NtCancelSynchronousIoFile(threadHandle, NULL, &isb); } if (status == STATUS_NOT_FOUND) { PhShowInformation(hWnd, L"There is no synchronous I/O to cancel."); return FALSE; } else if (!NT_SUCCESS(status)) { PhShowStatus(hWnd, L"Unable to cancel synchronous I/O", status, 0); return FALSE; } return TRUE; }
VOID PhpProcessStartupParameters( VOID ) { static PH_COMMAND_LINE_OPTION options[] = { { PH_ARG_SETTINGS, L"settings", MandatoryArgumentType }, { PH_ARG_NOSETTINGS, L"nosettings", NoArgumentType }, { PH_ARG_SHOWVISIBLE, L"v", NoArgumentType }, { PH_ARG_SHOWHIDDEN, L"hide", NoArgumentType }, { PH_ARG_COMMANDMODE, L"c", NoArgumentType }, { PH_ARG_COMMANDTYPE, L"ctype", MandatoryArgumentType }, { PH_ARG_COMMANDOBJECT, L"cobject", MandatoryArgumentType }, { PH_ARG_COMMANDACTION, L"caction", MandatoryArgumentType }, { PH_ARG_COMMANDVALUE, L"cvalue", MandatoryArgumentType }, { PH_ARG_RUNASSERVICEMODE, L"ras", MandatoryArgumentType }, { PH_ARG_NOKPH, L"nokph", NoArgumentType }, { PH_ARG_INSTALLKPH, L"installkph", NoArgumentType }, { PH_ARG_UNINSTALLKPH, L"uninstallkph", NoArgumentType }, { PH_ARG_DEBUG, L"debug", NoArgumentType }, { PH_ARG_HWND, L"hwnd", MandatoryArgumentType }, { PH_ARG_POINT, L"point", MandatoryArgumentType }, { PH_ARG_SHOWOPTIONS, L"showoptions", NoArgumentType }, { PH_ARG_PHSVC, L"phsvc", NoArgumentType }, { PH_ARG_NOPLUGINS, L"noplugins", NoArgumentType }, { PH_ARG_NEWINSTANCE, L"newinstance", NoArgumentType }, { PH_ARG_ELEVATE, L"elevate", NoArgumentType }, { PH_ARG_SILENT, L"s", NoArgumentType }, { PH_ARG_HELP, L"help", NoArgumentType }, { PH_ARG_SELECTPID, L"selectpid", MandatoryArgumentType }, { PH_ARG_PRIORITY, L"priority", MandatoryArgumentType }, { PH_ARG_PLUGIN, L"plugin", MandatoryArgumentType }, { PH_ARG_SELECTTAB, L"selecttab", MandatoryArgumentType } }; PH_STRINGREF commandLine; PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); memset(&PhStartupParameters, 0, sizeof(PH_STARTUP_PARAMETERS)); if (!PhParseCommandLine( &commandLine, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART, PhpCommandLineOptionCallback, NULL ) || PhStartupParameters.Help) { PhShowInformation( NULL, L"Command line options:\n\n" L"-c\n" L"-ctype command-type\n" L"-cobject command-object\n" L"-caction command-action\n" L"-cvalue command-value\n" L"-debug\n" L"-elevate\n" L"-help\n" L"-hide\n" L"-installkph\n" L"-newinstance\n" L"-nokph\n" L"-noplugins\n" L"-nosettings\n" L"-plugin pluginname:value\n" L"-priority r|h|n|l\n" L"-s\n" L"-selectpid pid-to-select\n" L"-selecttab name-of-tab-to-select\n" L"-settings filename\n" L"-uninstallkph\n" L"-v\n" ); if (PhStartupParameters.Help) RtlExitUserProcess(STATUS_SUCCESS); } if (PhStartupParameters.InstallKph) { NTSTATUS status; PPH_STRING kprocesshackerFileName; KPH_PARAMETERS parameters; kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); parameters.SecurityLevel = KphSecurityNone; parameters.CreateDynamicConfiguration = TRUE; status = KphInstallEx(L"KProcessHacker2", kprocesshackerFileName->Buffer, ¶meters); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) PhShowStatus(NULL, L"Unable to install KProcessHacker", status, 0); RtlExitUserProcess(status); } if (PhStartupParameters.UninstallKph) { NTSTATUS status; status = KphUninstall(L"KProcessHacker2"); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) PhShowStatus(NULL, L"Unable to uninstall KProcessHacker", status, 0); RtlExitUserProcess(status); } if (PhStartupParameters.Elevate && !PhElevated) { PhShellProcessHacker( NULL, NULL, SW_SHOW, PH_SHELL_EXECUTE_ADMIN, PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS, 0, NULL ); RtlExitUserProcess(STATUS_SUCCESS); } if (PhStartupParameters.Debug) { // The symbol provider won't work if this is chosen. PhShowDebugConsole(); } }
INT_PTR CALLBACK MainWndProc( __in HWND hwndDlg, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { // Add the Graphics card name to the Window Title. //PPH_STRING gpuname = GetDriverName(); //PPH_STRING title = PhFormatString(L"Graphics Information (%s)", gpuname->Buffer); //SetWindowText(hwndDlg, title->Buffer); //PhDereferenceObject(gpuname); //PhDereferenceObject(title); // We have already set the group boxes to have WS_EX_TRANSPARENT to fix // the drawing issue that arises when using WS_CLIPCHILDREN. However // in removing the flicker from the graphs the group boxes will now flicker. // It's a good tradeoff since no one stares at the group boxes. PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN); PhCenterWindow(hwndDlg, PhMainWndHandle); PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_ALWAYSONTOP), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhLoadWindowPlacementFromSetting(SETTING_NAME_GFX_WINDOW_POSITION, SETTING_NAME_GFX_WINDOW_SIZE, hwndDlg); PhInitializeGraphState(&GpuGraphState); PhInitializeGraphState(&CoreGraphState); PhInitializeGraphState(&MemGraphState); // TEMP if (GpuHistory.Count == 0) { PhInitializeCircularBuffer_FLOAT(&GpuHistory, PhGetIntegerSetting(L"SampleCount")); PhInitializeCircularBuffer_FLOAT(&CoreHistory, PhGetIntegerSetting(L"SampleCount")); PhInitializeCircularBuffer_ULONG(&MemHistory, PhGetIntegerSetting(L"SampleCount")); } GpuGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)110, PluginInstance->DllBase, NULL ); Graph_SetTooltip(GpuGraphHandle, TRUE); BringWindowToTop(GpuGraphHandle); CoreGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)111, PluginInstance->DllBase, NULL ); Graph_SetTooltip(CoreGraphHandle, TRUE); BringWindowToTop(CoreGraphHandle); MemGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)109, PluginInstance->DllBase, NULL ); Graph_SetTooltip(MemGraphHandle, TRUE); BringWindowToTop(MemGraphHandle); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessesUpdated), GfxUpdateHandler, NULL, &ProcessesUpdatedRegistration ); } break; case WM_DESTROY: { // Unregister our callbacks. PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration); // Save our settings. PhSetIntegerSetting(SETTING_NAME_GFX_ALWAYS_ON_TOP, AlwaysOnTop); PhSaveWindowPlacementToSetting(SETTING_NAME_GFX_WINDOW_POSITION, SETTING_NAME_GFX_WINDOW_SIZE, hwndDlg); // Reset our Window Management. PhDeleteLayoutManager(&WindowLayoutManager); // TEMP commented out. // Clear our buffers. //PhDeleteCircularBuffer_FLOAT(&GpuHistory); //PhDeleteCircularBuffer_ULONG(&MemHistory); // Clear our state. PhDeleteGraphState(&GpuGraphState); PhDeleteGraphState(&MemGraphState); // Quit. PostQuitMessage(0); } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case GCN_GETDRAWINFO: { PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; if (header->hwndFrom == GpuGraphHandle) { if (PhGetIntegerSetting(L"GraphShowText")) { HDC hdc; PhSwapReference2( &GpuGraphState.TooltipText, PhFormatString( L"%.0f%%", CurrentGpuUsage * 100 )); hdc = Graph_GetBufferedContext(GpuGraphHandle); SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &GpuGraphState.TooltipText->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } else { drawInfo->Text.Buffer = NULL; } drawInfo->Flags = PH_GRAPH_USE_GRID; drawInfo->LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel"); //drawInfo->LineColor2 = PhGetIntegerSetting(L"ColorCpuUser"); drawInfo->LineBackColor1 = PhHalveColorBrightness(drawInfo->LineColor1); //drawInfo->LineBackColor2 = PhHalveColorBrightness(drawInfo->LineColor2); PhGraphStateGetDrawInfo( &GpuGraphState, getDrawInfo, GpuHistory.Count ); if (!GpuGraphState.Valid) { PhCopyCircularBuffer_FLOAT( &GpuHistory, getDrawInfo->DrawInfo->LineData1, getDrawInfo->DrawInfo->LineDataCount ); GpuGraphState.Valid = TRUE; } } else if (header->hwndFrom == MemGraphHandle) { if (PhGetIntegerSetting(L"GraphShowText")) { HDC hdc; PhSwapReference2(&MemGraphState.TooltipText, PhFormatString( L"%s / %s (%.2f%%)", PhaFormatSize(UInt32x32To64(CurrentMemUsage, 1024), -1)->Buffer, PhaFormatSize(UInt32x32To64(MaxMemUsage, 1024), -1)->Buffer, (FLOAT)CurrentMemUsage / MaxMemUsage * 100 )); hdc = Graph_GetBufferedContext(MemGraphHandle); SelectObject(hdc, PhApplicationFont); PhSetGraphText( hdc, drawInfo, &MemGraphState.TooltipText->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT ); } else { drawInfo->Text.Buffer = NULL; } drawInfo->Flags = PH_GRAPH_USE_GRID; drawInfo->LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel"); //drawInfo->LineColor2 = PhGetIntegerSetting(L"ColorCpuUser"); drawInfo->LineBackColor1 = PhHalveColorBrightness(drawInfo->LineColor1); //drawInfo->LineBackColor2 = PhHalveColorBrightness(drawInfo->LineColor2); PhGraphStateGetDrawInfo( &MemGraphState, getDrawInfo, MemHistory.Count ); if (!MemGraphState.Valid) { ULONG i = 0; for (i = 0; i < drawInfo->LineDataCount; i++) { MemGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&MemHistory, i); } // Scale the data. PhxfDivideSingle2U( MemGraphState.Data1, (FLOAT)MaxMemUsage, drawInfo->LineDataCount ); MemGraphState.Valid = TRUE; } } else if (header->hwndFrom == CoreGraphHandle) { if (PhGetIntegerSetting(L"GraphShowText")) { HDC hdc; PhSwapReference2( &CoreGraphState.TooltipText, PhFormatString( L"%.0f%%", CurrentCoreUsage * 100 )); hdc = Graph_GetBufferedContext(CoreGraphHandle); SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &CoreGraphState.TooltipText->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } else { drawInfo->Text.Buffer = NULL; } drawInfo->Flags = PH_GRAPH_USE_GRID; drawInfo->LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel"); //drawInfo->LineColor2 = PhGetIntegerSetting(L"ColorCpuUser"); drawInfo->LineBackColor1 = PhHalveColorBrightness(drawInfo->LineColor1); //drawInfo->LineBackColor2 = PhHalveColorBrightness(drawInfo->LineColor2); PhGraphStateGetDrawInfo( &CoreGraphState, getDrawInfo, CoreHistory.Count ); if (!CoreGraphState.Valid) { PhCopyCircularBuffer_FLOAT( &CoreHistory, getDrawInfo->DrawInfo->LineData1, getDrawInfo->DrawInfo->LineDataCount ); CoreGraphState.Valid = TRUE; } } } break; case GCN_GETTOOLTIPTEXT: { PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; if (getTooltipText->Index < getTooltipText->TotalCount) { if (header->hwndFrom == GpuGraphHandle) { if (GpuGraphState.TooltipIndex != getTooltipText->Index) { FLOAT usage; usage = PhGetItemCircularBuffer_FLOAT(&GpuHistory, getTooltipText->Index); PhSwapReference2(&GpuGraphState.TooltipText, PhFormatString( L"%.0f%%", usage * 100 )); } getTooltipText->Text = GpuGraphState.TooltipText->sr; } else if (header->hwndFrom == MemGraphHandle) { if (MemGraphState.TooltipIndex != getTooltipText->Index) { ULONG usage; usage = PhGetItemCircularBuffer_ULONG(&MemHistory, getTooltipText->Index); PhSwapReference2(&MemGraphState.TooltipText, PhFormatString( L"%s / %s (%.2f%%)", PhaFormatSize(UInt32x32To64(usage, 1024), -1)->Buffer, PhaFormatSize(UInt32x32To64(MaxMemUsage, 1024), -1)->Buffer, (FLOAT)usage / MaxMemUsage * 100 )); } getTooltipText->Text = MemGraphState.TooltipText->sr; } else if (header->hwndFrom == CoreGraphHandle) { if (CoreGraphState.TooltipIndex != getTooltipText->Index) { FLOAT usage; usage = PhGetItemCircularBuffer_FLOAT(&CoreHistory, getTooltipText->Index); PhSwapReference2(&CoreGraphState.TooltipText, PhFormatString( L"%.0f%%", usage * 100 )); } getTooltipText->Text = CoreGraphState.TooltipText->sr; } } } break; case GCN_MOUSEEVENT: { PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)lParam; if (mouseEvent->Message == WM_LBUTTONDBLCLK) { if (header->hwndFrom == GpuGraphHandle) { PhShowInformation(hwndDlg, L"Double clicked!"); } } } break; } } break; case WM_SHOWWINDOW: { RECT margin; GfxPanelWindowHandle = CreateDialog( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSGFX_PANEL), hwndDlg, MainPanelDlgProc ); SetWindowPos( GfxPanelWindowHandle, NULL, 10, 0, 0, 0, SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER ); ShowWindow(GfxPanelWindowHandle, SW_SHOW); AlwaysOnTop = (BOOLEAN)PhGetIntegerSetting(SETTING_NAME_GFX_ALWAYS_ON_TOP); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED); GfxSetAlwaysOnTop(); margin.left = 0; margin.top = 0; margin.right = 0; margin.bottom = 25; MapDialogRect(hwndDlg, &margin); PhAddLayoutItemEx( &WindowLayoutManager, GfxPanelWindowHandle, NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT, margin ); SendMessage(hwndDlg, WM_SIZE, 0, 0); SendMessage(hwndDlg, WM_GFX_UPDATE, 0, 0); } break; case WM_SIZE: { HDWP deferHandle; HWND cpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPCONTROLLER); HWND diskGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU); HWND networkGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM); RECT clientRect; RECT panelRect; RECT margin = { 13, 13, 13, 13 }; RECT innerMargin = { 10, 20, 10, 10 }; LONG between = 3; LONG width; LONG height; PhLayoutManagerLayout(&WindowLayoutManager); GpuGraphState.Valid = FALSE; MemGraphState.Valid = FALSE; GetClientRect(hwndDlg, &clientRect); // Limit the rectangle bottom to the top of the panel. GetWindowRect(GfxPanelWindowHandle, &panelRect); MapWindowPoints(NULL, hwndDlg, (POINT *)&panelRect, 2); clientRect.bottom = panelRect.top; width = clientRect.right - margin.left - margin.right; height = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3; deferHandle = BeginDeferWindowPos(6); deferHandle = DeferWindowPos(deferHandle, diskGroupBox, NULL, margin.left, margin.top, width, height, SWP_NOACTIVATE | SWP_NOZORDER); deferHandle = DeferWindowPos( deferHandle, GpuGraphHandle, NULL, margin.left + innerMargin.left, margin.top + innerMargin.top, width - innerMargin.left - innerMargin.right, height - innerMargin.top - innerMargin.bottom, SWP_NOACTIVATE | SWP_NOZORDER ); deferHandle = DeferWindowPos(deferHandle, networkGroupBox, NULL, margin.left, margin.top + height + between, width, height, SWP_NOACTIVATE | SWP_NOZORDER); deferHandle = DeferWindowPos( deferHandle, MemGraphHandle, NULL, margin.left + innerMargin.left, margin.top + height + between + innerMargin.top, width - innerMargin.left - innerMargin.right, height - innerMargin.top - innerMargin.bottom, SWP_NOACTIVATE | SWP_NOZORDER ); deferHandle = DeferWindowPos(deferHandle, cpuGroupBox, NULL, margin.left, margin.top + (height + between) * 2, width, height, SWP_NOACTIVATE | SWP_NOZORDER); deferHandle = DeferWindowPos( deferHandle, CoreGraphHandle, NULL, margin.left + innerMargin.left, margin.top + (height + between) * 2 + innerMargin.top, width - innerMargin.left - innerMargin.right, height - innerMargin.top - innerMargin.bottom, SWP_NOACTIVATE | SWP_NOZORDER ); EndDeferWindowPos(deferHandle); } break; case WM_SIZING: { PhResizingMinimumSize((PRECT)lParam, wParam, 500, 400); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: DestroyWindow(hwndDlg); break; case IDC_ALWAYSONTOP: { AlwaysOnTop = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALWAYSONTOP)) == BST_CHECKED; GfxSetAlwaysOnTop(); } break; } } break; case WM_GFX_ACTIVATE: { if (IsIconic(hwndDlg)) ShowWindow(hwndDlg, SW_RESTORE); else ShowWindow(hwndDlg, SW_SHOW); SetForegroundWindow(hwndDlg); } break; case WM_GFX_UPDATE: { GetGfxUsages(); GetGfxTemp(); GetGfxClockSpeeds(); GpuGraphState.Valid = FALSE; GpuGraphState.TooltipIndex = -1; Graph_MoveGrid(GpuGraphHandle, 1); Graph_Draw(GpuGraphHandle); Graph_UpdateTooltip(GpuGraphHandle); InvalidateRect(GpuGraphHandle, NULL, FALSE); CoreGraphState.Valid = FALSE; CoreGraphState.TooltipIndex = -1; Graph_MoveGrid(CoreGraphHandle, 1); Graph_Draw(CoreGraphHandle); Graph_UpdateTooltip(CoreGraphHandle); InvalidateRect(CoreGraphHandle, NULL, FALSE); MemGraphState.Valid = FALSE; MemGraphState.TooltipIndex = -1; Graph_MoveGrid(MemGraphHandle, 1); Graph_Draw(MemGraphHandle); Graph_UpdateTooltip(MemGraphHandle); InvalidateRect(MemGraphHandle, NULL, FALSE); SendMessage(GfxPanelWindowHandle, WM_GFX_PANEL_UPDATE, 0, 0); } break; } return FALSE; }