This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  RichEdit Overlay
  Submitted by



This snippet demonstrates how to make a RichEdit control transparent -- so that the text draws over top of the contents of the parent window (or even a memory DC). Best of all, it should work all the way back to Win95 / NT 3.1 and only relies on the Win32 APIs.

The basic concept is to draw the contents of the control into a memory DC, then use BitBlt() techniques (or TransparentBlt() if available) to generate a mask and overlay the text directly over the target DC.



Obvious enhancements include preallocating the memory DC and mask, then imaging the text only when it changes.

The image shows the graphical output of the enclosed test application.

This code is hereby placed in the public domain.



Matt Slot, 8/2/00
fprefect@ambrosiasw.com
http://www.ambrosiasw.com/~fprefect/


Currently browsing [overlay.zip] (169,393 bytes) - [OVERLAY/OVERLAY.C] - (10,149 bytes)

/* File "OVERLAY.C" - Code to overlay a RichText control over a background    */
/* Code by Matt Slot <fprefect@ambrosiasw.com> and placed into public domain  */

#include <COMMCTRL.H> #include <RICHEDIT.H> #include <WINDOWSX.H> #include <WINDOWS.H>

/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* Preprocessor Definitions */

#define OVERLAY_CLASS "OVERLAY" #define PROGRAM_NAME "RichEdit Overlay" #define STRING "abcde fghij klmno pqrst uvwxyz 01234 56789 "

/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* Function Prototypes */

typedef BOOL WINAPI (*TransparentBltProc)(IN HDC,IN int,IN int,IN int, IN int,IN HDC,IN int,IN int,IN int,IN int,IN UINT);

BOOL RichEditOverlayHWND(HWND hwnd, HDC hdc, HWND hwndRich); BOOL RichEditOverlayHDC(HDC hdc, DWORD x, DWORD y, HWND hwndRich);

/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* Overlay the contents of a HWND with a RichEdit control (its child window) */

BOOL RichEditOverlayHWND(HWND hwnd, HDC hdc, HWND hwndRich) { POINT point = { 0, 0 };

/* Just get the window location from our parent window */ if (IsChild(hwnd, hwndRich)) MapWindowPoints(hwndRich, hwnd, &point, 1);

return(RichEditOverlayHDC(hdc, point.x, point.y, hwndRich)); } /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* Overlay the contents of the HDC at the given point with a RichEdit control */

BOOL RichEditOverlayHDC(HDC hdc, DWORD x, DWORD y, HWND hwndRich) { static TransparentBltProc gTransparentBltProc = NULL; static BOOL gTransparentBltFirst = TRUE; BOOL success = TRUE; HDC hdcSave = NULL; HDC hdcRich = NULL, hdcMask = NULL; HBITMAP hbmRich = NULL, hbmSaveRich = NULL; HBITMAP hbmMask = NULL, hbmSaveMask = NULL; COLORREF bkColor; DWORD bits, w, h; POINT point; RECT rect;

/* On our first call, we try to dynamically load TransparentBlt() */ if (gTransparentBltFirst) { HINSTANCE hModule = LoadLibrary("MSIMG32.DLL"); if (hModule) gTransparentBltProc = GetProcAddress(hModule, "TransparentBlt"); gTransparentBltFirst = FALSE; /* Don't bother trying again */ }

/* Establish our coordinates from the start. */ GetClientRect(hwndRich, &rect); w = rect.right - rect.left; h = rect.bottom - rect.top; /* Get the relevant characteristics of the source window */ hdcSave = GetDC(hwndRich); if (!hdcSave) { success = FALSE; goto CLEANUP; } bkColor = GetBkColor(hdcSave); bits = GetDeviceCaps(hdcSave, BITSPIXEL);

/* Create offscreen drawing contexts and bitmap for the pixels */ hdcRich = CreateCompatibleDC(hdcSave); if (!hdcRich) { success = FALSE; goto CLEANUP; } hbmRich = CreateBitmap(w, h, 1, bits, NULL); if (!hbmRich) { success = FALSE; goto CLEANUP; } hbmSaveRich = SelectBitmap(hdcRich, hbmRich);

/* Create offscreen drawing contexts and bitmap for the mask */ if (!gTransparentBltProc) { hdcMask = CreateCompatibleDC(hdcSave); if (!hdcMask) { success = FALSE; goto CLEANUP; } hbmMask = CreateBitmap(w, h, 1, 1, NULL); if (!hbmMask) { success = FALSE; goto CLEANUP; } hbmSaveMask = SelectBitmap(hdcMask, hbmMask); }

/* Draw the control into our offscreen drawing context */ SendMessage(hwndRich, WM_PRINT, (WPARAM) hdcRich, PRF_CLIENT | PRF_ERASEBKGND);

if (gTransparentBltProc) /* We'll gladly use it if it's available */ success = (*gTransparentBltProc)(hdc,x,y,w,h,hdcRich,0,0,w,h,bkColor); else { /* Otherwise use a mask and draw it manually */ BitBlt(hdcMask,0,0,w,h,hdcRich,0,0,SRCCOPY); BitBlt(hdc,x,y,w,h,hdcMask,0,0,SRCAND); BitBlt(hdcRich,0,0,w,h,hdcMask,0,0,0x00220326); /* SRCNOTAND */ success = BitBlt(hdc,x,y,w,h,hdcRich,0,0,SRCPAINT); }

CLEANUP:

/* Release all of our objects in order */ if (hbmSaveMask) SelectBitmap(hdcMask, hbmSaveMask); if (hbmMask) DeleteObject(hbmMask); if (hbmSaveRich) SelectBitmap(hdcRich, hbmSaveRich); if (hbmRich) DeleteObject(hbmRich); if (hdcSave) ReleaseDC(hwndRich, hdcSave);

return(success); }

/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* Private utility routines */

#define kFirstChildWindowID 10000

static BOOL CALLBACK CalcChildWindowProc(HWND hwnd, LPARAM param) { HMENU * child = (HMENU *) param;

if (*child == (HMENU) GetDlgCtrlID(hwnd)) *child = (HMENU) NULL; return((*child) ? TRUE : FALSE); } /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */

static HMENU CalcChildWindowID(HWND hwnd) { HMENU child; UINT i;

for(i=kFirstChildWindowID, child=(HMENU) NULL; !child; child = (HMENU) ++i) EnumChildWindows(hwnd, CalcChildWindowProc, (LPARAM) &child); return(child); } /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */

static LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT result = 0; HWND hwndRich; HDC hdc; PAINTSTRUCT ps; switch(msg) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps);

/* Grab the RichEdit handle from the parent window */ hwndRich = (HWND) GetWindowLong(hwnd, GWL_USERDATA); RichEditOverlayHWND(hwnd, hdc, hwndRich);

EndPaint(hwnd, &ps); result = 1; break;

case WM_DESTROY: PostQuitMessage(0); break; default: result = DefWindowProc(hwnd, msg, wParam, lParam); }

return(result); }

/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd = (HWND) NULL; HWND hwndRich = (HWND) NULL; MSG lpMsg; WNDCLASS wc; RECT rect; HDC hdc; UINT i, j; CHARFORMAT cf;

/* Create our class and use an interesting background brush */ if (!hPrev) { wc.lpszClassName = OVERLAY_CLASS; wc.hInstance = hInst; wc.lpfnWndProc = MyWndProc; wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION); wc.lpszMenuName = (char *) NULL; wc.hbrBackground = CreateHatchBrush(HS_BDIAGONAL, RGB(255,0,0)); wc.style = 0; wc.cbClsExtra = 0; wc.cbWndExtra = 0;

if (!RegisterClass(&wc)) return FALSE; }

/* Create the window */ hwnd = CreateWindow(OVERLAY_CLASS, PROGRAM_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, (HINSTANCE) hInst, (LPSTR) NULL);

/* Create the RichEdit control -- notice, we never make it visible! */ InitCommonControls(); LoadLibrary("RICHED32.DLL"); GetClientRect(hwnd, &rect); hwndRich = CreateWindowEx(0, "RICHEDIT", "", WS_CHILD | ES_LEFT | ES_SAVESEL | ES_MULTILINE | ES_AUTOVSCROLL, rect.left + 50, rect.top + 50, rect.right - rect.left - 100, rect.bottom - rect.top - 100, hwnd, CalcChildWindowID(hwnd), (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL); Edit_Enable(hwndRich, FALSE); hdc = GetDC(hwndRich); /* Fill the image with some interesting text, 1 run at a time */ ZeroMemory(&cf, sizeof(CHARFORMAT)); cf.cbSize = sizeof(CHARFORMAT); cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE; cf.dwEffects = 0; cf.yHeight = 120 / GetDeviceCaps(hdc, LOGPIXELSY); cf.yOffset = 0; cf.crTextColor = RGB(0,0,0); cf.bCharSet = ANSI_CHARSET; cf.bPitchAndFamily = DEFAULT_PITCH; strcpy(cf.szFaceName, "System"); for(i=0, j=sizeof(STRING)-sizeof(""); i<27; i++) { Edit_SetSel(hwndRich, j*i, j*i); Edit_ReplaceSel(hwndRich, STRING); Edit_SetSel(hwndRich, j*i, j*(i+1));

/* Format the text */ cf.crTextColor = RGB((i%3)*0x44,((i/3)%3)*0x44,((i/9)%3)*0x44); SendMessage(hwndRich, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf); } Edit_SetSel(hwndRich, 0, 0); ReleaseDC(hwndRich, hdc);

/* Store the handle to the child window so we can access it */ SetWindowLong(hwnd, GWL_USERDATA, (LONG) hwndRich);

/* Sit and spin */ ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&lpMsg, (HWND) NULL, 0, 0)) { TranslateMessage(&lpMsg); DispatchMessage(&lpMsg); } DestroyWindow(hwnd); return(lpMsg.wParam); }




The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.