/* 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);
}
|