windows 窗口全屏绘制,全程置顶,不可远程捕捉,不被预览影响,无标题无边框,所有屏幕全部绘制。
#include <windows.h>
#include <vector>
#include <string>
#include <chrono>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
// 显示器信息结构体
struct MonitorInfo {
HMONITOR hMonitor; // 显示器句柄
RECT rect; // 显示器位置和尺寸
};
// 窗口上下文结构体(每个窗口独立)
struct WindowContext {
HDC hdcMem = nullptr; // 内存设备上下文
HBITMAP hbmMem = nullptr; // 兼容位图
int width = 0; // 窗口宽度
int height = 0; // 窗口高度
int lastSecond = -1; // 上次刷新秒数(用于每秒更新)
bool isPrimary = false; // 标识是否主显示器
};
std::vector<MonitorInfo> g_monitorInfos; // 保存所有显示器信息
HWND g_hwndPrimary = nullptr; // 主显示器窗口句柄
// 显示器枚举回调函数
BOOL CALLBACK MonitorEnumProc(
HMONITOR hMonitor, // 当前显示器句柄
HDC hdcMonitor, // 显示器设备上下文(未使用)
LPRECT lprcMonitor, // 显示器区域
LPARAM dwData // 自定义数据(未使用)
) {
g_monitorInfos.push_back({ hMonitor, *lprcMonitor }); // 存储显示器信息
return TRUE; // 继续枚举
}
// 更新内存缓冲区的绘制内容
void UpdateBuffer(WindowContext& ctx, HWND hwnd) {
RECT rc;
GetClientRect(hwnd, &rc); // 获取窗口客户区尺寸
// 如果窗口尺寸变化则重建缓冲
if (ctx.width != rc.right || ctx.height != rc.bottom) {
// 释放旧资源
if (ctx.hdcMem) DeleteDC(ctx.hdcMem);
if (ctx.hbmMem) DeleteObject(ctx.hbmMem);
HDC hdc = GetDC(hwnd); // 获取窗口设备上下文
// 创建兼容内存DC
ctx.hdcMem = CreateCompatibleDC(hdc);
// 创建兼容位图
ctx.hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
SelectObject(ctx.hdcMem, ctx.hbmMem); // 选入内存DC
ReleaseDC(hwnd, hdc); // 释放原始DC
ctx.width = rc.right;
ctx.height = rc.bottom;
}
// 用深灰色填充背景
HBRUSH bgBrush = CreateSolidBrush(RGB(30, 30, 30));
FillRect(ctx.hdcMem, &rc, bgBrush);
DeleteObject(bgBrush);
// 获取当前时间
SYSTEMTIME st;
GetLocalTime(&st);
std::wstring timeStr = std::to_wstring(st.wHour) + L":"
+ (st.wMinute < 10 ? L"0" : L"") + std::to_wstring(st.wMinute) + L":"
+ (st.wSecond < 10 ? L"0" : L"") + std::to_wstring(st.wSecond);
// 设置文字透明背景
SetBkMode(ctx.hdcMem, TRANSPARENT);
// 主屏用红色文字,其他用黄色
SetTextColor(ctx.hdcMem, ctx.isPrimary ? RGB(255, 0, 0) : RGB(255, 255, 0));
// 创建字体
HFONT hFont = CreateFont(
48, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
HFONT hOldFont = (HFONT)SelectObject(ctx.hdcMem, hFont);
// 居中绘制时间文字
DrawText(ctx.hdcMem, timeStr.c_str(), -1, &rc,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// 恢复旧字体并删除新字体
SelectObject(ctx.hdcMem, hOldFont);
DeleteObject(hFont);
}
// 窗口过程函数
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
) {
// 从窗口附加数据中获取上下文
WindowContext* ctx = reinterpret_cast<WindowContext*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg) {
case WM_CREATE: {
// 创建窗口时初始化上下文
auto* newCtx = new WindowContext;
SetWindowLongPtr(hwnd, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(newCtx));
return 0;
}
case WM_ERASEBKGND: // 拦截背景擦除避免闪烁
return 1;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
if (ctx && ctx->hdcMem) {
// 将内存DC内容拷贝到屏幕
BitBlt(hdc, 0, 0, ctx->width, ctx->height,
ctx->hdcMem, 0, 0, SRCCOPY);
}
EndPaint(hwnd, &ps);
return 0;
}
case WM_TIMER: { // 定时器消息(每秒更新)
if (!ctx) return 0;
SYSTEMTIME st;
GetLocalTime(&st);
if (st.wSecond != ctx->lastSecond) { // 秒变化时更新
ctx->lastSecond = st.wSecond;
UpdateBuffer(*ctx, hwnd); // 重绘缓冲区
InvalidateRect(hwnd, nullptr, FALSE); // 请求重绘
UpdateWindow(hwnd); // 立即更新
}
return 0;
}
case WM_DESTROY: { // 窗口销毁时清理资源
KillTimer(hwnd, 1);
if (ctx) {
if (ctx->hdcMem) DeleteDC(ctx->hdcMem);
if (ctx->hbmMem) DeleteObject(ctx->hbmMem);
delete ctx;
}
if (hwnd == g_hwndPrimary)
g_hwndPrimary = nullptr; // 清除主屏句柄
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
// 程序入口
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
) {
// 注册窗口类
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc; // 窗口过程
wc.hInstance = hInstance; // 实例句柄
wc.lpszClassName = L"MultiDisplayWindow"; // 类名
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 背景画刷(实际未使用)
RegisterClass(&wc);
// 枚举所有显示器
EnumDisplayMonitors(
nullptr, // 所有显示器
nullptr, // 无裁剪区域
MonitorEnumProc, // 回调函数
0); // 无额外数据
// 获取主显示器句柄(使用默认点(0,0)和主屏标志)
HMONITOR hPrimary = MonitorFromPoint(
POINT{ 0, 0 },
MONITOR_DEFAULTTOPRIMARY);
DWORD dwExStyle = WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW;
// 为每个显示器创建窗口
for (const auto& mi : g_monitorInfos) {
// 创建全屏窗口
HWND hwnd = CreateWindowEx(
WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_NOACTIVATE, // 顶层透明窗口
L"MultiDisplayWindow", // 类名
nullptr, // 无标题
WS_POPUP | WS_VISIBLE, // 无边框可见窗口
mi.rect.left, // 显示器左边界
mi.rect.top, // 显示器上边界
mi.rect.right - mi.rect.left, // 宽度
mi.rect.bottom - mi.rect.top, // 高度
nullptr, // 无父窗口
nullptr, // 无菜单
hInstance, // 实例句柄
nullptr); // 无额外数据
if (hwnd) {
// 判断是否是主显示器
if (mi.hMonitor == hPrimary) {
g_hwndPrimary = hwnd; // 保存主屏句柄
WindowContext* ctx = reinterpret_cast<WindowContext*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (ctx)
ctx->isPrimary = true; // 设置主屏标志
}
// 设置窗口透明度(完全不透明)
SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA);
//设置远程不可捕获
BOOL affinityResult = SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE);
if (!affinityResult) {
// Failed to set window display affinity, handle error
}
// 设置不受Windows 11的窥视功能影响
BOOL excluded = TRUE;
if (SUCCEEDED(DwmSetWindowAttribute(hwnd, DWMWA_EXCLUDED_FROM_PEEK, &excluded, sizeof(BOOL)))) {
// Exclude the window from the Windows 11 peek feature
printf(__FILE__, __FUNCTION__, __LINE__, "Failed to DwmSetWindowAttribute DWMWA_EXCLUDED_FROM_PEEK.Error: " + std::to_string(GetLastError()));
}
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// 启动定时器(每100ms触发)
SetTimer(hwnd, 1, 100, nullptr);
}
}
// 消息循环
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}