Leaked source code of windows server 2003
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.

789 lines
23 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. typedef DWORD (WINAPI* pfnSetLayoutType)(HDC, DWORD);
  314. typedef DWORD (WINAPI* pfnGetLayoutType)(HDC);
  315. pfnSetLayoutType pfnSetLayout = (pfnSetLayoutType)GetProcAddress(hLib, "SetLayout");
  316. pfnGetLayoutType pfnGetLayout = (pfnGetLayoutType)GetProcAddress(hLib, "GetLayout");
  317. if (pfnSetLayout && pfnGetLayout)
  318. {
  319. DWORD dwLayout = pfnGetLayout(hDC);
  320. if (LAYOUT_RTL & dwLayout)
  321. {
  322. dwLayout ^= LAYOUT_RTL; // toggle LAYOUT_RTL off
  323. pfnSetLayout(hDC, dwLayout);
  324. CMTRACE(TEXT("CreateBitmapData -- Toggling off LAYOUT_RTL on the device context"));
  325. }
  326. }
  327. FreeLibrary(hLib);
  328. }
  329. //
  330. // If fCustomPalette is set then create a palette based on our bits
  331. // and realize it in the current DC.
  332. //
  333. if (fCustomPalette)
  334. {
  335. hPaletteNew = CmCreateDIBPalette(pBmi);
  336. if (hPaletteNew)
  337. {
  338. //
  339. // Select and realize the new palette so that the DDB is created with it below
  340. //
  341. HPALETTE hPalettePrev = SelectPalette(hDC,
  342. hPaletteNew, lpBmpData->bForceBackground); // FALSE == Foreground app behavior);
  343. // TRUE == Background app behavior);
  344. if (hPalettePrev)
  345. {
  346. iRes = RealizePalette(hDC);
  347. #ifdef DEBUG
  348. if (GDI_ERROR == iRes)
  349. {
  350. CMTRACE1(TEXT("MyCreateDDBitmap() RealizePalette() failed, GLE=%u."), GetLastError());
  351. }
  352. }
  353. else
  354. {
  355. CMTRACE1(TEXT("MyCreateDDBitmap() SelectPalette() failed, GLE=%u."), GetLastError());
  356. #endif
  357. }
  358. }
  359. }
  360. //
  361. // Determine number of color entries based upon color depth
  362. //
  363. int nNumColors = 0;
  364. if (pBmi->bmiHeader.biBitCount <= 8)
  365. {
  366. nNumColors = (1 << pBmi->bmiHeader.biBitCount);
  367. }
  368. //
  369. // Create the DDB from the bits
  370. //
  371. hDDBmp = CreateDIBitmap(hDC,
  372. &pBmi->bmiHeader,
  373. CBM_INIT,
  374. ((LPBYTE) pBmi) + sizeof(BITMAPINFOHEADER) + (nNumColors * sizeof(RGBQUAD)), //dib.dsBm.bmBits,
  375. pBmi,
  376. DIB_RGB_COLORS);
  377. #ifdef DEBUG
  378. if (!hDDBmp)
  379. {
  380. CMTRACE(TEXT("MyCreateDDBitmap() CreateDIBitmap() failed."));
  381. }
  382. #endif
  383. ReleaseDC(NULL, hDC);
  384. //
  385. // Fill in the bitmap data
  386. //
  387. if (hDDBmp)
  388. {
  389. lpBmpData->hDIBitmap = hDIBmp;
  390. lpBmpData->pBmi = pBmi;
  391. //
  392. // Delete existing DDB, if any
  393. //
  394. if (lpBmpData->hDDBitmap)
  395. {
  396. DeleteObject(lpBmpData->hDDBitmap);
  397. }
  398. lpBmpData->hDDBitmap = hDDBmp;
  399. if (hPaletteNew)
  400. {
  401. //
  402. // Delete existing Palette, if any
  403. //
  404. if (*lpBmpData->phMasterPalette)
  405. {
  406. DeleteObject(*lpBmpData->phMasterPalette);
  407. }
  408. *lpBmpData->phMasterPalette = hPaletteNew;
  409. }
  410. return TRUE;
  411. }
  412. //
  413. // Something went wrong, cleanup
  414. //
  415. CmFree(pBmi);
  416. return FALSE;
  417. }
  418. //
  419. // Bitmap window procedure
  420. //
  421. LRESULT CALLBACK BmpWndProc(HWND hwndBmp,
  422. UINT uMsg,
  423. WPARAM wParam,
  424. LPARAM lParam)
  425. {
  426. LPBMPDATA pBmpData = (LPBMPDATA) GetWindowLongU(hwndBmp,0);
  427. BOOL bRes;
  428. switch (uMsg)
  429. {
  430. case WM_CREATE:
  431. {
  432. return FALSE;
  433. }
  434. case WM_DESTROY:
  435. SetWindowLongU(hwndBmp,sizeof(LPBMPDATA),(LONG_PTR) NULL);
  436. break;
  437. case WM_PAINT:
  438. if (pBmpData && pBmpData->pBmi)
  439. {
  440. LPBITMAPINFO pBmi = pBmpData->pBmi;
  441. RECT rWnd;
  442. RECT rSrc = {0,0,(int)pBmpData->pBmi->bmiHeader.biWidth,
  443. (int)pBmpData->pBmi->bmiHeader.biHeight};
  444. PAINTSTRUCT ps;
  445. HDC hdcBmp;
  446. HBITMAP hbmpPrev;
  447. int iPrevStretchMode;
  448. //
  449. // Start painting
  450. //
  451. HDC hdc = BeginPaint(hwndBmp,&ps);
  452. if (hdc)
  453. {
  454. //
  455. // Select and realize our current palette in the current DC
  456. //
  457. //UnrealizeObject(*pBmpData->phMasterPalette);
  458. SelectPalette(hdc, *pBmpData->phMasterPalette, pBmpData->bForceBackground);
  459. RealizePalette(hdc);
  460. //
  461. // Create a compatible DC, we'll create the BMP here then BLT it to the real DC
  462. //
  463. hdcBmp = CreateCompatibleDC(hdc);
  464. if (hdcBmp)
  465. {
  466. //
  467. // Select and realize our current palette in the compatible DC
  468. //
  469. SelectPalette(hdcBmp, *pBmpData->phMasterPalette, pBmpData->bForceBackground);
  470. RealizePalette(hdcBmp);
  471. if (!hdcBmp)
  472. {
  473. CMTRACE(TEXT("BmpWndProc() CreateCompatibleDC() failed."));
  474. }
  475. if (!pBmpData->hDDBitmap)
  476. {
  477. CMTRACE(TEXT("BmpWndProc() - WM_PAINT - hDDBitmap is NULL."));
  478. }
  479. //
  480. // Select the bitmap into the compatible DC
  481. //
  482. hbmpPrev = (HBITMAP) SelectObject(hdcBmp,pBmpData->hDDBitmap);
  483. bRes = GetWindowRect(hwndBmp,&rWnd);
  484. if (!bRes)
  485. {
  486. CMTRACE1(TEXT("BmpWndProc() GetWindowRect() failed, GLE=%u."), GetLastError());
  487. }
  488. //
  489. // Now set the mode, and StretchBlt the bitmap from the compatible DC to the active DC
  490. //
  491. CMTRACE(TEXT("BmpWndProc() : Changing stretch mode"));
  492. iPrevStretchMode = SetStretchBltMode(hdc, STRETCH_DELETESCANS);
  493. bRes = StretchBlt(hdc,
  494. rWnd.left-rWnd.left,
  495. rWnd.top-rWnd.top,
  496. rWnd.right-rWnd.left,
  497. rWnd.bottom-rWnd.top,
  498. hdcBmp,
  499. rSrc.left-rSrc.left,
  500. rSrc.top-rSrc.top,
  501. rSrc.right-rSrc.left,
  502. rSrc.bottom-rSrc.top,
  503. SRCCOPY);
  504. if (!bRes)
  505. {
  506. CMTRACE1(TEXT("BmpWndProc() StretchBlt() failed, GLE=%u."), GetLastError());
  507. }
  508. //
  509. // Restore the mode in the active DC
  510. //
  511. CMTRACE(TEXT("BmpWndProc() Restoring stretch mode"));
  512. iPrevStretchMode = SetStretchBltMode(hdc, iPrevStretchMode);
  513. //
  514. // Restore the compatible DC and release it
  515. //
  516. SelectObject(hdcBmp,hbmpPrev);
  517. DeleteDC(hdcBmp);
  518. }
  519. else
  520. {
  521. CMTRACE1(TEXT("BmpWndProc() CreateCompatibleDC() failed, GLE=%u."), GetLastError());
  522. }
  523. bRes = EndPaint(hwndBmp,&ps);
  524. if (!bRes)
  525. {
  526. CMTRACE(TEXT("BmpWndProc() EndPaint() failed."));
  527. }
  528. }
  529. else
  530. {
  531. CMTRACE1(TEXT("BmpWndProc() BeginPaint() failed, GLE=%u."), GetLastError());
  532. }
  533. }
  534. break;
  535. case STM_SETIMAGE:
  536. if (wParam == IMAGE_BITMAP)
  537. {
  538. CMTRACE2(TEXT("STM_SETIMAGE: wParam=%u, lParam=%u"), wParam, lParam);
  539. //
  540. // lParam contains a handle to the bitmap data, store it in extra bytes
  541. //
  542. SetWindowLongU(hwndBmp,0, lParam); // pBmpData
  543. CMTRACE2(TEXT("SetWindowLongU called with hwndBmp = %u, lParam=%u"), hwndBmp, lParam);
  544. //
  545. // Force a repaint
  546. //
  547. bRes = InvalidateRect(hwndBmp,NULL,TRUE);
  548. CMTRACE2(TEXT("InvalidateRect called with hwndBmp = %u, lParam=%u"), hwndBmp, lParam);
  549. #ifdef DEBUG
  550. if (!bRes)
  551. {
  552. CMTRACE(TEXT("BmpWndProc() InvalidateRect() failed."));
  553. }
  554. #endif
  555. if (pBmpData && pBmpData->hDDBitmap)
  556. {
  557. return ((LRESULT) pBmpData->hDDBitmap);
  558. }
  559. else
  560. {
  561. return NULL;
  562. }
  563. }
  564. break;
  565. }
  566. return (DefWindowProcU(hwndBmp,uMsg,wParam,lParam));
  567. }
  568. //+---------------------------------------------------------------------------
  569. //
  570. // Function: QueryNewPalette
  571. //
  572. // Synopsis: Helper function to encapsulate handling of WM_QUERYNEWPALETTE
  573. //
  574. // Arguments: hwndDlg - Handle of the dialog receiving the message
  575. // lpBmpData - Struct containing handles for bmp to display
  576. // iBmpCtrl - Bitmap control ID
  577. //
  578. // Returns: Nothing
  579. //
  580. // History: a-nichb - Created - 7/14/97
  581. //
  582. //----------------------------------------------------------------------------
  583. void QueryNewPalette(LPBMPDATA lpBmpData, HWND hwndDlg, int iBmpCtrl)
  584. {
  585. MYDBGASSERT(lpBmpData);
  586. if (lpBmpData)
  587. {
  588. //
  589. // We just handle this as a standard palette change because we
  590. // want to ensure that we create a new DDB using a palette based
  591. // upon our bitmap.
  592. //
  593. PaletteChanged(lpBmpData, hwndDlg, iBmpCtrl);
  594. }
  595. }
  596. //+---------------------------------------------------------------------------
  597. //
  598. // Function: PaletteChanged
  599. //
  600. // Synopsis: Helper function to encapsulate handling of WM_PALETTECHANGED
  601. //
  602. // Arguments: hwndDlg - Handle of the dialog receiving the message
  603. // lpBmpData - Struct containing handles for bmp to display
  604. // iBmpCtrl - Bitmap control ID
  605. //
  606. // Returns: Nothing
  607. //
  608. // History: a-nichb - Created - 7/14/97
  609. //
  610. //----------------------------------------------------------------------------
  611. void PaletteChanged(LPBMPDATA lpBmpData, HWND hwndDlg, int iBmpCtrl)
  612. {
  613. MYDBGASSERT(lpBmpData);
  614. if (NULL == lpBmpData || NULL == lpBmpData->phMasterPalette)
  615. {
  616. return;
  617. }
  618. //
  619. // Unrealize the master palette if it exists
  620. //
  621. if (*lpBmpData->phMasterPalette)
  622. {
  623. UnrealizeObject(*lpBmpData->phMasterPalette);
  624. }
  625. //
  626. // Create a device dependent bitmap and appropriate palette
  627. //
  628. if (CreateBitmapData(lpBmpData->hDIBitmap, lpBmpData, hwndDlg, TRUE))
  629. {
  630. //
  631. // SetImage to update handles for painting and force draw
  632. //
  633. HBITMAP hbmpTmp = (HBITMAP) SendDlgItemMessageA(hwndDlg, iBmpCtrl, STM_SETIMAGE,
  634. IMAGE_BITMAP,(LPARAM) lpBmpData);
  635. #ifdef DEBUUG
  636. if (!hbmpTmp)
  637. {
  638. CMTRACE(TEXT("PaletteChanged().WM_PALETTECHANGED - STM_SETIMAGE returned NULL."));
  639. }
  640. #endif
  641. }
  642. }