win11实现类似任务栏日期功能_1

相信带伙都用过或看过鲁大师或者类似鲁大师这种东西,讲道理不是我care它,鲁大师**都不用。 

但是有个功能还是比较好的,他会在任务栏实时显示温度之类的资源信息。 最近新加了内存,想偶尔看看电脑资源占用,总不能老打开任务管理器吧....

实现思路

首先得想法就是,创建窗口,在窗口中绘制箭头效果做网速显示也好,绘制文字显示资源占用也好都好做。关键问题就是如何在任务栏创建出来窗口,这方面winapi并没有给出相应的接口。

我去查了一下,搜到了一个叫DeskBand的东西

来自CSDN概述想必大家都很熟悉鲁大师这样的软件,那么用过的人肯定都会觉得一个功能很有用,就是它在任务栏语言栏位置显示的一个小控件,用来监视一些系统资源的使用情况。肯定也有不少人想制作像它那样的软件,可是搜索的时候连个关键字都找不到,任务栏的这个位置到底叫什么呢?通过一个偶然的机会,才找到它的学名—— DeskBand。但是令人难受的是,MSDN上有关其定制的资料少之又少,不过还好天无绝人之路,在Gith..._deskbandhttps://blog.csdn.net/q886yes/article/details/86531307

气人的是win11把他移除了。

最终实现方法是创建一个POPUP的窗口,将该窗口的父窗口设置为任务栏。这个窗户就可以在任务栏的指定位置显示了,注意z轴关系,不要让任务栏把他遮盖了。

代码

目前代码只创建了窗口并让窗口显示在任务栏上,绘制有时间再写。

窗口类的实现好像是参考了B站一个搬运视频,一个讲DX11的大佬的写法,核心是将this指针在创建窗口时传给lparam,以下是winapi对lparam参数解释

[in, optional] lpParam

类型: LPVOID

指向要通过 CREATESTRUCT 结构传递到窗口的值的指针, (WM_CREATE消息的 lParam 参数指向的 lpCreateParams 成员。 此消息在返回之前由此函数发送到创建的窗口。

窗口类头文件:

class ZdsjWindow
{
public:
    ZdsjWindow(HWND parent, HINSTANCE hinstance);
    ZdsjWindow(const ZdsjWindow& zdsj_window) = delete;
    ZdsjWindow& operator=(const ZdsjWindow& zdsj_window) = delete;
    ~ZdsjWindow();
    HWND getHwnd();
private:
    // 注册窗口类
    bool registerClass(HINSTANCE hinstance);
    // 创建窗口
    bool createWindow(HINSTANCE hinstance);
    // 计算宽度
    int getWidth(const RECT* rect);
    // 计算高度
    int getHeight(const RECT* rect);
    
    static LRESULT CALLBACK HandelMsgSetUp(HWND handle, UINT msg, WPARAM wParam, LPARAM lParam);
    static LRESULT CALLBACK HandelMsgForward(HWND handle, UINT msg, WPARAM wParam, LPARAM lParam);
    LRESULT CALLBACK HandelMsg(HWND handle, UINT msg, WPARAM wParam, LPARAM lParam);
       
    
    const wchar_t* _windowName = L"SourceObserve";
    const wchar_t* _className = L"SourceObserve";
    HWND _hwnd = NULL;
    RECT* _rect = nullptr;
    TaskTray* _taskTray = nullptr;
    Menu* _menu = nullptr;
};

 窗口类实现:

ZdsjWindow::ZdsjWindow(HWND parent, HINSTANCE hinstance)
{
    // 设置窗口大小
    RECT rect = {};
    GetWindowRect(parent, &rect);
    this->_rect = new RECT;
    this->_rect->left = rect.left + 100;
    this->_rect->top = 0;
    this->_rect->right = rect.left + 100 + 100;
    this->_rect->bottom = this->_rect->top + this->getHeight(&rect);
    
    // 1. 设置窗口类并注册
    if(!this->registerClass(hinstance))
    {
        exit(REGISTER_ERROR_EXIT);
    }
    
    // 2. 创建窗口
    if(!this->createWindow(hinstance))
    {
        exit(CREATEWINDOW_ERROR_EXIT);
    }
    // ShowWindow(this->_hwnd, 1);
    // 3. 设置系统托盘
    this->_menu = new Menu();
    this->_taskTray = new TaskTray(this->_hwnd, this->_menu->getMenu());
    // 4. 设置父窗口并显示
    SetParent(this->_hwnd, parent);
    SetWindowPos(this->_hwnd, HWND_TOP, this->_rect->left, this->_rect->top,
        this->getWidth(this->_rect), this->getHeight(this->_rect), SWP_DEFERERASE);
    SetLayeredWindowAttributes(this->_hwnd, NULL, 255, LWA_ALPHA);
    ShowWindowAsync(this->_hwnd, 1);
}

ZdsjWindow::~ZdsjWindow()
{
    UnregisterClass(this->_className, NULL);
    delete this->_rect;
    if(this->_hwnd != NULL)
    {
        DestroyWindow(this->_hwnd);
    }
}

HWND ZdsjWindow::getHwnd()
{
    return this->_hwnd;
}

bool ZdsjWindow::registerClass(HINSTANCE hinstance)
{
    WNDCLASSEXW wndclass = {};
    wndclass.cbSize = sizeof(wndclass);
    wndclass.style = CS_HREDRAW | CS_VREDRAW ;
    wndclass.lpfnWndProc = HandelMsgSetUp;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hinstance;
    wndclass.hIcon = NULL;
    // MAKEINTRESOURCE()
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    // wndclass.hCursor = NULL;
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = this->_className;
    return RegisterClassExW(&wndclass);
}

bool ZdsjWindow::createWindow(HINSTANCE hinstance)
{
    this->_hwnd = CreateWindowExW(
        WS_EX_LAYERED,
        this->_className,
        this->_windowName,
        WS_POPUP,
        this->_rect->left,
        this->_rect->top,
        this->getWidth(this->_rect),
        this->getHeight(this->_rect),
        NULL,
        NULL,
        hinstance,
        this
    );
    return this->_hwnd != NULL;
}

int ZdsjWindow::getWidth(const RECT* rect)
{
    return rect->right - rect->left;
}

int ZdsjWindow::getHeight(const RECT* rect)
{
    return rect->bottom - rect->top;
}

LRESULT ZdsjWindow::HandelMsgSetUp(HWND handle, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_NCCREATE) {
        // 创建窗口时触发
        // lParam 指向 CREATESTRUCT 结构的指针,其中包含有关正在创建的窗口的信息。
        // CREATESTRUCT.lpCreateParams 也就是CreateWindowExW的LPVOID指向的指针
        const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
        ZdsjWindow* const pwnd = static_cast<ZdsjWindow*>(pCreate->lpCreateParams);
        // 将执行CreateWindowExW的this指针存入窗口
        SetWindowLongPtrW(handle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pwnd));
        // 不能通过WINAPI调用成员函数, 在将此函数设置为消息处理函数后,被当作WINAPI了
        // 将消息转发到静态方法
        // GWLP_WNDPROC设置窗口过程的新地址
        SetWindowLongPtrW(handle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&ZdsjWindow::HandelMsgForward));
        return pwnd->HandelMsg(handle, msg, wParam, lParam);
    }
    return DefWindowProc(handle, msg, wParam, lParam);
}

LRESULT ZdsjWindow::HandelMsgForward(HWND handle, UINT msg, WPARAM wParam, LPARAM lParam)
{
    ZdsjWindow* const pwnd = reinterpret_cast<ZdsjWindow*>(GetWindowLongPtrW(handle, GWLP_USERDATA));
    return pwnd->HandelMsg(handle, msg, wParam, lParam);
}

LRESULT ZdsjWindow::HandelMsg(HWND handle, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    WORD event;
    switch (msg)
    {
    case WM_SETCURSOR:
        LOWORD(lParam);
        event = HIWORD(lParam);
        switch (event)
        {
        case WM_MOUSEMOVE:
            // 目前只能move触发
            break;
        case WM_MOUSEHOVER :
            // xPos = GET_X_LPARAM(lParam); 
            // yPos = GET_Y_LPARAM(lParam);
            // std::cout << "x: " << xPos << " y: " << yPos << std::endl;
            break;
        case WM_RBUTTONDBLCLK:
            // std::cout << "rclick" << std::endl;
            break;
        }
        break;
    case WM_SIZE:
        //
        // width = LOWORD(lParam);
        // height = HIWORD(lParam);
        // std::cout << "size" << " width: " << width << " height: " << height << std::endl;
        break;
    case WM_PAINT:
        break;
    case WM_NCPAINT:
        break;
    case WM_CREATE://窗口创建时候的消息.
        break;
    case WM_USER://连续使用该程序时候的消息.
        break;
    case WM_DESTROY://窗口销毁时候的消息.
        PostQuitMessage(0);
        break;
    default:
        break;
    }
    if (this->_menu != nullptr) {
        switch (msg)
        {
        case WM_COMMAND:
            this->_menu->dealMenuMessage(handle, msg, wParam, lParam);
            break;
        }
    }
    // 处理系统托盘消息
    if (this->_taskTray != nullptr) {
        this->_taskTray->dealTaskBarMessage(handle, msg, wParam, lParam);
    }
    return DefWindowProc(handle, msg, wParam, lParam);
}

其中关键点就是setParent,设置父窗口。父窗口,也就是任务栏句柄获取方式:

HWND parent = FindWindowW(L"Shell_TrayWnd", NULL);

这个类名和窗口名可以通过vs自带spy++或者其他工具获取,但好像获取的与这个不太一样。

需要注意的是setwindowpos里设置z轴,hWndInsertAfter参数。

[in, optional] hWndInsertAfter

类型:HWND

在 Z 顺序中定位窗口之前窗口的句柄。 此参数必须是窗口句柄或以下值之一。

Value含义

HWND_BOTTOM HWND_BOTTOM

(HWND) 1

将窗口置于 Z 顺序的底部。 如果 hWnd 参数标识最顶层的窗口,则窗口将失去其最顶层状态,并放置在所有其他窗口的底部。

HWND_NOTOPMOST

(HWND) -2

将窗口置于所有非顶部窗口上方 (,即位于最顶部窗口) 后面。 如果窗口已经是非最顶部窗口,则此标志不起作用。

HWND_TOP

(HWND) 0

将窗口置于 Z 顺序的顶部。

HWND_TOPMOST

(HWND) -1

将窗口置于所有非最顶部窗口的上面。 该窗口即使已停用,也会保留在最高位置。

文件里面的taskTray和menu是系统托盘区的,就是任务栏右边类似qq那种小图标,右键退出之类的。

后续准备通过dx11绘制具体资源数据,放在下篇细说吧,这个还没有传github后续应该会传的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值