欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 再聊Win11 24H2 自定义桌面背景

再聊Win11 24H2 自定义桌面背景

2025/6/15 16:56:44 来源:https://blog.csdn.net/geesehoward20000/article/details/148610574  浏览:    关键词:再聊Win11 24H2 自定义桌面背景

在之前的文章聊聊Win11 24H2 自定义桌面背景_24h2自定义壁纸-CSDN博客中,针对24H2的改动,分析了解决的方法,并给出了C和C#两种代码。后来有些小伙伴来问我,发现没有测试过的C代码竟然是无法使用的,这里先说声抱歉。

这段时间一直在忙着玩逆向,今天终于有时间来看一下原因了。

首先,C我是用了一个控制台程序去启动一个界面程序,并通过标题获取程序句柄,并设置ExStyle,再把程序父窗口设置为workerw,按道理说,应该是正确的,但无论怎样处理,程序在改变父窗体后都是不可见的状态,这就非常奇怪了。

于是,今天想尝试一下,看看是不是因为启动程序的方式不对导致的。

尝试创建一个windows窗体程序,程序很简单,也不需要放任何控件,只需要确定程序启动后,正确嵌入桌面,并在图标下层即可。尝试编写如下代码

// CountDownApp.cpp : 定义应用程序的入口点。
//#include "framework.h"
#include "CountDownApp.h"#define MAX_LOADSTRING 100// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此处放置代码。// 初始化全局字符串LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadStringW(hInstance, IDC_COUNTDOWNAPP, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_COUNTDOWNAPP));MSG msg;// 主消息循环:while (GetMessage(&msg, nullptr, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam;
}//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{WNDCLASSEXW wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style          = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc    = WndProc;wcex.cbClsExtra     = 0;wcex.cbWndExtra     = 0;wcex.hInstance      = hInstance;wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_COUNTDOWNAPP));wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_COUNTDOWNAPP);wcex.lpszClassName  = szWindowClass;wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassExW(&wcex);
}BOOL CALLBACK EnumWinProc(HWND hwnd, LPARAM IParam)
{HWND hDefView = FindWindowEx(hwnd, 0, "SHELLDLL_DefView", 0);if (hDefView != NULL) {HWND hWorkerw = FindWindowEx(hwnd, NULL, "WorkerW", 0);//获取窗口的句柄HWND hAppHwnd = (HWND)IParam;//获取窗口扩展式样LONG nExStyle = GetWindowLong(hAppHwnd, GWL_EXSTYLE);//窗口扩展式样添加分层nExStyle |= WS_EX_LAYERED;nExStyle |= WS_EX_COMPOSITED;LONG setResult = SetWindowLong(hAppHwnd, GWL_EXSTYLE, nExStyle);//刷新窗口,让式样立即生效BOOL ret = UpdateWindow(hAppHwnd);ret = ShowWindow(hAppHwnd, SW_SHOW);//窗口设置为桌面窗口的子窗口HWND preHwnd = SetParent(hAppHwnd, hWorkerw);return FALSE;}return TRUE;
}//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{hInst = hInstance; // 将实例句柄存储在全局变量中HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (!hWnd){return FALSE;}HWND hProgman = FindWindow("Progman", 0);//发送0x52c消息LRESULT result = SendMessage(hProgman, 0x52c, 0, 0);if (EnumWindows(EnumWinProc, (LPARAM)hWnd)){ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);}return TRUE;
}//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_COMMAND:break;case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);// TODO: 在此处添加使用 hdc 的任何绘图代码...EndPaint(hWnd, &ps);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}

一次就成功了!!说实话,有点懵,程序逻辑非常简单,就是在创建窗口实力的时候完成了控制台程序的操作,为啥就成功了呢?控制台创建的程序属性也一样,但就是不显示,程序自己来就显示正常。

具体原因还是不确定,猜测可能的原因是:

控制台创建进程后,窗口一完成load事件,之后再改动属性并刷新时,无法达到预期效果

2025.06.13更新:经过这两天的调试跟踪发现,WS_EX_LAYERED带有透明属性,会让界面的WM_PAINT消息失效,也就是说,在窗口创建前设置WS_EX_LAYERED不会影响窗口绘制,一旦窗口绘制成功,切换父句柄会让窗体变透明,由于WM_PAINT不会再执行,所以,默认控件无法再次显示出来。C#也一样,使用Paint事件跟踪发现,WS_EX_LAYERED窗体创建时,Paint事件执行2次,非WS_EX_LAYERED窗体执行1次。如果创建时没有改变父窗体,通过按钮改变,WS_EX_LAYERED窗体Paint事件只会调用一次,这样整个窗体就一直保持透明状态。

目前还没找到解决方案,也许用WS_EX_LAYERED属性本身有问题,只适合一次性启动嵌入桌面背景的程序,而要通过按钮切换则无法达到效果。后续可能会尝试其它方案来实现自定义,但目前还没有思路。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词