//
// Zhadum.cpp
//
// Copyright (c) 2001-2002 Mark H. P. Lord. All rights reserved.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the author(s) be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include "stdafx.h"
#include <wingdi.h>
#include "Zhadum.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
// Disable warning of conversion from LONG to x * (a Win64 portability warning
// given by VC7)
#pragma warning(disable:4312)
#pragma warning(disable:4311)
const char *dollarIdZhadum = "$Id: Zhadum.cpp,v 1.4 2002/10/21 23:31:52 mark Exp $";
//
// Win32 Defines
//
#define WS_EX_LAYERED 0x00080000
#define LWA_COLORKEY 0x00000001
#define LWA_ALPHA 0x00000002
#define ULW_COLORKEY 0x00000001
#define ULW_ALPHA 0x00000002
#define ULW_OPAQUE 0x00000004
#define AC_SRC_OVER 0x00
#define AC_SRC_ALPHA 0x01
//
// Helpers
//
#define countof(x) (sizeof (x) / sizeof ((x)[0]))
#define minimum(a, b) ((a) < (b) ? (a) : (b))
#define maximum(a, b) ((a) > (b) ? (a) : (b))
#ifndef _WIN64
#define GetZhadumShadowDataFromHWnd(hwnd) (ZhadumShadowData *) GetWindowLong (hwnd, 0)
#define SetZhadumShadowDataForHWnd(hwnd, data) SetWindowLong (hwnd, 0, (LONG) data)
#else
#define GetZhadumShadowDataFromHWnd(hwnd) (ZhadumShadowData *) GetWindowLongPtr (hwnd, 0)
#define SetZhadumShadowDataForHWnd(hwnd, data) SetWindowLongPtr (hwnd, 0, (LONG_PTR) data)
#endif
#define is_atom(p) (((size_t) (p) & (~0xffff)) == 0)
//
// Z'Ha'Dum
//
// Types
struct ZhadumShadowData {
HBITMAP bmp;
bool vertical;
int alpha;
};
typedef DWORD uint32;
typedef BYTE byte;
typedef BOOL (__stdcall *ZhadumSetLayeredWindowAttributesType) (HWND, COLORREF, BYTE, DWORD);
typedef BOOL (__stdcall *ZhadumUpdateLayeredWindowType) (HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD);
// Constants
#define ZHADUM_WM_SETALPHA (WM_USER + 1)
#define ZHADUM_WM_SETVERTICAL (WM_USER + 2)
#define MAX_ZHADUM_WNDS 128
#define MAX_ZHADUM_EXCLUSIONS 128
#if 1
// Normal shadow size
#define X_INDENT 2
#define Y_INDENT 5
#define X_SIZE 7
#define Y_SIZE 7
#define MAX_ALPHA 100
#define MIN_ALPHA 0
#else
// Chunkier shadows
#define X_INDENT 4
#define Y_INDENT 7
#define X_SIZE 14
#define Y_SIZE 14
#define MAX_ALPHA 100
#define MIN_ALPHA 0
#endif
static TCHAR zhadumShadowWndClassName[] = TEXT ("ZhadumShadow");
// Globals
static HINSTANCE zhadumHInst;
static HHOOK zhadumHook = NULL;
struct ZhadumWindowInfo {
HWND hwnd;
RECT rect;
BOOL visible;
HWND shadows[2];
};
static ZhadumWindowInfo zhadumWindows[MAX_ZHADUM_WNDS];
static int zhadumWindowCount = 0;
static BOOL zhadumRegisteredShadowClass = FALSE;
static ZhadumSetLayeredWindowAttributesType zhadumSetLayeredWindowAttributes;
static ZhadumUpdateLayeredWindowType zhadumUpdateLayeredWindow;
enum ZhadumExclusionType {
ZhadumExclusionType_Window,
ZhadumExclusionType_Class,
ZhadumExclusionType_Atom,
};
struct ZhadumExclusion {
ZhadumExclusionType type;
union {
HWND hwnd;
TCHAR *className;
LPCTSTR atom;
} u;
};
static ZhadumExclusion zhadumExclusions[MAX_ZHADUM_EXCLUSIONS];
static int zhadumExclusionCount = 0;
//
// Local Functions
//
static BOOL ZhadumInitialise () {
HMODULE hmodule = GetModuleHandle (TEXT ("user32.dll"));
if (zhadumSetLayeredWindowAttributes && zhadumUpdateLayeredWindow) {
return TRUE;
}
zhadumSetLayeredWindowAttributes =
(ZhadumSetLayeredWindowAttributesType) GetProcAddress (hmodule, "SetLayeredWindowAttributes");
zhadumUpdateLayeredWindow =
(ZhadumUpdateLayeredWindowType) GetProcAddress (hmodule, "UpdateLayeredWindow");
if (! zhadumSetLayeredWindowAttributes || ! zhadumUpdateLayeredWindow) {
return FALSE;
}
return TRUE;
}
static void FillU32 (uint32 *out, uint32 value, int count) {
while (count--) {
*out++ = value;
}
}
static void FillPixels (uint32 *surf, int surfw, int surfh,
int left, int top, int right, int bottom, uint32 value) {
int w = right - left;
assert (! (left < 0 || top < 0 || right > surfw || bottom > surfh || bottom < top || right < left));
if (left < 0 || top < 0 || right > surfw || bottom > surfh || bottom < top || right < left) {
return;
}
for (; top != bottom; ++top) {
FillU32 (&surf[left + top * surfw], value, w);
}
}
static void FillRoundedCorner (uint32 *surf, int cx, int cy, int cornersize,
int left, int top, int right, int bottom, int dx, int dy) {
if (left < 0 || top < 0 || right > cx || bottom > cy || bottom < top || right < left)
return;
uint32 *rowptr = surf + top;
int cyminus1 = cornersize - 1;
//double scale = sqrt (cyminus1*cyminus1 + cyminus1*cyminus1);
double scale = cyminus1;
int njinit = dx < 0 ? (cornersize-1) : 0;
int ni = dy < 0 ? (cornersize-1) : 0;
int nj;
int i, j;
uint32 value;
for (i = top; i != bottom; ++i, rowptr += cx, ni += dy) {
for (j = left, nj = njinit; j != right; ++j, nj += dx) {
value = (uint32)floor (sqrt (ni*ni + nj*nj) * 255.0 / scale);
if (value > 255)
rowptr[j] = 0;
else {
value = 255-value;
value = ((value * (MAX_ALPHA-MIN_ALPHA+1)) >> 8) + MIN_ALPHA;
rowptr[j] = value << 24;
}
}
}
}
static void ZhadumShadowWindowUpdate (HWND hwnd) {
ZhadumShadowData *data = GetZhadumShadowDataFromHWnd (hwnd);
if (data->bmp) {
DeleteObject (data->bmp);
}
SIZE sz;
RECT rwnd;
GetWindowRect (hwnd, &rwnd);
sz.cx = rwnd.right - rwnd.left;
sz.cy = rwnd.bottom - rwnd.top;
if (! sz.cx || ! sz.cy) {
data->bmp = NULL;
return;
}
// We have to use a DIB section for 16-bit video mode support
BITMAPINFO bitmapInfo;
bitmapInfo.bmiHeader.biSize = sizeof (bitmapInfo.bmiHeader);
bitmapInfo.bmiHeader.biWidth = sz.cx;
bitmapInfo.bmiHeader.biHeight = -(int)sz.cy;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = sz.cx * sz.cy * 4;
bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
bitmapInfo.bmiHeader.biClrUsed = 0;
bitmapInfo.bmiHeader.biClrImportant = 0;
HDC hdc = GetDC (NULL);
VOID *bits;
data->bmp = CreateDIBSection (hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
ReleaseDC (NULL, hdc);
if (! data->bmp) {
//ZhadumDisplayWinError (GetLastError (), TEXT ("CreateBitmap"));
return;
}
int area = sz.cx * sz.cy;
int i;
uint32 *pixels = (uint32 *) bits;
uint32 *pixelptr = pixels;
if (! data->vertical) {
FillRoundedCorner (pixelptr, sz.cx, sz.cy, sz.cy,
0, 0, sz.cy, sz.cy, -1, 1);
uint32 *rowptr = pixelptr;
int maxx = minimum (sz.cx, sz.cy);
for (i = 0; i != sz.cy; ++i, rowptr += sz.cx) {
FillPixels (pixelptr, sz.cx, sz.cy, maxx, i, sz.cx, i + 1, rowptr[maxx-1]);
}
FillRoundedCorner (pixelptr, sz.cx, sz.cy, sz.cy,
sz.cx - sz.cy, 0, sz.cx, sz.cy, 1, 1);
}
else {
FillRoundedCorner (pixelptr, sz.cx, sz.cy, sz.cx,
0, 0, sz.cx, sz.cx, 1, -1);
int maxy = minimum (sz.cx, sz.cy);
uint32 *rowptr = pixelptr + (maxy - 1) * sz.cx;
for (i = 0; i != sz.cx; ++i) {
FillPixels (pixelptr, sz.cx, sz.cy, i, maxy, i + 1, sz.cy, rowptr[i]);
}
}
if (data->alpha != 255) {
int alpha;
if (data->alpha == 0) {
alpha = 1;
}
else {
alpha = data->alpha;
}
byte *alphaptr = (byte *) pixels;
byte *alphaend = alphaptr + area * 4;
alphaptr += 3;
alphaend += 3;
for (; alphaptr != alphaend; alphaptr += 4) {
*alphaptr = (byte) ((int) (*alphaptr) * alpha / 255);
}
}
hdc = ::GetDC (NULL);
HDC hdctemp = CreateCompatibleDC (hdc);
SetLayout (hdctemp, LAYOUT_BITMAPORIENTATIONPRESERVED);
HGDIOBJ oldbmp = SelectObject (hdctemp, data->bmp);
POINT ptwnd;
ptwnd.x = rwnd.left;
ptwnd.y = rwnd.top;
POINT ptzero = { 0, 0 };
BLENDFUNCTION blend;
memset (&blend, 0, sizeof (blend));
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
if (zhadumUpdateLayeredWindow) {
(*zhadumUpdateLayeredWindow) (hwnd, hdc, &ptwnd, &sz, hdctemp, &ptzero, 0, &blend, ULW_ALPHA);
}
SelectObject (hdctemp, oldbmp);
DeleteDC (hdctemp);
::ReleaseDC (NULL, hdc);
}
// Our window procedure for our shadow windows
static LRESULT CALLBACK ZhadumShadowWndProc (HWND hwnd, UINT msg, WPARAM wparam,
LPARAM lparam) {
ZhadumShadowData *data;
switch (msg) {
case WM_CREATE: {
data = (ZhadumShadowData *) calloc (sizeof (ZhadumShadowData), 1);
if (! data) {
return -1;
}
SetZhadumShadowDataForHWnd (hwnd, data);
data->alpha = 255;
data->vertical = false;
break;
}
case WM_DESTROY: {
data = GetZhadumShadowDataFromHWnd (hwnd);
if (data) {
if (data->bmp) {
DeleteObject (data->bmp);
}
free (data);
}
break;
}
case WM_PAINT: {
ValidateRect (hwnd, NULL);
return 0;
}
case WM_NCHITTEST: {
return HTTRANSPARENT;
}
case WM_SIZE: {
ZhadumShadowWindowUpdate (hwnd);
break;
}
case ZHADUM_WM_SETVERTICAL: {
ZhadumShadowData *data = GetZhadumShadowDataFromHWnd (hwnd);
data->vertical = wparam != 0;
return 0;
}
case ZHADUM_WM_SETALPHA: {
ZhadumShadowData *data = GetZhadumShadowDataFromHWnd (hwnd);
int alpha = (int) wparam;
if (alpha != data->alpha) {
data->alpha = alpha;
ZhadumShadowWindowUpdate (hwnd);
}
return 0;
}
}
return DefWindowProc (hwnd, msg, wparam, lparam);
}
// Register the shadow window's window class, if it's not already been done
static BOOL ZhadumRegisterShadowClass () {
if (! zhadumRegisteredShadowClass) {
WNDCLASSEX wc;
wc.cbSize = sizeof (wc);
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof (ZhadumShadowData *);
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = zhadumHInst;
wc.lpfnWndProc = (WNDPROC) ZhadumShadowWndProc;
wc.lpszClassName = zhadumShadowWndClassName;
wc.lpszMenuName = NULL;
wc.style = 0;
if (RegisterClassEx (&wc)) {
zhadumRegisteredShadowClass = TRUE;
}
return zhadumRegisteredShadowClass;
}
else {
return TRUE;
}
}
// Update the specified window's shadows. If isvisible is specified it should
// be zero if the window is being hidden or > zero if the window is being
// shown
static void ZhadumUpdateWindow (HWND hwnd, int isvisible = -1) {
ZhadumWindowInfo *p = zhadumWindows;
ZhadumWindowInfo *e = p + zhadumWindowCount;
for (; p != e; ++p) {
if (p->hwnd == hwnd) {
break;
}
}
if (p == e) {
// Window's not being shadowed, so quit
return;
}
int i;
if (isvisible >= 0) {
// "isvisible" was passed to us, so we received a WM_SHOWWINDOW or some
// other indication that the window's visibility is changing
if (! isvisible) {
// We should be invisible
if (p->visible) {
// We're currently visibile
p->visible = FALSE;
// Destroy the shadow windows
for (i = 0; i != 2; ++i) {
if (p->shadows[i]) {
DestroyWindow (p->shadows[i]);
}
}
memset (p->shadows, 0, sizeof (HWND) * 2);
return;
}
else {
// No problem, already invisible
return;
}
}
else {
// We should be visible
if (! p->visible) {
// We're not, so we're going to need the shadow window class
if (! ZhadumRegisterShadowClass ()) {
return;
}
// Update visible flag now
p->visible = TRUE;
// Make the shadow windows
for (i = 0; i != 2; ++i) {
p->shadows[i] = CreateWindowEx (WS_EX_LAYERED | WS_EX_TRANSPARENT,
zhadumShadowWndClassName, NULL,
WS_POPUP | WS_DISABLED,
0, 0, 0, 0, hwnd, NULL, zhadumHInst, NULL);
SendMessage (p->shadows[i], ZHADUM_WM_SETVERTICAL, i, 0);
ShowWindow (p->shadows[i], SW_SHOWNA);
}
// Reset the rectangle to force it to update as necessary
memset (&p->rect, 0, sizeof (p->rect));
}
}
}
// If we reach here then either our visibility state didn't change or we've
// just become visible
if (! p->visible) {
return;
}
// Get the window's current location
RECT rect;
GetWindowRect (hwnd, &rect);
// Compare the current rectangles to the rectangle the shadows were last set
// to.
if (p->rect.left == rect.left && p->rect.top == rect.top
&& p->rect.right == rect.right && p->rect.bottom == rect.bottom) {
// No change, quit now
return;
}
// Shadows need to follow the window
p->rect = rect;
SetWindowPos (p->shadows[0], NULL, rect.left+X_INDENT, rect.bottom,
rect.right - rect.left + X_SIZE - X_INDENT, Y_SIZE, SWP_NOZORDER | SWP_NOACTIVATE);
SetWindowPos (p->shadows[1], NULL, rect.right, rect.top+Y_INDENT, X_SIZE,
rect.bottom-rect.top-Y_INDENT, SWP_NOZORDER | SWP_NOACTIVATE);
}
// Add a window to the list of windows to be shadowed
static void ZhadumAddWindow (HWND hwnd) {
ZhadumWindowInfo *p = zhadumWindows;
ZhadumWindowInfo *e = p + zhadumWindowCount;
for (; p != e; ++p) {
if (p->hwnd == hwnd) {
return;
}
}
if (e != zhadumWindows + countof (zhadumWindows)) {
// There's room
memset (e, 0, sizeof (*e));
e->hwnd = hwnd;
++zhadumWindowCount;
}
}
// Remove a window from the list of windows to be shadowed
static void ZhadumRemoveWindow (HWND hwnd) {
ZhadumWindowInfo *p = zhadumWindows;
ZhadumWindowInfo *e = p + zhadumWindowCount;
for (; p != e; ++p) {
if (p->hwnd == hwnd) {
// Remove the shadows, if they exist
for (int i = 0; i != 2; ++i) {
if (p->shadows[i]) {
DestroyWindow (p->shadows[i]);
}
}
// Shrink the list
if (p + 1 < e) {
memmove (p, p + 1, (e - (p + 1)) * sizeof (ZhadumWindowInfo));
return;
}
--zhadumWindowCount;
}
}
}
// Should we shadow a window?
static BOOL ZhadumShouldShadow (HWND hwnd, LPCREATESTRUCT cs) {
// Child windows are a no no
if ((cs->style & (WS_POPUP | WS_CHILD | WS_OVERLAPPED)) == WS_CHILD) {
return FALSE;
}
// Check for us first
if (! is_atom (cs->lpszClass)) {
if (lstrcmp (cs->lpszClass, zhadumShadowWndClassName) == 0) {
return FALSE;
}
}
// Scan the exclusions
ZhadumExclusion *p = zhadumExclusions;
ZhadumExclusion *e = zhadumExclusions + zhadumExclusionCount;
for (; p != e; ++p) {
switch (p->type) {
case ZhadumExclusionType_Window:
if (hwnd == p->u.hwnd) {
return FALSE;
}
break;
case ZhadumExclusionType_Atom:
if (cs->lpszClass == p->u.atom) {
return FALSE;
}
break;
case ZhadumExclusionType_Class:
if (! is_atom (cs->lpszClass)
&& 0 == lstrcmp (cs->lpszClass, p->u.className)) {
return FALSE;
}
break;
}
}
return TRUE;
}
// Our hook procedure. We're only interested in certain messages.
static LRESULT CALLBACK ZhadumHookProc (int code, WPARAM wparam, LPARAM lparam) {
HWND hwnd;
switch (((CWPRETSTRUCT *) lparam)->message) {
case WM_CREATE: {
// Window being created. If it's suitable for shadowing (i.e.,
// it's not a child window and it's not disabled) then add it
// to the list of windows to shadow.
// We catch shadows this way because they're always disabled.
LPCREATESTRUCT cs = (LPCREATESTRUCT) ((CWPRETSTRUCT *) lparam)->lParam;
if (ZhadumShouldShadow (((CWPRETSTRUCT *) lparam)->hwnd, cs)) {
ZhadumAddWindow (((CWPRETSTRUCT *) lparam)->hwnd);
}
break;
}
case WM_DESTROY:
// A window is being destroyed. Remove it from the shadowed window
// list, if it's there.
ZhadumRemoveWindow (((CWPRETSTRUCT *) lparam)->hwnd);
break;
case WM_SIZE:
case WM_MOVE:
case WM_MOVING:
case WM_SIZING:
case WM_ACTIVATE:
// The window has moved or resized so we should adjust the shadows
hwnd = ((CWPRETSTRUCT *) lparam)->hwnd;
ZhadumUpdateWindow (hwnd,
(GetWindowLong (hwnd, GWL_STYLE) & WS_VISIBLE) ? 1 : 0);
break;
case WM_SHOWWINDOW:
// The window is being shown or hidden, update the shadows accordingly
ZhadumUpdateWindow (((CWPRETSTRUCT *) lparam)->hwnd,
((CWPRETSTRUCT *) lparam)->wParam ? 1 : 0);
break;
}
return CallNextHookEx (zhadumHook, code, wparam, lparam);
}
// Add an exclusion to the list
static BOOL ZhadumAddExclusion (const ZhadumExclusion *exclusion) {
if (zhadumExclusionCount == MAX_ZHADUM_EXCLUSIONS) {
return FALSE;
}
zhadumExclusions[zhadumExclusionCount++] = *exclusion;
return TRUE;
}
// Free a single ZhadumExclusion
static void ZhadumFreeExclusion (ZhadumExclusion *exclusion) {
if (exclusion->type == ZhadumExclusionType_Class) {
free (exclusion->u.className);
}
exclusion->type = ZhadumExclusionType_Window;
}
// Free all exclusions
static void ZhadumFreeExclusions () {
ZhadumExclusion *p = zhadumExclusions;
ZhadumExclusion *e = zhadumExclusions + zhadumExclusionCount;
for (; p != e; ++p) {
ZhadumFreeExclusion (p);
}
zhadumExclusionCount = 0;
}
//
// Global Functions
//
// Exclude the specified window from window shadows. Returns FALSE if there
// are too many exclusions in place.
BOOL WINAPI ZhadumExcludeWindow (HWND hwnd) {
ZhadumExclusion excl;
ZhadumRemoveWindow (hwnd);
excl.type = ZhadumExclusionType_Window;
excl.u.hwnd = hwnd;
return ZhadumAddExclusion (&excl);
}
// Remove the exclusion on the specified window. This won't create shadows
// but it will allow any future windows with the same HWND to have shadows.
// You no longer have to call this, it's handled internally.
void WINAPI ZhadumUnexcludeWindow (HWND hwnd) {
ZhadumExclusion *p = zhadumExclusions;
ZhadumExclusion *e = zhadumExclusions + zhadumExclusionCount;
for (; p != e; ++p) {
if (p->type == ZhadumExclusionType_Window
&& p->u.hwnd == hwnd) {
memmove (p, p + 1, (e - (p + 1)) * sizeof (ZhadumExclusion));
return;
}
}
}
// Exclude the specified WNDCLASS (can be an internal class, e.g. WC_DIALOG).
// Returns FALSE if there are too many exclusions in place.
BOOL WINAPI ZhadumExcludeClass (LPCTSTR classname) {
ZhadumExclusion excl;
if (! is_atom (classname)) {
excl.type = ZhadumExclusionType_Atom;
int size = (lstrlen (classname) + 1) * sizeof (TCHAR);
excl.u.className = (TCHAR *) malloc (size);
if (! excl.u.className) {
return FALSE;
}
memcpy (excl.u.className, classname, size);
if (! ZhadumAddExclusion (&excl)) {
free (excl.u.className);
return FALSE;
}
else {
return TRUE;
}
}
else {
excl.type = ZhadumExclusionType_Atom;
excl.u.atom = classname;
return ZhadumAddExclusion (&excl);
}
}
// Set the alpha of the shadows belonging to the specified window.
void WINAPI ZhadumSetWindowShadowAlpha (HWND hwnd, BYTE alpha) {
ZhadumWindowInfo *p = zhadumWindows;
ZhadumWindowInfo *e = p + zhadumWindowCount;
for (; p != e; ++p) {
if (p->hwnd == hwnd) {
for (int i = 0; i != 2; ++i) {
if (p->shadows[i]) {
SendMessage (p->shadows[i], ZHADUM_WM_SETALPHA, (WPARAM) alpha, 0);
}
}
}
}
}
// Begins automatically applying window shadows to our popup windows
BOOL WINAPI ZhadumBegin (HINSTANCE hinst) {
if (zhadumHook != NULL) {
// Hook already installed
return TRUE;
}
// Remember this
zhadumHInst = hinst;
// Make sure shadows are available
if (! ZhadumInitialise ()) {
return FALSE;
}
// Exclude menus
ZhadumExcludeClass ((LPCTSTR) 32768);
// Set a Windows CALLWNDPROCRECT hook, which will get called whenever
// a window procedure returns. We inspect the messages and work on the
// ones we're interested in.
zhadumHook = SetWindowsHookEx (WH_CALLWNDPROCRET, ZhadumHookProc, GetModuleHandle (NULL), GetCurrentThreadId ());
// Return boolean indicating success
return zhadumHook != NULL ? TRUE : FALSE;
}
// Stop auto-shadowing
void WINAPI ZhadumEnd () {
if (zhadumHook != NULL) {
UnhookWindowsHookEx (zhadumHook);
zhadumHook = NULL;
}
// Remove all the window entries from the list
ZhadumWindowInfo *p = zhadumWindows;
ZhadumWindowInfo *e = p + zhadumWindowCount;
zhadumWindowCount = 0;
for (; p != e; ++p) {
for (int i = 0; i != 2; ++i) {
if (p->shadows[i]) {
DestroyWindow (p->shadows[i]);
}
}
}
// Remove all the exclusions
ZhadumFreeExclusions ();
}
void WINAPI ZhadumDisplayWinError (DWORD err, LPCTSTR title) {
TCHAR buf[128];
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
0,
buf,
countof (buf),
NULL);
MessageBox (NULL, buf, title, MB_OK | MB_ICONSTOP);
}