Windows 透明绿边窗口

需求

在 Windows 上,一些视频会议软件进行屏幕分享的时候,分享的屏幕时会有一个绿色边框将其标记出来,方便分享人知道当前正在分享的是哪一个屏幕,这篇博客主要就介绍一下如何实现这么一个窗口。

我们要做到下面几个点

1、始终置顶窗口(WS_EX_TOPMOST)

2、透明并且可穿透(WS_EX_LAYERED | WS_EX_TRANSPARENT)

3、没有最大化、最小化等(WS_EX_TOOLWINDOW)

4、有绿边(使用 Gdiplus::SolidBrush)

具体实现

1、创建一个透明窗口,这里使用到的扩展属性是 WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND hWND, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_ERASEBKGND:
		return 0;
	case WM_CLOSE:
		DestroyWindow(hWND);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWND, msg, wParam, lParam);
	}
	return 0;
}

int main(void) {
	HINSTANCE hinstance = GetModuleHandle(0);
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hinstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "TransparentWindow";
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	if (!RegisterClassEx(&wc))
	{
		return NULL;
	}
	HWND hwnd = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, "TransparentWindow", "TransparentWindow", WS_POPUP | WS_VISIBLE, 0, 0, 1920, 1080, NULL, NULL, hinstance, NULL);
	if (!hwnd)
	{
		return NULL;
	}
	MSG msg = { 0 };
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

2、上面我们创建了一个大小为 1920 x 1080 的窗口,也就是我的屏幕大小,接下来需要给这个窗口带上绿边,这里我们填充 4 个矩形区域,可以先看下面的图

就像上面两张图片这样,假设绿边的宽度为 4,那么我们需要将

上方:{0,0,width,4}

下方:{0,height-4,width,4}

左方:{0,4,4,height-4}

右方:{width-4,4,4,height-4}

这四个区域填充为绿色,接下来我们填充区域

全部代码

#include <Windows.h>

extern "C" {
#include <gdiplus.h>
}

#pragma comment(lib, "Gdiplus.lib")

LRESULT CALLBACK WndProc(HWND hWND, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_ERASEBKGND:
		return 0;
	case WM_CLOSE:
		DestroyWindow(hWND);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWND, msg, wParam, lParam);
	}
	return 0;
}

void FillWindow(HWND hwnd) {
	RECT rect;
	GetClientRect(hwnd, &rect);
	int width = rect.right - rect.left;
	int height = rect.bottom - rect.top;
	int linesize = 4;

	HDC hdc = GetDC(hwnd);

	HDC mem_dc = ::CreateCompatibleDC(hdc);
	HBITMAP hbitmap = ::CreateCompatibleBitmap(hdc, width, height);
	HBITMAP old_hbitmap = (HBITMAP)::SelectObject(mem_dc, hbitmap);

	Gdiplus::Graphics graphics(mem_dc);
	graphics.Clear(Gdiplus::Color(255, 0, 0));
	Gdiplus::SolidBrush brush(Gdiplus::Color(0, 230, 0));

	graphics.FillRectangle(&brush, 0, 0, width, linesize);
	graphics.FillRectangle(&brush, 0, height - linesize, width, linesize);
	graphics.FillRectangle(&brush, 0, linesize, linesize, height-4);
	graphics.FillRectangle(&brush, width - linesize, linesize, linesize, height-4);

	BLENDFUNCTION bs = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
	tagPOINT pos{ 0,0 };
	tagPOINT dstPos = { rect.left, rect.top };
	tagSIZE  dstSize = { width, height };
	BOOL bRes = ::UpdateLayeredWindow(hwnd, hdc, &dstPos, &dstSize, graphics.GetHDC(), &pos, RGB(255, 0, 0), &bs, ULW_COLORKEY);

	graphics.ReleaseHDC(mem_dc);
	::SelectObject(mem_dc, old_hbitmap);
	::DeleteDC(mem_dc);
	::DeleteObject(hbitmap);
	ReleaseDC(hwnd, hdc);

	mem_dc = NULL;
	hbitmap = NULL;
	old_hbitmap = NULL;
}

int main(void) {
	SetProcessDPIAware();
	HINSTANCE hinstance = GetModuleHandle(0);
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hinstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "TransparentWindow";
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	if (!RegisterClassEx(&wc))
	{
		return NULL;
	}
	HWND hwnd = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, "TransparentWindow", "TransparentWindow", 
		WS_POPUP | WS_VISIBLE, 0, 0, 1920, 1080, NULL, NULL, hinstance, NULL);
	if (!hwnd)
	{
		return NULL;
	}
	Gdiplus::GdiplusStartupInput input;
	Gdiplus::GdiplusStartupOutput output;
	ULONG_PTR token;
	Gdiplus::Status status = GdiplusStartup(&token, &input, &output);
	
	FillWindow(hwnd);
	MSG msg = { 0 };
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	Gdiplus::GdiplusShutdown(token);
	return 0;
}

可以自己手动运行观察效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值