SetLayeredWindowAttributes导致窗口最小化后鼠标点击异常求助
问题描述
窗口最小化恢复后,除单个像素区域外,无法点击窗口上的任何内容。使用MinGW编译,通过清单文件启用子窗口透明效果;移除清单文件则问题消失,但子窗口无法实现透明效果。
相关WM_CREATE代码片段:
case WM_CREATE: SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED); SetLayeredWindowAttributes(hwnd, RGB(255, 0, 0), 0 /*doesn't matter*/, LWA_COLORKEY); hbackground = CreateWindowExA(0, "STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_BITMAP, 0, 0, window_width, window_height, hwnd, NULL, NULL, (LPVOID)NULL); setImage(hbackground, background_image_name, monitor_dimension.width, monitor_dimension.height); SetWindowLongA(hbackground, GWL_EXSTYLE, GetWindowLongA(hbackground, GWL_EXSTYLE) | WS_EX_LAYERED); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED); SetLayeredWindowAttributes(hbackground, 0, (255 * 50) / 100, LWA_ALPHA); SetLayeredWindowAttributes(hbackground, 0, (255 * 50) / 100, LWA_ALPHA); break;
解决方法
1. 修正清单文件的兼容性配置
清单文件中的旧系统兼容或DPI设置可能导致窗口区域计算错误,建议调整为以下内容:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> </dependentAssembly> </dependency> <application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware> </windowsSettings> </application> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> </assembly>
- 启用每监视器DPI感知,避免窗口缩放导致的区域偏移
- 移除不必要的旧Windows版本兼容节点,减少兼容性冲突
2. 在窗口恢复时重置分层属性
窗口最小化后,分层窗口的区域或属性信息可能丢失,需在WM_SIZE或WM_RESTORE消息中重新初始化:
case WM_SIZE: if (wParam != SIZE_MINIMIZED) { // 重置父窗口分层属性与尺寸 SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); SetWindowPos(hwnd, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_FRAMECHANGED | SWP_NOMOVE); SetLayeredWindowAttributes(hwnd, RGB(255, 0, 0), 0, LWA_COLORKEY); // 重置子窗口尺寸与透明属性 SetWindowPos(hbackground, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER); SetWindowLongA(hbackground, GWL_EXSTYLE, GetWindowLongA(hbackground, GWL_EXSTYLE) | WS_EX_LAYERED); SetLayeredWindowAttributes(hbackground, 0, (255 * 50) / 100, LWA_ALPHA); } break; case WM_RESTORE: // 强制触发WM_SIZE逻辑,确保窗口属性正确重置 RECT rc; GetWindowRect(hwnd, &rc); SendMessage(hwnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rc.right - rc.left, rc.bottom - rc.top)); break;
3. 清理冗余代码
原WM_CREATE中重复调用了SetLayeredWindowAttributes(hbackground, ...),移除其中一次即可,避免不必要的属性覆盖。
4. 改用UpdateLayeredWindow(可选)
若SetLayeredWindowAttributes仍存在问题,可改用UpdateLayeredWindow精确控制窗口透明度与区域:
// 示例:在初始化或WM_PAINT中调用 HDC hdcScreen = GetDC(NULL); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, window_width, window_height); HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp); // 绘制内容到hdcMem(此处替换为你的绘图逻辑) // ... BLENDFUNCTION blend = {0}; blend.BlendOp = AC_SRC_OVER; blend.SourceConstantAlpha = (255 * 50)/100; blend.AlphaFormat = AC_SRC_ALPHA; POINT ptWinPos = {0, 0}; SIZE szWin = {window_width, window_height}; POINT ptSrc = {0, 0}; UpdateLayeredWindow(hbackground, hdcScreen, &ptWinPos, &szWin, hdcMem, &ptSrc, 0, &blend, ULW_ALPHA); // 清理资源 SelectObject(hdcMem, hbmpOld); DeleteObject(hbmp); DeleteDC(hdcMem); ReleaseDC(NULL, hdcScreen);
内容的提问来源于stack exchange,提问作者SKNG
相关产品推荐
相关产品推荐

