/* * RESIMAGE.CPP * * Implementation of the Results Image control for OLE 2.0 UI dialogs. * We need a separate control for dialogs in order to control the repaints * properly and to provide a clean message interface for the dialog * implementations. * * Copyright (c)1992 Microsoft Corporation, All Right Reserved */ #include "precomp.h" #include "resimage.h" #include "uiclass.h" OLEDBGDATA //Reference counter indicating how many times fResultImageInitialize has been //successfully called static UINT uRegistered = 0; //Bitmap and image dimensions for result images. static HBITMAP hBmpResults = NULL; static UINT cxBmpResult; static UINT cyBmpResult; /* * FResultImageInitialize * * Purpose: * Attempts to load result bitmaps for the current display driver * for use in OLE 2.0 UI dialogs. Also registers the ResultImage * control class. * * Parameters: * hInst HINSTANCE instance of the DLL. * * hPrevInst HINSTANCE of the previous instance. Used to * determine whether to register window classes or not. * * Return Value: * BOOL TRUE if all initialization succeeded, FALSE otherwise. */ #pragma code_seg(".text$initseg") BOOL FResultImageInitialize(HINSTANCE hInst, HINSTANCE hPrevInst) { int cx, iBmp; HDC hDC; BITMAP bm; WNDCLASS wc; /* * Determine the aspect ratio of the display we're currently * running on and load the appropriate bitmap into the global * hBmpResults (used from the ResultImage control only). * * By retrieving the logical Y extent of the display driver, you * only have limited possibilities: * LOGPIXELSY Display * ---------------------------------------- * 48 CGA (unsupported) * 72 EGA * 96 VGA * 120 8514/a (i.e. HiRes VGA) */ hDC=GetDC(NULL); if (NULL==hDC) return FALSE; cx=GetDeviceCaps(hDC, LOGPIXELSY); ReleaseDC(NULL, hDC); /* * Instead of single comparisons, check ranges instead, so in case * we get something funky, we'll act reasonable. */ if (72 >=cx) iBmp=IDB_RESULTSEGA; if (72 < cx && 120 > cx) iBmp=IDB_RESULTSVGA; if (120 <=cx) iBmp=IDB_RESULTSHIRESVGA; if (NULL == hBmpResults) { hBmpResults=LoadBitmap(hInst, MAKEINTRESOURCE(iBmp)); if (NULL==hBmpResults) { //On error, fail loading the DLL OleDbgOut1(TEXT("FResultImageInitialize: Failed LoadBitmap.\r\n")); return FALSE; } OleDbgOut4(TEXT("FResultImageInitialize: Loaded hBmpResults\r\n")); // Now that we have the bitmap, calculate image dimensions GetObject(hBmpResults, sizeof(BITMAP), &bm); cxBmpResult = bm.bmWidth/CIMAGESX; cyBmpResult = bm.bmHeight; } // Only register class if we're the first instance if (hPrevInst) uRegistered++; else { // Static flag fRegistered guards against calling this function more // than once in the same instance if (0 == uRegistered) { wc.lpfnWndProc =ResultImageWndProc; wc.cbClsExtra =0; wc.cbWndExtra =CBRESULTIMAGEWNDEXTRA; wc.hInstance =hInst; wc.hIcon =NULL; wc.hCursor =LoadCursor(NULL, IDC_ARROW); wc.hbrBackground =NULL; wc.lpszMenuName =NULL; wc.style =CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; wc.lpszClassName = TEXT(SZCLASSRESULTIMAGE1); uRegistered = RegisterClass(&wc) ? 1 : 0; wc.lpszClassName = TEXT(SZCLASSRESULTIMAGE2); uRegistered = RegisterClass(&wc) ? 1 : 0; wc.lpszClassName = TEXT(SZCLASSRESULTIMAGE3); uRegistered = RegisterClass(&wc) ? 1 : 0; } else uRegistered++; } return (uRegistered > 0); } #pragma code_seg() /* * ResultImageUninitialize * * Purpose: * Cleans up anything done in FResultImageInitialize, such as freeing * the bitmaps. Call from WEP. * * Parameters: * None * * Return Value: * None */ void ResultImageUninitialize(void) { --uRegistered; if (0 == uRegistered) { if (NULL != hBmpResults) { DeleteObject(hBmpResults); hBmpResults = NULL; } } } /* * ResultImageWndProc * * Purpose: * Window Procedure for the ResultImage custom control. Only handles * WM_CREATE, WM_PAINT, and private messages to manipulate the bitmap. * * Parameters: * Standard * * Return Value: * Standard */ LONG CALLBACK ResultImageWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { UINT iBmp; PAINTSTRUCT ps; HDC hDC; //Handle standard Windows messages. switch (iMsg) { case WM_CREATE: SetWindowWord(hWnd, RIWW_IMAGEINDEX, RESULTIMAGE_NONE); return 0L; case WM_PAINT: iBmp = GetWindowWord(hWnd, RIWW_IMAGEINDEX); hDC = BeginPaint(hWnd, &ps); RECT rc; UINT x, y; HDC hDCDlg; HBRUSH hBr; LOGBRUSH lb; HWND hDlg; /* * Our job before using TransparentBlt is to figure out * where to position the result image. We place it centered * on this control, so get our rect's center and subtract * half of the image dimensions. */ GetClientRect(hWnd, &rc); x = (rc.right+rc.left-cxBmpResult)/2; y = (rc.bottom+rc.top-cyBmpResult)/2; // Get the backgroup color the dialog is using. hDlg=GetParent(hWnd); hDCDlg=GetDC(hDlg); hBr = (HBRUSH)SendMessage(hDlg, WM_CTLCOLORDLG, (WPARAM)hDCDlg, (LPARAM)hDlg); ReleaseDC(hDlg, hDCDlg); GetObject(hBr, sizeof(LOGBRUSH), &lb); SetBkColor(hDC, lb.lbColor); if (RESULTIMAGE_NONE != iBmp) { TransparentBlt(hDC, x, y, hBmpResults, iBmp*cxBmpResult, 0, cxBmpResult, cyBmpResult, RGBTRANSPARENT); } else { FillRect(hDC, &rc, hBr); } EndPaint(hWnd, &ps); break; case RIM_IMAGESET: // wParam contains the new index. iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX); // Validate the index before changing it and repainting if (RESULTIMAGE_NONE==wParam || ((RESULTIMAGE_MIN <= wParam) && (RESULTIMAGE_MAX >= wParam))) { SetWindowWord(hWnd, RIWW_IMAGEINDEX, (WORD)wParam); InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); } // Return the previous index. return iBmp; case RIM_IMAGEGET: // Return the current index. iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX); return (LONG)iBmp; default: return DefWindowProc(hWnd, iMsg, wParam, lParam); } return 0L; } /* * TransparentBlt * * Purpose: * Given a DC, a bitmap, and a color to assume as transparent in that * bitmap, BitBlts the bitmap to the DC letting the existing background * show in place of the transparent color. * * Parameters: * hDC HDC on which to draw. * x, y UINT location at which to draw the bitmap * hBmp HBITMIP to draw from * xOrg, yOrg UINT coordinates from which to draw the bitamp * cx, cy UINT dimensions of the bitmap to Blt. * cr COLORREF to consider as transparent. * * Return Value: * None */ void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, UINT xOrg, UINT yOrg, UINT cx, UINT cy, COLORREF cr) { HDC hDCSrc, hDCMid, hMemDC; HBITMAP hBmpMono, hBmpT; HBRUSH hBr, hBrT; COLORREF crBack, crText; if (NULL == hBmp) return; // Get three intermediate DC's hDCSrc = CreateCompatibleDC(hDC); hDCMid = CreateCompatibleDC(hDC); hMemDC = CreateCompatibleDC(hDC); SelectObject(hDCSrc, hBmp); // Create a monochrome bitmap for masking hBmpMono=CreateCompatibleBitmap(hDCMid, cx, cy); SelectObject(hDCMid, hBmpMono); // Create a middle bitmap hBmpT=CreateCompatibleBitmap(hDC, cx, cy); SelectObject(hMemDC, hBmpT); // Create a monochrome mask where we have 0's in the image, 1's elsewhere. crBack=SetBkColor(hDCSrc, cr); BitBlt(hDCMid, 0, 0, cx, cy, hDCSrc, xOrg, yOrg, SRCCOPY); SetBkColor(hDCSrc, crBack); // Put the unmodified image in the temporary bitmap BitBlt(hMemDC, 0, 0, cx, cy, hDCSrc, xOrg, yOrg, SRCCOPY); // Create an select a brush of the background color hBr = CreateSolidBrush(GetBkColor(hDC)); hBrT = (HBRUSH)SelectObject(hMemDC, hBr); // Force conversion of the monochrome to stay black and white. crText=SetTextColor(hMemDC, 0L); crBack=SetBkColor(hMemDC, RGB(255, 255, 255)); /* * Where the monochrome mask is 1, Blt the brush; where the mono mask * is 0, leave the destination untouches. This results in painting * around the image with the background brush. We do this first * in the temporary bitmap, then put the whole thing to the screen. */ BitBlt(hMemDC, 0, 0, cx, cy, hDCMid, 0, 0, ROP_DSPDxax); BitBlt(hDC, x, y, cx, cy, hMemDC, 0, 0, SRCCOPY); SetTextColor(hMemDC, crText); SetBkColor(hMemDC, crBack); SelectObject(hMemDC, hBrT); DeleteObject(hBr); DeleteDC(hMemDC); DeleteDC(hDCSrc); DeleteDC(hDCMid); DeleteObject(hBmpT); DeleteObject(hBmpMono); }