Reputation: 2822
There are several ways to do this using .NET (take this for instance), yet I wasn't able to reproduce the same thing using only C++ win32.
My approach was to use WS_EX_LAYERED
and then SetLayeredWindowAttributes
to have some control over the opacity, but I read more and I found out that WS_EX_TRANSPARENT
is 'better'- it allows click-through.
However, using
hWnd = CreateWindowEx(WS_EX_TRANSPARENT, fooName, fooName, WS_OVERLAPPEDWINDOW | WS_POPUP | WS_CLIPSIBLINGS, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
doesn't seem to do the trick. There is also another thing: once I get the click-through window working, can I use
PostMessage(hWnd, WM_LBUTTONUP, 0, MAKELPARAM(GET_X_LPARAM(lParam) ,GET_Y_LPARAM(lParam)));
to block the dragging state from passing through?
Note: the dragging state is produced using a touchpad device.
Upvotes: 10
Views: 10999
Reputation: 6271
I have been lately working on creating windows with transparency and click-through properties and I just tried this:
HWND hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TRANSPARENT, cName, wTitle, NULL, 0, 0, 640, 480, NULL, 0, GetModuleHandle(NULL), 0);
You can't close it, minimize it, drag it, etc - every click you make goes straight through as if it didn't exist. Then just change transparency using:
SetLayeredWindowAttributes(hWnd, 0, 100, LWA_ALPHA);
It achieves everything that in your question, if I understood it correctly.
Your approach might have not worked because WS_EX_LAYERED
must be defined if you use WS_EX_TRANSPARENT
.
Upvotes: 6
Reputation: 2822
The click-through part:
Indeed, WS_EX_TRANSPARENT
by itself is a big lie; so I used WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST
instead.
I have control over the opacity using SetLayeredWindowAttributes(hWnd, 0, (255 * opacity) / 100, LWA_ALPHA);
(quite unorthodox, but it works) and I also use
SetCapture(hWnd);
ShowCursor(false);
to grab the mouse focus as the top level window doesn't let go and hides the cursor.
I also tried to force the focus on the window adding WM_NCACTIVATE
and WM_ACTIVEAPP
:
case WM_MOUSEMOVE:
fprintf(stdout, "Mouse move [%d][%d]\n", GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
SetForegroundWindow(hWnd);
break;
case WM_LBUTTONDOWN:
printf("Mouse click\n");
SetForegroundWindow(hWnd);
break;
case WM_NCACTIVATE:
return false;
case WM_ACTIVATEAPP:
wActive = (bool)wParam;
if(wActive == false)
return 0;
else
return DefWindowProc(hWnd, message, wParam, lParam);
The dragging part:
In my particular case I wanted to 'poke' the window underneath (child window) without losing focus; unfortunately, any mouse click event will change the focus to that child window - a solution would be to:
SetTimer
, WM_TIMER
) and check whether your application lost focus or notWM_KILLFOCUS
message with a WM_SETFOCUS
messageUpvotes: 6