用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;
}

效果:

相关推荐
yujunl2 小时前
重写了一个BOM查询的脚本
开发语言
事圆则缓2 小时前
Kotlin 集合与序列:给页面一份清楚的数据
开发语言·windows·kotlin
事圆则缓2 小时前
Kotlin 异步与并发:从一次搜索请求走到状态流
android·开发语言·kotlin
从小白到软工2 小时前
4-3 项目-学生成绩管理系统(上)
c语言·开发语言·数据结构·经验分享·ai编程
外收内放3 小时前
Python基础语法练习题(72)
开发语言·python
无忧.芙桃3 小时前
C++语言原理与实践(十三):stack、queue 和 priority_queue的介绍与使用
开发语言·c++·栈·队列
Shaoshing3 小时前
消息发送
java·开发语言
乌暮3 小时前
从 `println` 到生产级日志:Spring Boot 日志体系完全指南
java·开发语言·jvm·spring boot·后端·学习·面试
星夜离尘564 小时前
MATLAB 定点量化误差实验 半个 LSB 的界限为什么挡不住削顶失真
开发语言·matlab