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.

790 lines
22 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: image.cpp
  4. //
  5. // Module: CMDIAL and CMAK
  6. //
  7. // Synopsis: CMDIAL/CMAK specific imaging support routines
  8. //
  9. // Copyright (c) 1998-1999 Microsoft Corporation
  10. //
  11. // Author: nickball Created Header 03/30/98
  12. // quintinb moved to common\source 08/06/98
  13. //
  14. //+----------------------------------------------------------------------------
  15. //+---------------------------------------------------------------------------
  16. //
  17. // Function: CmGetBitmapInfo
  18. //
  19. // Synopsis: Helper function to retrieve the contents of a bitmap from an HBITMAP
  20. //
  21. // Arguments: hbm - Hanhdle of the target bitmap
  22. //
  23. // Returns: A pointer to a LPBITMAPINFO that contains the INFOHEADER,
  24. // ColorTable and bits for the bitmap.
  25. //
  26. // Note: When accessing this value, or passing it on to other BITMAP APIs
  27. // it is recommended that the value be cast as an (LPBYTE).
  28. //
  29. // History: a-nichb - Cleaned-up and commented - 3/21/97
  30. //
  31. //----------------------------------------------------------------------------
  32. LPBITMAPINFO CmGetBitmapInfo(HBITMAP hbm)
  33. {
  34. LPBITMAPINFO pbmi = NULL;
  35. HDC hDC = NULL;
  36. int nNumColors = 0;
  37. int iRes;
  38. LPBITMAPINFO lpbmih = NULL;
  39. DWORD dwInfoSize = 0;
  40. WORD wbiBits = 0;
  41. if (!hbm)
  42. {
  43. return NULL;
  44. }
  45. // Get the basic bmp object info
  46. BITMAP BitMap;
  47. if (!GetObjectA(hbm, sizeof(BITMAP), &BitMap))
  48. {
  49. goto Cleanup;
  50. }
  51. // Calc the color bits and num colors
  52. wbiBits = BitMap.bmPlanes * BitMap.bmBitsPixel;
  53. if (wbiBits <= 8)
  54. {
  55. nNumColors = 1 << wbiBits;
  56. }
  57. // Allocate a BITMAPINFO structure large enough to hold header + color palette
  58. dwInfoSize = sizeof(BITMAPINFOHEADER) + (nNumColors * sizeof(RGBQUAD));
  59. lpbmih = (LPBITMAPINFO) CmMalloc(dwInfoSize);
  60. if (!lpbmih)
  61. {
  62. goto Cleanup;
  63. }
  64. // Pre-fill the info that we have about the bmp
  65. lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  66. lpbmih->bmiHeader.biWidth = BitMap.bmWidth;
  67. lpbmih->bmiHeader.biHeight = BitMap.bmHeight;
  68. lpbmih->bmiHeader.biPlanes = 1;
  69. lpbmih->bmiHeader.biBitCount = wbiBits;
  70. // Call GetDiBits() w/ 5th Param to NULL, this is treated by the system as
  71. // a query in which case it validates the lpbmih contents and fills in the
  72. // biSizeImage member of the structure
  73. hDC = GetDC(NULL);
  74. if (!hDC)
  75. {
  76. goto Cleanup;
  77. }
  78. iRes = GetDIBits(hDC,hbm,0,BitMap.bmHeight,NULL,(LPBITMAPINFO) lpbmih,DIB_RGB_COLORS);
  79. #ifdef DEBUG
  80. if (!iRes)
  81. {
  82. CMTRACE(TEXT("CmGetBitmapInfo() GetDIBits() failed."));
  83. }
  84. #endif
  85. if (iRes)
  86. {
  87. DWORD dwFullSize = dwInfoSize;
  88. // Create a complete DIB structure with room for bits and fill it
  89. if (lpbmih->bmiHeader.biSizeImage)
  90. {
  91. dwFullSize += lpbmih->bmiHeader.biSizeImage;
  92. }
  93. else
  94. {
  95. dwFullSize += (((WORD) (lpbmih->bmiHeader.biWidth * lpbmih->bmiHeader.biBitCount) / 8) * (WORD) BitMap.bmHeight);
  96. }
  97. pbmi = (LPBITMAPINFO) CmMalloc(dwFullSize + sizeof(DWORD));
  98. #ifdef DEBUG
  99. *((DWORD *) (((PBYTE) pbmi)+dwFullSize)) = 0x12345678;
  100. *((DWORD *) (((PBYTE) pbmi)+dwFullSize-sizeof(DWORD))) = 0x23456789;
  101. #endif
  102. if (pbmi)
  103. {
  104. // Load the new larger LPBITMAPINFO struct with existing info,
  105. // and get the data bits. Release the existing LPBITMAPINFO.
  106. CopyMemory(pbmi, lpbmih, dwInfoSize);
  107. //
  108. // We have a handle, we want the exact bits.
  109. //
  110. iRes = GetDIBits(hDC,
  111. hbm,
  112. 0,
  113. BitMap.bmHeight,
  114. ((LPBYTE) pbmi) + dwInfoSize,
  115. pbmi,
  116. DIB_RGB_COLORS);
  117. #ifdef DEBUG
  118. if (*((DWORD *) (((PBYTE) pbmi) + dwFullSize)) != 0x12345678)
  119. {
  120. CMTRACE(TEXT("CmGetBitmapInfo() GetDIBits() copied too much."));
  121. }
  122. if (*((DWORD *) (((PBYTE) pbmi) + dwFullSize - sizeof(DWORD))) == 0x23456789)
  123. {
  124. CMTRACE(TEXT("CmGetBitmapInfo() GetDIBits() didn't copy enough."));
  125. }
  126. #endif
  127. // If GetDiBits() failed, free the BITMAPINFO buffer
  128. if (!iRes)
  129. {
  130. CmFree(pbmi);
  131. pbmi = NULL;
  132. }
  133. }
  134. }
  135. // Cleanup
  136. Cleanup:
  137. if (lpbmih)
  138. {
  139. CmFree(lpbmih);
  140. }
  141. if (hDC)
  142. {
  143. ReleaseDC(NULL, hDC);
  144. }
  145. return pbmi;
  146. }
  147. static HPALETTE CmCreateDIBPalette(LPBITMAPINFO pbmi)
  148. {
  149. WORD wNumColors = 0;
  150. HPALETTE hRes = NULL;
  151. if (!pbmi)
  152. {
  153. return (NULL);
  154. }
  155. // Get num colors according to color depth
  156. // Note: 24-bit bitmaps have no color table
  157. if (pbmi->bmiHeader.biBitCount <= 8)
  158. {
  159. wNumColors = 1 << pbmi->bmiHeader.biBitCount;
  160. }
  161. // Fill logical palette based upon color table
  162. if (wNumColors)
  163. {
  164. LPLOGPALETTE pLogPal;
  165. int idx;
  166. pLogPal = (LPLOGPALETTE) CmMalloc(sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*wNumColors);
  167. if (pLogPal)
  168. {
  169. pLogPal->palVersion = 0x300;
  170. pLogPal->palNumEntries = wNumColors;
  171. for (idx=0;idx<wNumColors;idx++)
  172. {
  173. pLogPal->palPalEntry[idx].peRed = pbmi->bmiColors[idx].rgbRed;
  174. pLogPal->palPalEntry[idx].peGreen = pbmi->bmiColors[idx].rgbGreen;
  175. pLogPal->palPalEntry[idx].peBlue = pbmi->bmiColors[idx].rgbBlue;
  176. pLogPal->palPalEntry[idx].peFlags = 0;
  177. }
  178. // Create a new palette
  179. hRes = CreatePalette(pLogPal);
  180. #ifdef DEBUG
  181. if (!hRes)
  182. {
  183. CMTRACE1(TEXT("CmCreateDIBPalette() CreatePalette() failed, GLE=%u."), GetLastError());
  184. }
  185. #endif
  186. CmFree(pLogPal);
  187. }
  188. }
  189. return hRes;
  190. }
  191. HBITMAP CmLoadBitmap(HINSTANCE hInst, LPCTSTR pszSpec)
  192. {
  193. return ((HBITMAP) CmLoadImage(hInst, pszSpec, IMAGE_BITMAP, 0, 0));
  194. }
  195. //+----------------------------------------------------------------------------
  196. //
  197. // Function: ReleaseBitmapData
  198. //
  199. // Synopsis: Releases resources and memory acquired during CreateBitmapData. Note
  200. // that if you are using this with the BmpWndProc function below, that you
  201. // should call an STM_SETIMAGE with a NULL image pointer param in order to
  202. // clear out the window procedures window long. Otherwise, it could get
  203. // a WM_PAINT message and try to use the freed memory before you can
  204. // clear it out or have the window destroyed by the dialog manager.
  205. //
  206. // Arguments: LPBMPDATA pBmpData - Ptr to the BmpData to be released
  207. //
  208. // Returns: Nothing
  209. //
  210. // History: nickball Created 3/27/98
  211. //
  212. //+----------------------------------------------------------------------------
  213. void ReleaseBitmapData(LPBMPDATA pBmpData)
  214. {
  215. MYDBGASSERT(pBmpData);
  216. if (NULL == pBmpData)
  217. {
  218. return;
  219. }
  220. if (pBmpData->hDIBitmap)
  221. {
  222. DeleteObject(pBmpData->hDIBitmap);
  223. pBmpData->hDIBitmap = NULL;
  224. }
  225. if (pBmpData->hDDBitmap)
  226. {
  227. DeleteObject(pBmpData->hDDBitmap);
  228. pBmpData->hDDBitmap = NULL;
  229. }
  230. if (pBmpData->pBmi)
  231. {
  232. CmFree(pBmpData->pBmi);
  233. pBmpData->pBmi = NULL;
  234. }
  235. }
  236. //+----------------------------------------------------------------------------
  237. //
  238. // Function: CreateBitmapData
  239. //
  240. // Synopsis: Fills a BMPDATA struct with all data necessary to display a bitmap.
  241. //
  242. // Arguments: HBITMAP hBmp - Handle of the source bitmap
  243. // LPBMPDATA lpBmpData - Ptr to the BmpData struct to be filled
  244. // HWND hwnd - The hwnd that the bitmap will be displayed in.
  245. // BOOL fCustomPalette - Indicates that the DDB should be created with a palette specific to the bitmap.
  246. //
  247. // Returns: BOOL - TRUE on succes
  248. //
  249. // History: nickball Created 3/27/98
  250. //
  251. //+----------------------------------------------------------------------------
  252. BOOL CreateBitmapData(HBITMAP hDIBmp,
  253. LPBMPDATA lpBmpData,
  254. HWND hwnd,
  255. BOOL fCustomPalette)
  256. {
  257. MYDBGASSERT(hDIBmp);
  258. MYDBGASSERT(lpBmpData);
  259. MYDBGASSERT(lpBmpData->phMasterPalette);
  260. if (NULL == hDIBmp || NULL == lpBmpData)
  261. {
  262. return NULL;
  263. }
  264. //
  265. // Params look good, get busy
  266. //
  267. HPALETTE hPaletteNew = NULL;
  268. LPBITMAPINFO pBmi = NULL;
  269. HBITMAP hDDBmp = NULL;
  270. HDC hDC;
  271. int iRes = 0;
  272. //
  273. // If we already have a pBmi value, we will assume it is up to date, as
  274. // both it and the DIB do not change throughout the life of the BMP.
  275. // Note: If BmpData is not zero initialized, you will have problems.
  276. //
  277. if (lpBmpData->pBmi)
  278. {
  279. pBmi = lpBmpData->pBmi;
  280. }
  281. else
  282. {
  283. //
  284. // Use the bitmap handle to retrieve a BITMAPINFO ptr complete w/ data
  285. //
  286. pBmi = CmGetBitmapInfo(lpBmpData->hDIBitmap);
  287. if (NULL == pBmi)
  288. {
  289. return FALSE;
  290. }
  291. }
  292. //
  293. // we need a DC
  294. //
  295. hDC = GetDC(hwnd);
  296. if (!hDC)
  297. {
  298. CMTRACE(TEXT("MyCreateDDBitmap() GetDC() failed."));
  299. return FALSE;
  300. }
  301. //
  302. // If CM is localized so that it is RTL (Right to Left => arabic and Hebrew),
  303. // then we need to call SetLayout on the hDC from above. If we don't
  304. // set the layout back to LTR, the bitmap will show up as all black instead of as
  305. // an image.
  306. //
  307. HMODULE hLib = LoadLibrary(TEXT("gdi32.dll"));
  308. if (hLib)
  309. {
  310. #ifndef LAYOUT_RTL
  311. #define LAYOUT_RTL 0x00000001 // Right to left
  312. #endif
  313. DWORD dwLayout;
  314. typedef DWORD (WINAPI* pfnSetLayoutType)(HDC, DWORD);
  315. typedef DWORD (WINAPI* pfnGetLayoutType)(HDC);
  316. pfnSetLayoutType pfnSetLayout = (pfnSetLayoutType)GetProcAddress(hLib, "SetLayout");
  317. pfnGetLayoutType pfnGetLayout = (pfnGetLayoutType)GetProcAddress(hLib, "GetLayout");
  318. if (pfnSetLayout && pfnGetLayout)
  319. {
  320. DWORD dwLayout = pfnGetLayout(hDC);
  321. if (LAYOUT_RTL & dwLayout)
  322. {
  323. dwLayout ^= LAYOUT_RTL; // toggle LAYOUT_RTL off
  324. pfnSetLayout(hDC, dwLayout);
  325. CMTRACE(TEXT("CreateBitmapData -- Toggling off LAYOUT_RTL on the device context"));
  326. }
  327. }
  328. FreeLibrary(hLib);
  329. }
  330. //
  331. // If fCustomPalette is set then create a palette based on our bits
  332. // and realize it in the current DC.
  333. //
  334. if (fCustomPalette)
  335. {
  336. hPaletteNew = CmCreateDIBPalette(pBmi);
  337. if (hPaletteNew)
  338. {
  339. //
  340. // Select and realize the new palette so that the DDB is created with it below
  341. //
  342. HPALETTE hPalettePrev = SelectPalette(hDC,
  343. hPaletteNew, lpBmpData->bForceBackground); // FALSE == Foreground app behavior);
  344. // TRUE == Background app behavior);
  345. if (hPalettePrev)
  346. {
  347. iRes = RealizePalette(hDC);
  348. #ifdef DEBUG
  349. if (GDI_ERROR == iRes)
  350. {
  351. CMTRACE1(TEXT("MyCreateDDBitmap() RealizePalette() failed, GLE=%u."), GetLastError());
  352. }
  353. }
  354. else
  355. {
  356. CMTRACE1(TEXT("MyCreateDDBitmap() SelectPalette() failed, GLE=%u."), GetLastError());
  357. #endif
  358. }
  359. }
  360. }
  361. //
  362. // Determine number of color entries based upon color depth
  363. //
  364. int nNumColors = 0;
  365. if (pBmi->bmiHeader.biBitCount <= 8)
  366. {
  367. nNumColors = (1 << pBmi->bmiHeader.biBitCount);
  368. }
  369. //
  370. // Create the DDB from the bits
  371. //
  372. hDDBmp = CreateDIBitmap(hDC,
  373. &pBmi->bmiHeader,
  374. CBM_INIT,
  375. ((LPBYTE) pBmi) + sizeof(BITMAPINFOHEADER) + (nNumColors * sizeof(RGBQUAD)), //dib.dsBm.bmBits,
  376. pBmi,
  377. DIB_RGB_COLORS);
  378. #ifdef DEBUG
  379. if (!hDDBmp)
  380. {
  381. CMTRACE(TEXT("MyCreateDDBitmap() CreateDIBitmap() failed."));
  382. }
  383. #endif
  384. ReleaseDC(NULL, hDC);
  385. //
  386. // Fill in the bitmap data
  387. //
  388. if (hDDBmp)
  389. {
  390. lpBmpData->hDIBitmap = hDIBmp;
  391. lpBmpData->pBmi = pBmi;
  392. //
  393. // Delete existing DDB, if any
  394. //
  395. if (lpBmpData->hDDBitmap)
  396. {
  397. DeleteObject(lpBmpData->hDDBitmap);
  398. }
  399. lpBmpData->hDDBitmap = hDDBmp;
  400. if (hPaletteNew)
  401. {
  402. //
  403. // Delete existing Palette, if any
  404. //
  405. if (*lpBmpData->phMasterPalette)
  406. {
  407. DeleteObject(*lpBmpData->phMasterPalette);
  408. }
  409. *lpBmpData->phMasterPalette = hPaletteNew;
  410. }
  411. return TRUE;
  412. }
  413. //
  414. // Something went wrong, cleanup
  415. //
  416. CmFree(pBmi);
  417. return FALSE;
  418. }
  419. //
  420. // Bitmap window procedure
  421. //
  422. LRESULT CALLBACK BmpWndProc(HWND hwndBmp,
  423. UINT uMsg,
  424. WPARAM wParam,
  425. LPARAM lParam)
  426. {
  427. LPBMPDATA pBmpData = (LPBMPDATA) GetWindowLongU(hwndBmp,0);
  428. BOOL bRes;
  429. switch (uMsg)
  430. {
  431. case WM_CREATE:
  432. {
  433. return FALSE;
  434. }
  435. case WM_DESTROY:
  436. SetWindowLongU(hwndBmp,sizeof(LPBMPDATA),(LONG_PTR) NULL);
  437. break;
  438. case WM_PAINT:
  439. if (pBmpData && pBmpData->pBmi)
  440. {
  441. LPBITMAPINFO pBmi = pBmpData->pBmi;
  442. RECT rWnd;
  443. RECT rSrc = {0,0,(int)pBmpData->pBmi->bmiHeader.biWidth,
  444. (int)pBmpData->pBmi->bmiHeader.biHeight};
  445. PAINTSTRUCT ps;
  446. HDC hdcBmp;
  447. HBITMAP hbmpPrev;
  448. int iPrevStretchMode;
  449. //
  450. // Start painting
  451. //
  452. HDC hdc = BeginPaint(hwndBmp,&ps);
  453. if (hdc)
  454. {
  455. //
  456. // Select and realize our current palette in the current DC
  457. //
  458. //UnrealizeObject(*pBmpData->phMasterPalette);
  459. SelectPalette(hdc, *pBmpData->phMasterPalette, pBmpData->bForceBackground);
  460. RealizePalette(hdc);
  461. //
  462. // Create a compatible DC, we'll create the BMP here then BLT it to the real DC
  463. //
  464. hdcBmp = CreateCompatibleDC(hdc);
  465. if (hdcBmp)
  466. {
  467. //
  468. // Select and realize our current palette in the compatible DC
  469. //
  470. SelectPalette(hdcBmp, *pBmpData->phMasterPalette, pBmpData->bForceBackground);
  471. RealizePalette(hdcBmp);
  472. if (!hdcBmp)
  473. {
  474. CMTRACE(TEXT("BmpWndProc() CreateCompatibleDC() failed."));
  475. }
  476. if (!pBmpData->hDDBitmap)
  477. {
  478. CMTRACE(TEXT("BmpWndProc() - WM_PAINT - hDDBitmap is NULL."));
  479. }
  480. //
  481. // Select the bitmap into the compatible DC
  482. //
  483. hbmpPrev = (HBITMAP) SelectObject(hdcBmp,pBmpData->hDDBitmap);
  484. bRes = GetWindowRect(hwndBmp,&rWnd);
  485. if (!bRes)
  486. {
  487. CMTRACE1(TEXT("BmpWndProc() GetWindowRect() failed, GLE=%u."), GetLastError());
  488. }
  489. //
  490. // Now set the mode, and StretchBlt the bitmap from the compatible DC to the active DC
  491. //
  492. CMTRACE(TEXT("BmpWndProc() : Changing stretch mode"));
  493. iPrevStretchMode = SetStretchBltMode(hdc, STRETCH_DELETESCANS);
  494. bRes = StretchBlt(hdc,
  495. rWnd.left-rWnd.left,
  496. rWnd.top-rWnd.top,
  497. rWnd.right-rWnd.left,
  498. rWnd.bottom-rWnd.top,
  499. hdcBmp,
  500. rSrc.left-rSrc.left,
  501. rSrc.top-rSrc.top,
  502. rSrc.right-rSrc.left,
  503. rSrc.bottom-rSrc.top,
  504. SRCCOPY);
  505. if (!bRes)
  506. {
  507. CMTRACE1(TEXT("BmpWndProc() StretchBlt() failed, GLE=%u."), GetLastError());
  508. }
  509. //
  510. // Restore the mode in the active DC
  511. //
  512. CMTRACE(TEXT("BmpWndProc() Restoring stretch mode"));
  513. iPrevStretchMode = SetStretchBltMode(hdc, iPrevStretchMode);
  514. //
  515. // Restore the compatible DC and release it
  516. //
  517. SelectObject(hdcBmp,hbmpPrev);
  518. DeleteDC(hdcBmp);
  519. }
  520. else
  521. {
  522. CMTRACE1(TEXT("BmpWndProc() CreateCompatibleDC() failed, GLE=%u."), GetLastError());
  523. }
  524. bRes = EndPaint(hwndBmp,&ps);
  525. if (!bRes)
  526. {
  527. CMTRACE(TEXT("BmpWndProc() EndPaint() failed."));
  528. }
  529. }
  530. else
  531. {
  532. CMTRACE1(TEXT("BmpWndProc() BeginPaint() failed, GLE=%u."), GetLastError());
  533. }
  534. }
  535. break;
  536. case STM_SETIMAGE:
  537. if (wParam == IMAGE_BITMAP)
  538. {
  539. CMTRACE2(TEXT("STM_SETIMAGE: wParam=%u, lParam=%u"), wParam, lParam);
  540. //
  541. // lParam contains a handle to the bitmap data, store it in extra bytes
  542. //
  543. SetWindowLongU(hwndBmp,0, lParam); // pBmpData
  544. CMTRACE2(TEXT("SetWindowLongU called with hwndBmp = %u, lParam=%u"), hwndBmp, lParam);
  545. //
  546. // Force a repaint
  547. //
  548. bRes = InvalidateRect(hwndBmp,NULL,TRUE);
  549. CMTRACE2(TEXT("InvalidateRect called with hwndBmp = %u, lParam=%u"), hwndBmp, lParam);
  550. #ifdef DEBUG
  551. if (!bRes)
  552. {
  553. CMTRACE(TEXT("BmpWndProc() InvalidateRect() failed."));
  554. }
  555. #endif
  556. if (pBmpData && pBmpData->hDDBitmap)
  557. {
  558. return ((LRESULT) pBmpData->hDDBitmap);
  559. }
  560. else
  561. {
  562. return NULL;
  563. }
  564. }
  565. break;
  566. }
  567. return (DefWindowProcU(hwndBmp,uMsg,wParam,lParam));
  568. }
  569. //+---------------------------------------------------------------------------
  570. //
  571. // Function: QueryNewPalette
  572. //
  573. // Synopsis: Helper function to encapsulate handling of WM_QUERYNEWPALETTE
  574. //
  575. // Arguments: hwndDlg - Handle of the dialog receiving the message
  576. // lpBmpData - Struct containing handles for bmp to display
  577. // iBmpCtrl - Bitmap control ID
  578. //
  579. // Returns: Nothing
  580. //
  581. // History: a-nichb - Created - 7/14/97
  582. //
  583. //----------------------------------------------------------------------------
  584. void QueryNewPalette(LPBMPDATA lpBmpData, HWND hwndDlg, int iBmpCtrl)
  585. {
  586. MYDBGASSERT(lpBmpData);
  587. if (lpBmpData)
  588. {
  589. //
  590. // We just handle this as a standard palette change because we
  591. // want to ensure that we create a new DDB using a palette based
  592. // upon our bitmap.
  593. //
  594. PaletteChanged(lpBmpData, hwndDlg, iBmpCtrl);
  595. }
  596. }
  597. //+---------------------------------------------------------------------------
  598. //
  599. // Function: PaletteChanged
  600. //
  601. // Synopsis: Helper function to encapsulate handling of WM_PALETTECHANGED
  602. //
  603. // Arguments: hwndDlg - Handle of the dialog receiving the message
  604. // lpBmpData - Struct containing handles for bmp to display
  605. // iBmpCtrl - Bitmap control ID
  606. //
  607. // Returns: Nothing
  608. //
  609. // History: a-nichb - Created - 7/14/97
  610. //
  611. //----------------------------------------------------------------------------
  612. void PaletteChanged(LPBMPDATA lpBmpData, HWND hwndDlg, int iBmpCtrl)
  613. {
  614. MYDBGASSERT(lpBmpData);
  615. if (NULL == lpBmpData || NULL == lpBmpData->phMasterPalette)
  616. {
  617. return;
  618. }
  619. //
  620. // Unrealize the master palette if it exists
  621. //
  622. if (*lpBmpData->phMasterPalette)
  623. {
  624. UnrealizeObject(*lpBmpData->phMasterPalette);
  625. }
  626. //
  627. // Create a device dependent bitmap and appropriate palette
  628. //
  629. if (CreateBitmapData(lpBmpData->hDIBitmap, lpBmpData, hwndDlg, TRUE))
  630. {
  631. //
  632. // SetImage to update handles for painting and force draw
  633. //
  634. HBITMAP hbmpTmp = (HBITMAP) SendDlgItemMessageA(hwndDlg, iBmpCtrl, STM_SETIMAGE,
  635. IMAGE_BITMAP,(LPARAM) lpBmpData);
  636. #ifdef DEBUUG
  637. if (!hbmpTmp)
  638. {
  639. CMTRACE(TEXT("PaletteChanged().WM_PALETTECHANGED - STM_SETIMAGE returned NULL."));
  640. }
  641. #endif
  642. }
  643. }