Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

699 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: peakmetr.cpp
  6. * Content: Implements a peak meter custom control
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 09/22/99 pnewson Created
  12. * 03/23/00 rodtoll Added casts for Win64
  13. * 04/19/2000 pnewson Error handling cleanup
  14. ***************************************************************************/
  15. #include "dxvtlibpch.h"
  16. #undef DPF_SUBCOMP
  17. #define DPF_SUBCOMP DN_SUBCOMP_VOICE
  18. struct SPeakMeterWndInfo
  19. {
  20. DWORD dwCurLevel;
  21. DWORD dwMinLevel;
  22. DWORD dwMaxLevel;
  23. DWORD dwSteps;
  24. HGDIOBJ hBlackStockPen;
  25. HGDIOBJ hWhiteStockPen;
  26. HGDIOBJ hRedPen;
  27. HGDIOBJ hYellowPen;
  28. HGDIOBJ hGreenPen;
  29. HBRUSH hRedBrush;
  30. HBRUSH hYellowBrush;
  31. HBRUSH hGreenBrush;
  32. };
  33. LRESULT CALLBACK PeakMeterWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  34. LRESULT WM_CREATE_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  35. LRESULT WM_DESTROY_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  36. LRESULT WM_PAINT_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  37. // the window class name of the peak meter custom control
  38. const TCHAR gc_szPeakMeterWindowClassName[] = _T("DirectPlayVoicePeakMeter");
  39. // default values for caller settable data
  40. #define DEFAULT_CURLEVEL 0
  41. #define DEFAULT_MINLEVEL 0
  42. #define DEFAULT_MAXLEVEL 0xffffffff
  43. #define DEFAULT_STEPS 20
  44. // sizes of various things in the window
  45. #define WINDOW_BORDER_SIZE 1
  46. #define MIN_BAR_HEIGHT 2
  47. #define MIN_BAR_WIDTH 2
  48. #define BAR_GUTTER_SIZE 1
  49. #define MIN_NUMBER_BARS 5
  50. // the threshold above which the bar turns yellow, then red
  51. #define RED_THRESHOLD 0.9
  52. #define YELLOW_THRESHOLD 0.8
  53. #undef DPF_MODNAME
  54. #define DPF_MODNAME "CPeakMeterWndClass::Register"
  55. HRESULT CPeakMeterWndClass::Register()
  56. {
  57. WNDCLASS wndclass;
  58. ATOM atom;
  59. HRESULT hr;
  60. LONG lRet;
  61. DPF_ENTER();
  62. m_hinst = GetModuleHandleA(gc_szDVoiceDLLName);
  63. if (m_hinst == NULL)
  64. {
  65. lRet = GetLastError();
  66. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetModuleHandle failed, code: %i", lRet);
  67. hr = DVERR_GENERIC;
  68. goto error_cleanup;
  69. }
  70. wndclass.style = CS_HREDRAW|CS_VREDRAW;
  71. wndclass.lpfnWndProc = PeakMeterWndProc;
  72. wndclass.cbClsExtra = 0;
  73. wndclass.cbWndExtra = sizeof(LONG_PTR);
  74. wndclass.hInstance = m_hinst;
  75. wndclass.hIcon = NULL;
  76. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  77. wndclass.hbrBackground = (HBRUSH) GetSysColorBrush(COLOR_BTNFACE);
  78. wndclass.lpszMenuName = NULL;
  79. wndclass.lpszClassName = gc_szPeakMeterWindowClassName;
  80. atom = RegisterClass(&wndclass);
  81. if (atom == 0)
  82. {
  83. lRet = GetLastError();
  84. DPFX(DPFPREP, DVF_ERRORLEVEL, "RegisterClass failed, code: %i", lRet);
  85. hr = DVERR_GENERIC;
  86. goto error_cleanup;
  87. }
  88. DPF_EXIT();
  89. return S_OK;
  90. error_cleanup:
  91. DPF_EXIT();
  92. return hr;
  93. }
  94. #undef DPF_MODNAME
  95. #define DPF_MODNAME "CPeakMeterWndClass::Unregister"
  96. HRESULT CPeakMeterWndClass::Unregister()
  97. {
  98. HRESULT hr;
  99. LONG lRet;
  100. DPF_ENTER();
  101. if (!UnregisterClass(gc_szPeakMeterWindowClassName, m_hinst))
  102. {
  103. lRet = GetLastError();
  104. DPFX(DPFPREP, DVF_ENTRYLEVEL, "RegisterClass failed, code: %i", lRet);
  105. hr = DVERR_GENERIC;
  106. goto error_cleanup;
  107. }
  108. DPF_EXIT();
  109. return S_OK;
  110. error_cleanup:
  111. DPF_EXIT();
  112. return hr;
  113. }
  114. #undef DPF_MODNAME
  115. #define DPF_MODNAME "PeakMeterWndProc"
  116. LRESULT CALLBACK PeakMeterWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  117. {
  118. LRESULT lres;
  119. LONG lRet;
  120. SPeakMeterWndInfo* lppmwi;
  121. DPF_ENTER();
  122. switch (message)
  123. {
  124. case WM_CREATE:
  125. lres = WM_CREATE_Handler(hwnd, message, wParam, lParam);
  126. DPF_EXIT();
  127. return lres;
  128. case WM_DESTROY:
  129. lres = WM_DESTROY_Handler(hwnd, message, wParam, lParam);
  130. DPF_EXIT();
  131. return lres;
  132. case PM_SETCUR:
  133. case PM_SETMAX:
  134. case PM_SETMIN:
  135. case PM_SETSTEPS:
  136. SetLastError(ERROR_SUCCESS);
  137. lppmwi = (SPeakMeterWndInfo*)GetWindowLongPtr(hwnd, 0);
  138. lRet = GetLastError();
  139. if (lRet != ERROR_SUCCESS)
  140. {
  141. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetWindowLongPtr failed, code: %i", lRet);
  142. DPF_EXIT();
  143. return DVERR_WIN32;
  144. }
  145. switch (message)
  146. {
  147. case PM_SETCUR:
  148. lppmwi->dwCurLevel = (DWORD) lParam;
  149. break;
  150. case PM_SETMAX:
  151. lppmwi->dwMaxLevel = (DWORD) lParam;
  152. break;
  153. case PM_SETMIN:
  154. lppmwi->dwMinLevel = (DWORD) lParam;
  155. break;
  156. case PM_SETSTEPS:
  157. if (lParam < MIN_NUMBER_BARS)
  158. {
  159. lppmwi->dwSteps = MIN_NUMBER_BARS;
  160. }
  161. else
  162. {
  163. lppmwi->dwSteps = (DWORD) lParam;
  164. }
  165. break;
  166. default:
  167. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unreachable code!?!");
  168. DPF_EXIT();
  169. return DVERR_GENERIC;
  170. }
  171. // no error handling available
  172. InvalidateRgn(hwnd, NULL, TRUE);
  173. return S_OK;
  174. case WM_PAINT:
  175. lres = WM_PAINT_Handler(hwnd, message, wParam, lParam);
  176. DPF_EXIT();
  177. return lres;
  178. }
  179. lres = DefWindowProc(hwnd, message, wParam, lParam);
  180. DPF_EXIT();
  181. return lres;
  182. }
  183. LRESULT WM_CREATE_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  184. {
  185. DPF_ENTER();
  186. SPeakMeterWndInfo* lppmwi = NULL;
  187. LONG lRet;
  188. HRESULT hr;
  189. // allocate a window info struct
  190. lppmwi = (SPeakMeterWndInfo*)DNMalloc(sizeof(SPeakMeterWndInfo));
  191. if (lppmwi == NULL)
  192. {
  193. DPFX(DPFPREP, DVF_ERRORLEVEL, "DNMalloc failed");
  194. hr = DVERR_OUTOFMEMORY;
  195. goto error_cleanup;
  196. }
  197. ZeroMemory(lppmwi, sizeof(SPeakMeterWndInfo));
  198. lppmwi->dwCurLevel = DEFAULT_CURLEVEL;
  199. lppmwi->dwMinLevel = DEFAULT_MINLEVEL;
  200. lppmwi->dwMaxLevel = DEFAULT_MAXLEVEL;
  201. lppmwi->dwSteps = DEFAULT_STEPS;
  202. // create the pens and brushes we'll be needing
  203. lppmwi->hBlackStockPen = GetStockObject(BLACK_PEN);
  204. if (lppmwi->hBlackStockPen == NULL)
  205. {
  206. lRet = GetLastError();
  207. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetStockObject failed, code: %i", lRet);
  208. hr = DVERR_GENERIC;
  209. goto error_cleanup;
  210. }
  211. lppmwi->hWhiteStockPen = GetStockObject(WHITE_PEN);
  212. if (lppmwi->hWhiteStockPen == NULL)
  213. {
  214. lRet = GetLastError();
  215. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetStockObject failed, code: %i", lRet);
  216. hr = DVERR_GENERIC;
  217. goto error_cleanup;
  218. }
  219. lppmwi->hRedBrush = CreateSolidBrush(RGB(0xff, 0x00, 0x00));
  220. if (lppmwi->hRedBrush == NULL)
  221. {
  222. lRet = GetLastError();
  223. DPFX(DPFPREP, DVF_ERRORLEVEL, "CreateSolidBrush failed, code: %i", lRet);
  224. hr = DVERR_GENERIC;
  225. goto error_cleanup;
  226. }
  227. lppmwi->hYellowBrush = CreateSolidBrush(RGB(0xff, 0xff, 0x00));
  228. if (lppmwi->hYellowBrush == NULL)
  229. {
  230. lRet = GetLastError();
  231. DPFX(DPFPREP, DVF_ERRORLEVEL, "CreateSolidBrush failed, code: %i", lRet);
  232. hr = DVERR_GENERIC;
  233. goto error_cleanup;
  234. }
  235. lppmwi->hGreenBrush = CreateSolidBrush(RGB(0x00, 0xff, 0x00));
  236. if (lppmwi->hGreenBrush == NULL)
  237. {
  238. lRet = GetLastError();
  239. DPFX(DPFPREP, DVF_ERRORLEVEL, "CreateSolidBrush failed, code: %i", lRet);
  240. hr = DVERR_GENERIC;
  241. goto error_cleanup;
  242. }
  243. lppmwi->hRedPen = CreatePen(PS_SOLID, 1, RGB(0xff, 0x00, 0x00));
  244. if (lppmwi->hRedPen == NULL)
  245. {
  246. lRet = GetLastError();
  247. DPFX(DPFPREP, DVF_ERRORLEVEL, "CreatePen failed, code: %i", lRet);
  248. hr = DVERR_GENERIC;
  249. goto error_cleanup;
  250. }
  251. lppmwi->hYellowPen = CreatePen(PS_SOLID, 1, RGB(0xff, 0xff, 0x00));
  252. if (lppmwi->hYellowPen == NULL)
  253. {
  254. lRet = GetLastError();
  255. DPFX(DPFPREP, DVF_ERRORLEVEL, "CreatePen failed, code: %i", lRet);
  256. hr = DVERR_GENERIC;
  257. goto error_cleanup;
  258. }
  259. lppmwi->hGreenPen = CreatePen(PS_SOLID, 1, RGB(0x00, 0xff, 0x00));
  260. if (lppmwi->hGreenPen == NULL)
  261. {
  262. lRet = GetLastError();
  263. DPFX(DPFPREP, DVF_ERRORLEVEL, "CreatePen failed, code: %i", lRet);
  264. hr = DVERR_GENERIC;
  265. goto error_cleanup;
  266. }
  267. // save the window information
  268. SetLastError(ERROR_SUCCESS);
  269. SetWindowLongPtr(hwnd, 0, (LONG_PTR)lppmwi);
  270. lRet = GetLastError();
  271. if (lRet != ERROR_SUCCESS)
  272. {
  273. DPFX(DPFPREP, DVF_ERRORLEVEL, "SetWindowLongPtr failed, code: %i", lRet);
  274. hr = DVERR_GENERIC;
  275. goto error_cleanup;
  276. }
  277. DPF_EXIT();
  278. return 0; // will continue window creation
  279. error_cleanup:
  280. if (lppmwi != NULL)
  281. {
  282. if (lppmwi->hGreenPen != NULL)
  283. {
  284. DeleteObject(lppmwi->hGreenPen);
  285. lppmwi->hGreenPen = NULL;
  286. }
  287. if (lppmwi->hYellowPen != NULL)
  288. {
  289. DeleteObject(lppmwi->hYellowPen);
  290. lppmwi->hYellowPen = NULL;
  291. }
  292. if (lppmwi->hRedPen != NULL)
  293. {
  294. DeleteObject(lppmwi->hRedPen);
  295. lppmwi->hRedPen = NULL;
  296. }
  297. if (lppmwi->hGreenBrush != NULL)
  298. {
  299. DeleteObject(lppmwi->hGreenBrush);
  300. lppmwi->hGreenBrush = NULL;
  301. }
  302. if (lppmwi->hYellowBrush != NULL)
  303. {
  304. DeleteObject(lppmwi->hYellowBrush);
  305. lppmwi->hYellowBrush = NULL;
  306. }
  307. if (lppmwi->hRedBrush != NULL)
  308. {
  309. DeleteObject(lppmwi->hRedBrush);
  310. lppmwi->hRedBrush = NULL;
  311. }
  312. DNFree(lppmwi);
  313. }
  314. DPF_EXIT();
  315. return -1; // will abort window creation
  316. }
  317. LRESULT WM_DESTROY_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  318. {
  319. DPF_ENTER();
  320. SPeakMeterWndInfo* lppmwi;
  321. LONG lRet;
  322. // get the window info
  323. SetLastError(ERROR_SUCCESS);
  324. lppmwi = (SPeakMeterWndInfo*)GetWindowLongPtr(hwnd, 0);
  325. lRet = GetLastError();
  326. if (lRet != ERROR_SUCCESS)
  327. {
  328. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetWindowLongPtr failed, code: %i", lRet);
  329. // Couldn't get the pointer, so can't clean anything else up!
  330. DPF_EXIT();
  331. return 0; // not sure what returning non-zero will do...
  332. }
  333. // set the window info to null, just in case...
  334. SetLastError(ERROR_SUCCESS);
  335. SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL);
  336. lRet = GetLastError();
  337. if (lRet != ERROR_SUCCESS)
  338. {
  339. DPFX(DPFPREP, DVF_ERRORLEVEL, "SetWindowLongPtr failed, code: %i", lRet);
  340. }
  341. if (lppmwi != NULL)
  342. {
  343. if (lppmwi->hGreenPen != NULL)
  344. {
  345. DeleteObject(lppmwi->hGreenPen);
  346. lppmwi->hGreenPen = NULL;
  347. }
  348. if (lppmwi->hYellowPen != NULL)
  349. {
  350. DeleteObject(lppmwi->hYellowPen);
  351. lppmwi->hYellowPen = NULL;
  352. }
  353. if (lppmwi->hRedPen != NULL)
  354. {
  355. DeleteObject(lppmwi->hRedPen);
  356. lppmwi->hRedPen = NULL;
  357. }
  358. if (lppmwi->hGreenBrush != NULL)
  359. {
  360. DeleteObject(lppmwi->hGreenBrush);
  361. lppmwi->hGreenBrush = NULL;
  362. }
  363. if (lppmwi->hYellowBrush != NULL)
  364. {
  365. DeleteObject(lppmwi->hYellowBrush);
  366. lppmwi->hYellowBrush = NULL;
  367. }
  368. if (lppmwi->hRedBrush != NULL)
  369. {
  370. DeleteObject(lppmwi->hRedBrush);
  371. lppmwi->hRedBrush = NULL;
  372. }
  373. DNFree(lppmwi);
  374. }
  375. DPF_EXIT();
  376. return 0;
  377. }
  378. LRESULT WM_PAINT_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  379. {
  380. DPF_ENTER();
  381. LONG lRet;
  382. HDC hdc = NULL;
  383. PAINTSTRUCT ps;
  384. RECT rect;
  385. SPeakMeterWndInfo* lppmwi;
  386. DWORD dwStepsLocal;
  387. // get the window info
  388. SetLastError(ERROR_SUCCESS);
  389. lppmwi = (SPeakMeterWndInfo*)GetWindowLongPtr(hwnd, 0);
  390. lRet = GetLastError();
  391. if (lRet != ERROR_SUCCESS)
  392. {
  393. DPFX(DPFPREP, DVF_ERRORLEVEL, "SetWindowLongPtr failed, code: %i", lRet);
  394. goto error_cleanup;
  395. }
  396. // get the client rectangle
  397. if (!GetClientRect(hwnd, &rect))
  398. {
  399. lRet = GetLastError();
  400. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetClientRect failed, code: %i", lRet);
  401. goto error_cleanup;
  402. }
  403. // start painting
  404. hdc = BeginPaint(hwnd, &ps);
  405. if (hdc == NULL)
  406. {
  407. lRet = GetLastError();
  408. DPFX(DPFPREP, DVF_ERRORLEVEL, "BeginPaint failed, code: %i", lRet);
  409. goto error_cleanup;
  410. }
  411. // make sure the client rectangle is a minimum reasonable size.
  412. if (rect.right - rect.left <
  413. 2 * WINDOW_BORDER_SIZE +
  414. 2 * BAR_GUTTER_SIZE +
  415. MIN_BAR_WIDTH
  416. || rect.bottom - rect.top <
  417. 2 * WINDOW_BORDER_SIZE +
  418. (MIN_BAR_HEIGHT + BAR_GUTTER_SIZE) * MIN_NUMBER_BARS )
  419. {
  420. // unreasonable size - fill the whole rect with red so
  421. // the developer will notice
  422. if (SelectObject(hdc, lppmwi->hRedPen) == NULL)
  423. {
  424. lRet = GetLastError();
  425. DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet);
  426. goto error_cleanup;
  427. }
  428. if (SelectObject(hdc, lppmwi->hRedBrush) == NULL)
  429. {
  430. lRet = GetLastError();
  431. DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet);
  432. goto error_cleanup;
  433. }
  434. if (!Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom))
  435. {
  436. lRet = GetLastError();
  437. DPFX(DPFPREP, DVF_ERRORLEVEL, "Rectangle failed, code: %i", lRet);
  438. goto error_cleanup;
  439. }
  440. }
  441. else
  442. {
  443. // select the black pen - should be the default, but I'm paranoid
  444. if (SelectObject(hdc, lppmwi->hBlackStockPen) == NULL)
  445. {
  446. lRet = GetLastError();
  447. DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet);
  448. goto error_cleanup;
  449. }
  450. // move to the upper left corner, again should be default.
  451. if (!MoveToEx(hdc, 0, 0, NULL))
  452. {
  453. lRet = GetLastError();
  454. DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet);
  455. goto error_cleanup;
  456. }
  457. // draw a black line across the top
  458. if (!LineTo(hdc, rect.right, 0))
  459. {
  460. lRet = GetLastError();
  461. DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet);
  462. goto error_cleanup;
  463. }
  464. // move to one pixel below the upper left
  465. if (!MoveToEx(hdc, 0, 1, NULL))
  466. {
  467. lRet = GetLastError();
  468. DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet);
  469. goto error_cleanup;
  470. }
  471. // draw a black line down the left side, leave the last pixel alone.
  472. if (!LineTo(hdc, 0, rect.bottom-1))
  473. {
  474. lRet = GetLastError();
  475. DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet);
  476. goto error_cleanup;
  477. }
  478. // select the white pen
  479. if (SelectObject(hdc, lppmwi->hWhiteStockPen) == NULL)
  480. {
  481. lRet = GetLastError();
  482. DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet);
  483. goto error_cleanup;
  484. }
  485. // move to the upper right corner
  486. if (!MoveToEx(hdc, rect.right-1 , 0, NULL))
  487. {
  488. lRet = GetLastError();
  489. DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet);
  490. goto error_cleanup;
  491. }
  492. // draw a white line down the right side
  493. if (!LineTo(hdc, rect.right-1, rect.bottom))
  494. {
  495. lRet = GetLastError();
  496. DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet);
  497. goto error_cleanup;
  498. }
  499. // move to the lower left corner,
  500. if (!MoveToEx(hdc, 0 , rect.bottom-1, NULL))
  501. {
  502. lRet = GetLastError();
  503. DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet);
  504. goto error_cleanup;
  505. }
  506. // draw a white line across the bottom
  507. if (!LineTo(hdc, rect.right-1, rect.bottom-1))
  508. {
  509. lRet = GetLastError();
  510. DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet);
  511. goto error_cleanup;
  512. }
  513. // see if there is enough room to display the suggested
  514. // number of bars.
  515. DWORD dwFreeSpace = (rect.bottom) - (2 * WINDOW_BORDER_SIZE) - BAR_GUTTER_SIZE;
  516. if (dwFreeSpace < lppmwi->dwSteps * (BAR_GUTTER_SIZE + MIN_BAR_HEIGHT))
  517. {
  518. // There is not enough room to display the suggested size.
  519. // Figure out how many bars we can display if they are the
  520. // minimum size.
  521. dwStepsLocal = dwFreeSpace / (BAR_GUTTER_SIZE + MIN_BAR_HEIGHT);
  522. }
  523. else
  524. {
  525. dwStepsLocal = lppmwi->dwSteps;
  526. }
  527. // start drawing the bars from the bottom up
  528. HBRUSH hCurBrush;
  529. HGDIOBJ hCurPen;
  530. DWORD dwIndex;
  531. for (dwIndex = 0; dwIndex < dwStepsLocal; ++dwIndex)
  532. {
  533. // what "value" does the bar we are about to draw have?
  534. // i.e. how far up the scale is it?
  535. float fBarValue = (float)(dwIndex + 1) / (float)dwStepsLocal;
  536. // what is the "value" of the control at this moment?
  537. // i.e. how far up the scale should the bars go?
  538. float fCurValue =
  539. (float)(lppmwi->dwCurLevel - lppmwi->dwMinLevel) /
  540. (float)(lppmwi->dwMaxLevel - lppmwi->dwMinLevel);
  541. // are we done drawning bars?
  542. if (fBarValue > fCurValue)
  543. {
  544. // that's it, we're finished
  545. break;
  546. }
  547. // figure out what color this bar should be
  548. if (fBarValue > RED_THRESHOLD)
  549. {
  550. hCurBrush = lppmwi->hRedBrush;
  551. hCurPen = lppmwi->hRedPen;
  552. }
  553. else if (fBarValue > YELLOW_THRESHOLD)
  554. {
  555. hCurBrush = lppmwi->hYellowBrush;
  556. hCurPen = lppmwi->hYellowPen;
  557. }
  558. else
  559. {
  560. hCurBrush = lppmwi->hGreenBrush;
  561. hCurPen = lppmwi->hGreenPen;
  562. }
  563. if (SelectObject(hdc, hCurPen) == NULL)
  564. {
  565. lRet = GetLastError();
  566. DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet);
  567. goto error_cleanup;
  568. }
  569. if (SelectObject(hdc, hCurBrush) == NULL)
  570. {
  571. lRet = GetLastError();
  572. DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet);
  573. goto error_cleanup;
  574. }
  575. POINT pUpperLeft;
  576. POINT pLowerRight;
  577. pUpperLeft.x = WINDOW_BORDER_SIZE + BAR_GUTTER_SIZE;
  578. pUpperLeft.y = (rect.bottom)
  579. - WINDOW_BORDER_SIZE
  580. - ((dwIndex + 1) * dwFreeSpace) / dwStepsLocal;
  581. pLowerRight.x = rect.right
  582. - WINDOW_BORDER_SIZE
  583. - BAR_GUTTER_SIZE;
  584. pLowerRight.y = (rect.bottom)
  585. - WINDOW_BORDER_SIZE
  586. - BAR_GUTTER_SIZE
  587. - (dwIndex * dwFreeSpace) / dwStepsLocal;
  588. if (!Rectangle(hdc, pUpperLeft.x, pUpperLeft.y, pLowerRight.x, pLowerRight.y))
  589. {
  590. lRet = GetLastError();
  591. DPFX(DPFPREP, DVF_ERRORLEVEL, "Rectangle failed, code: %i", lRet);
  592. goto error_cleanup;
  593. }
  594. }
  595. }
  596. // we're done - no error checking available on this call...
  597. EndPaint(hwnd, &ps);
  598. hdc = NULL;
  599. // return zero to indicate that we processed this message
  600. DPF_EXIT();
  601. return 0;
  602. error_cleanup:
  603. if (hdc != NULL)
  604. {
  605. EndPaint(hwnd, &ps);
  606. hdc = NULL;
  607. }
  608. // return non-zero to indicate that we did not process
  609. // this message successfully
  610. DPF_EXIT();
  611. return -1;
  612. }