[TASKMGR] Fix a heap corruption bug (#4311)
[reactos.git] / base / applications / taskmgr / graphctl.c
1 /*
2 * PROJECT: ReactOS Task Manager
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Graph plotting controls
5 * COPYRIGHT: Copyright 2002 Robert Dickenson <robd@reactos.org>
6 * Copyright 2021 Wu Haotian <rigoligo03@gmail.com>
7 */
8
9 #include "precomp.h"
10
11 #include <math.h>
12
13 WNDPROC OldGraphCtrlWndProc;
14
15 BOOL
16 GraphCtrl_Create(PTM_GRAPH_CONTROL inst, HWND hWnd, HWND hParentWnd, PTM_FORMAT fmt)
17 {
18 HDC hdc, hdcg;
19 HBITMAP hbmOld;
20 UINT Size;
21 INT p;
22 RECT rc;
23
24 inst->hParentWnd = hParentWnd;
25 inst->hWnd = hWnd;
26
27 Size = GetSystemMetrics(SM_CXSCREEN);
28 inst->BitmapWidth = Size;
29 Size /= PLOT_SHIFT;
30 inst->PointBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size * NUM_PLOTS);
31 if (!inst->PointBuffer)
32 {
33 goto fail;
34 }
35
36 inst->NumberOfPoints = Size;
37 inst->CurrIndex = 0;
38
39 /* Styling */
40 inst->hPenGrid = CreatePen(PS_SOLID, 0, fmt->clrGrid);
41 inst->hPen0 = CreatePen(PS_SOLID, 0, fmt->clrPlot0);
42 inst->hPen1 = CreatePen(PS_SOLID, 0, fmt->clrPlot1);
43 inst->hBrushBack = CreateSolidBrush(fmt->clrBack);
44
45 if (!inst->hPenGrid ||
46 !inst->hPen0 ||
47 !inst->hPen1 ||
48 !inst->hBrushBack)
49 {
50 goto fail;
51 }
52
53 if (fmt->GridCellWidth >= PLOT_SHIFT << 2)
54 inst->GridCellWidth = fmt->GridCellWidth;
55 else
56 inst->GridCellWidth = PLOT_SHIFT << 2;
57 if (fmt->GridCellHeight >= PLOT_SHIFT << 2)
58 inst->GridCellHeight = fmt->GridCellHeight;
59 else
60 inst->GridCellHeight = PLOT_SHIFT << 2;
61
62 inst->DrawSecondaryPlot = fmt->DrawSecondaryPlot;
63
64 GetClientRect(hWnd, &rc);
65 inst->BitmapHeight = rc.bottom;
66 inst->ftPixelsPerPercent = (FLOAT)(inst->BitmapHeight) / 100.00f;
67
68 hdc = GetDC(hParentWnd);
69 hdcg = CreateCompatibleDC(hdc);
70 inst->hdcGraph = hdcg;
71 inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, inst->BitmapHeight);
72
73 if (!hdc ||
74 !hdcg ||
75 !inst->hbmGraph)
76 {
77 goto fail;
78 }
79
80 ReleaseDC(hParentWnd, hdc);
81 hbmOld = (HBITMAP)SelectObject(hdcg, inst->hbmGraph);
82 DeleteObject(hbmOld);
83
84 SetBkColor(hdcg, fmt->clrBack);
85 rc.right = inst->BitmapWidth;
86 FillRect(hdcg, &rc, inst->hBrushBack);
87
88 inst->CurrShift = 0;
89 SelectObject(hdcg, inst->hPenGrid);
90 for (p = inst->GridCellHeight - 1;
91 p < inst->BitmapHeight;
92 p += inst->GridCellHeight)
93 {
94 MoveToEx(hdcg, 0, p, NULL);
95 LineTo(hdcg, inst->BitmapWidth, p);
96 }
97 for (p = inst->BitmapWidth - 1;
98 p > 0;
99 p -= inst->GridCellWidth)
100 {
101 MoveToEx(hdcg, p, 0, NULL);
102 LineTo(hdcg, p, inst->BitmapHeight);
103 }
104 SelectObject(hdcg, inst->hPen0);
105
106 return TRUE;
107
108 fail:
109 GraphCtrl_Dispose(inst);
110 return FALSE;
111 }
112
113 void
114 GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst)
115 {
116 if (inst->PointBuffer)
117 HeapFree(GetProcessHeap(), 0, inst->PointBuffer);
118
119 if (inst->hPenGrid)
120 DeleteObject(inst->hPenGrid);
121
122 if (inst->hPen0)
123 DeleteObject(inst->hPen0);
124
125 if (inst->hPen1)
126 DeleteObject(inst->hPen1);
127
128 if (inst->hBrushBack)
129 DeleteObject(inst->hBrushBack);
130
131 if (inst->hbmGraph)
132 DeleteObject(inst->hbmGraph);
133
134 if (inst->hdcGraph)
135 DeleteObject(inst->hdcGraph);
136 }
137
138 void
139 GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst, BYTE val0, BYTE val1)
140 {
141 HDC hdcg;
142 PBYTE t;
143 RECT rcDirt;
144
145 UINT Prev0, Prev1, RetainingWidth;
146 INT PrevY, CurrY, p, v;
147
148 hdcg = inst->hdcGraph;
149 RetainingWidth = inst->BitmapWidth - PLOT_SHIFT;
150 t = inst->PointBuffer;
151 Prev0 = *(t + inst->CurrIndex);
152 Prev1 = *(t + inst->CurrIndex + inst->NumberOfPoints);
153 if (inst->CurrIndex < inst->NumberOfPoints - 1)
154 {
155 inst->CurrIndex++;
156 }
157 else
158 {
159 inst->CurrIndex = 0;
160 }
161 *(t + inst->CurrIndex) = val0;
162 *(t + inst->CurrIndex + inst->NumberOfPoints) = val1;
163
164 /* Drawing points, first shifting the plot left */
165 BitBlt(hdcg, 0, 0, RetainingWidth, inst->BitmapHeight, hdcg, PLOT_SHIFT, 0, SRCCOPY);
166
167 rcDirt.left = RetainingWidth;
168 rcDirt.top = 0;
169 rcDirt.right = inst->BitmapWidth;
170 rcDirt.bottom = inst->BitmapHeight;
171 FillRect(hdcg, &rcDirt, inst->hBrushBack);
172
173 SelectObject(hdcg, inst->hPenGrid);
174 for (p = inst->GridCellHeight - 1;
175 p < inst->BitmapHeight;
176 p += inst->GridCellHeight)
177 {
178 MoveToEx(hdcg, RetainingWidth, p, NULL);
179 LineTo(hdcg, inst->BitmapWidth, p);
180 }
181 v = inst->CurrShift + PLOT_SHIFT;
182 if (v >= inst->GridCellWidth)
183 {
184 v -= inst->GridCellWidth;
185 p = inst->BitmapWidth - v - 1;
186 MoveToEx(hdcg, p, 0, NULL);
187 LineTo(hdcg, p, inst->BitmapHeight);
188 }
189 inst->CurrShift = v;
190
191 if (inst->DrawSecondaryPlot)
192 {
193 SelectObject(inst->hdcGraph, inst->hPen1);
194
195 PrevY = inst->BitmapHeight - Prev1 * inst->ftPixelsPerPercent;
196 MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
197 CurrY = inst->BitmapHeight - val1 * inst->ftPixelsPerPercent;
198 LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
199 }
200
201 SelectObject(inst->hdcGraph, inst->hPen0);
202 PrevY = inst->BitmapHeight - Prev0 * inst->ftPixelsPerPercent;
203 MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
204 CurrY = inst->BitmapHeight - val0 * inst->ftPixelsPerPercent;
205 LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
206 }
207
208 inline void
209 GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst, INT h)
210 {
211 HDC hdcg;
212 PBYTE t;
213 RECT rc;
214 INT i, j, y, x, p;
215 FLOAT coef;
216
217 hdcg = inst->hdcGraph;
218 rc.left = 0; rc.top = 0;
219 rc.right = inst->BitmapWidth; rc.bottom = h;
220 FillRect(hdcg, &rc, inst->hBrushBack);
221
222 SelectObject(hdcg, inst->hPenGrid);
223
224 for (p = inst->GridCellHeight - 1;
225 p < inst->BitmapHeight;
226 p += inst->GridCellHeight)
227 {
228 MoveToEx(hdcg, 0, p, NULL);
229 LineTo(hdcg, inst->BitmapWidth, p);
230 }
231
232 for (p = inst->BitmapWidth - inst->CurrShift - 1;
233 p > 0;
234 p -= inst->GridCellWidth)
235 {
236 MoveToEx(hdcg, p, 0, NULL);
237 LineTo(hdcg, p, inst->BitmapHeight);
238 }
239
240 coef = inst->ftPixelsPerPercent;
241
242 if (inst->DrawSecondaryPlot)
243 {
244 SelectObject(hdcg, inst->hPen1);
245 t = inst->PointBuffer + inst->NumberOfPoints;
246 x = inst->BitmapWidth - 1;
247 j = inst->CurrIndex;
248 y = h - *(t + j) * coef;
249 MoveToEx(hdcg, x, y, NULL);
250 for (i = 0; i < inst->NumberOfPoints; i++)
251 {
252 j = (j ? j : inst->NumberOfPoints) - 1;
253 y = h - *(t + j) * coef;
254 x -= PLOT_SHIFT;
255 LineTo(hdcg, x, y);
256 }
257 }
258
259 SelectObject(hdcg, inst->hPen0);
260 t = inst->PointBuffer;
261 x = inst->BitmapWidth - 1;
262 j = inst->CurrIndex;
263 y = h - *(t + j) * coef;
264 MoveToEx(hdcg, x, y, NULL);
265
266 for (i = 0; i < inst->NumberOfPoints; i++)
267 {
268 j = (j ? j : inst->NumberOfPoints) - 1;
269 y = h - *(t + j) * coef;
270 x -= PLOT_SHIFT;
271 LineTo(hdcg, x, y);
272 }
273 }
274
275 inline void
276 GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst, INT nh)
277 {
278 HDC hdc;
279 HBITMAP hbmOld;
280
281 inst->BitmapHeight = nh;
282 inst->ftPixelsPerPercent = (FLOAT)nh / 100.00f;
283
284 hdc = GetDC(inst->hParentWnd);
285 hbmOld = inst->hbmGraph;
286 inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, nh);
287 SelectObject(inst->hdcGraph, inst->hbmGraph);
288 DeleteObject(hbmOld);
289 ReleaseDC(inst->hParentWnd, hdc);
290
291 GraphCtrl_RedrawBitmap(inst, nh);
292 }
293
294 extern TM_GRAPH_CONTROL PerformancePageCpuUsageHistoryGraph;
295 extern TM_GRAPH_CONTROL PerformancePageMemUsageHistoryGraph;
296 extern HWND hPerformancePageCpuUsageHistoryGraph;
297 extern HWND hPerformancePageMemUsageHistoryGraph;
298
299 INT_PTR CALLBACK
300 GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
301 {
302 PTM_GRAPH_CONTROL graph;
303
304 switch (message)
305 {
306 case WM_ERASEBKGND:
307 return TRUE;
308 /*
309 * Filter out mouse & keyboard messages
310 */
311 // case WM_APPCOMMAND:
312 case WM_CAPTURECHANGED:
313 case WM_LBUTTONDBLCLK:
314 case WM_LBUTTONDOWN:
315 case WM_LBUTTONUP:
316 case WM_MBUTTONDBLCLK:
317 case WM_MBUTTONDOWN:
318 case WM_MBUTTONUP:
319 case WM_MOUSEACTIVATE:
320 case WM_MOUSEHOVER:
321 case WM_MOUSELEAVE:
322 case WM_MOUSEMOVE:
323 // case WM_MOUSEWHEEL:
324 case WM_NCHITTEST:
325 case WM_NCLBUTTONDBLCLK:
326 case WM_NCLBUTTONDOWN:
327 case WM_NCLBUTTONUP:
328 case WM_NCMBUTTONDBLCLK:
329 case WM_NCMBUTTONDOWN:
330 case WM_NCMBUTTONUP:
331 // case WM_NCMOUSEHOVER:
332 // case WM_NCMOUSELEAVE:
333 case WM_NCMOUSEMOVE:
334 case WM_NCRBUTTONDBLCLK:
335 case WM_NCRBUTTONDOWN:
336 case WM_NCRBUTTONUP:
337 // case WM_NCXBUTTONDBLCLK:
338 // case WM_NCXBUTTONDOWN:
339 // case WM_NCXBUTTONUP:
340 case WM_RBUTTONDBLCLK:
341 case WM_RBUTTONDOWN:
342 case WM_RBUTTONUP:
343 // case WM_XBUTTONDBLCLK:
344 // case WM_XBUTTONDOWN:
345 // case WM_XBUTTONUP:
346 case WM_ACTIVATE:
347 case WM_CHAR:
348 case WM_DEADCHAR:
349 case WM_GETHOTKEY:
350 case WM_HOTKEY:
351 case WM_KEYDOWN:
352 case WM_KEYUP:
353 case WM_KILLFOCUS:
354 case WM_SETFOCUS:
355 case WM_SETHOTKEY:
356 case WM_SYSCHAR:
357 case WM_SYSDEADCHAR:
358 case WM_SYSKEYDOWN:
359 case WM_SYSKEYUP:
360 return 0;
361
362 case WM_NCCALCSIZE:
363 return 0;
364
365 case WM_SIZE:
366 {
367 if (hWnd == hPerformancePageCpuUsageHistoryGraph)
368 graph = &PerformancePageCpuUsageHistoryGraph;
369 else if (hWnd == hPerformancePageMemUsageHistoryGraph)
370 graph = &PerformancePageMemUsageHistoryGraph;
371 else
372 return 0;
373
374 if (HIWORD(lParam) != graph->BitmapHeight)
375 {
376 GraphCtrl_RedrawOnHeightChange(graph, HIWORD(lParam));
377 }
378 InvalidateRect(hWnd, NULL, FALSE);
379
380 return 0;
381 }
382
383 case WM_PAINT:
384 {
385 RECT rcClient;
386 HDC hdc;
387 PAINTSTRUCT ps;
388
389 if (hWnd == hPerformancePageCpuUsageHistoryGraph)
390 graph = &PerformancePageCpuUsageHistoryGraph;
391 else if (hWnd == hPerformancePageMemUsageHistoryGraph)
392 graph = &PerformancePageMemUsageHistoryGraph;
393 else
394 return 0;
395
396 hdc = BeginPaint(hWnd, &ps);
397 GetClientRect(hWnd, &rcClient);
398 BitBlt(hdc, 0, 0,
399 rcClient.right,
400 rcClient.bottom,
401 graph->hdcGraph,
402 graph->BitmapWidth - rcClient.right,
403 0,
404 SRCCOPY);
405 EndPaint(hWnd, &ps);
406 return 0;
407 }
408 }
409
410 /*
411 * We pass on all non-handled messages
412 */
413 return CallWindowProcW(OldGraphCtrlWndProc, hWnd, message, wParam, lParam);
414 }