用C++编写屏幕准星

c 复制代码
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib,"gdiplus.lib")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")

using namespace Gdiplus;

// 高DPI感知定义
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
#endif

static int     g_x = 1920; // 圆点的坐标位置,主要看你的显示器分辨率,如果是3840x2160,那么分别填写1920和1080
static int     g_y = 1080; // 圆点的坐标位置
static float   g_centerDotRadius = 4.8f; // 圆点半径
static float   g_lineLen = 20.0f; // 十字准星线条长度
static float   g_lineWidth = 1.0f; // 十字准星线条厚度
static BYTE    g_alpha = 255; // 不透明度

HBITMAP DrawCrosshairBitmap(int width, int height) {
    Bitmap bmp(width, height, PixelFormat32bppARGB);
    Graphics g(&bmp);
    g.Clear(Color(0, 0, 0, 0));

    REAL cx = width / 2.0f;
    REAL cy = height / 2.0f;

    SolidBrush redBrush(Color(g_alpha, 255, 63, 63));
    Pen redPen(Color(g_alpha, 255, 63, 63), g_lineWidth);

    g.FillEllipse(&redBrush,
        cx - g_centerDotRadius,
        cy - g_centerDotRadius,
        g_centerDotRadius * 2,
        g_centerDotRadius * 2);

    g.DrawLine(&redPen, cx - g_lineLen, cy, cx + g_lineLen, cy);
    g.DrawLine(&redPen, cx, cy - g_lineLen, cx, cy + g_lineLen);

    HBITMAP hBmp = nullptr;
    bmp.GetHBITMAP(Color(0, 0, 0, 0), &hBmp);
    return hBmp;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    if (msg == WM_DESTROY)
    {
        PostQuitMessage(0);
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

int main() {
    // ==========开启每显示器DPI感知,必须放在main最前面!==========
    SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);

    GdiplusStartupInput gdiInput{};
    ULONG_PTR gdiToken;
    GdiplusStartup(&gdiToken, &gdiInput, nullptr);

    const wchar_t* clsName = L"CrosshairULW";
    WNDCLASSEXW wc{ 0 };
    wc.cbSize = sizeof(WNDCLASSEXW);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandleW(NULL);
    wc.lpszClassName = clsName;
    RegisterClassExW(&wc);

    int winHalf = (int)(g_lineLen + 12.0f);
    int winSize = winHalf * 2;

    HWND hwnd = CreateWindowExW(
        WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT,
        clsName,
        L"",
        WS_POPUP,
        0, 0, winSize, winSize,
        NULL,
        NULL,
        GetModuleHandleW(NULL),
        NULL
    );

    HBITMAP hCrossBmp = DrawCrosshairBitmap(winSize, winSize);

    HDC hdcScreen = GetDC(NULL);
    HDC hdcMem = CreateCompatibleDC(hdcScreen);
    HBITMAP hOld = (HBITMAP)SelectObject(hdcMem, hCrossBmp);

    SIZE winSz = { winSize, winSize };
    POINT ptSrc = { 0,0 };
    POINT ptDst = { g_x - winHalf, g_y - winHalf };
    BLENDFUNCTION bf{};
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 255;
    bf.AlphaFormat = AC_SRC_ALPHA;

    UpdateLayeredWindow(
        hwnd,
        hdcScreen,
        &ptDst,
        &winSz,
        hdcMem,
        &ptSrc,
        0,
        &bf,
        ULW_ALPHA
    );

    SelectObject(hdcMem, hOld);
    DeleteDC(hdcMem);
    ReleaseDC(NULL, hdcScreen);
    DeleteObject(hCrossBmp);

    ShowWindow(hwnd, SW_SHOWNOACTIVATE);

    MSG msg{};
    while (GetMessageW(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    GdiplusShutdown(gdiToken);
    return (int)msg.wParam;
}

效果:

相关推荐
曦樂~7 小时前
Cpp面筋
c语言·c++
道尔柯南8 小时前
C++ string 类详解:从常用接口到深拷贝,彻底掌握字符串处理
android·java·c++
来让爷抱一个9 小时前
Python 异步里混用同步库,事件循环被卡住的全过程
开发语言·python
十二11 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
心祭丫丫11 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
露天赏雪12 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
D e re k ZH13 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
yeccheng14 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
联犀14 小时前
纯 Go 的 CAD 开源库 go-cad:直接解析 DWG/DXF,现在也能导出 PDF
开发语言·golang·pdf
zjxtxdy15 小时前
C++面向对象程序开发-类与对象
开发语言·c++