提升程序窗口Z序的UIAccess获取方法

需积分: 15 5 下载量 118 浏览量 更新于2024-10-09 收藏 244KB ZIP 举报
资源摘要信息:"通过System令牌获取UIAccess" 知识点一:UIAccess权限 UIAccess是一种特殊的权限,能够让程序窗口拥有比其他普通窗口更高的层级,即能够位于Z序的更高位置。例如,程序窗口可以位于任务管理器和屏幕键盘之上,这对于需要在其他窗口之上显示的屏幕标记和录制工具来说尤为重要。若不启用UIAccess权限,程序窗口可能会被其他窗口遮挡,无法正常显示。 知识点二:Z序(Z-Order) Z序是Windows系统中用于管理窗口堆叠顺序的概念,决定了哪个窗口在最上面,哪个窗口在最下面。窗口的Z序可以被手动或自动地调整。手动调整通常是通过调用SetWindowPos函数来改变窗口的位置,其中有一个参数为HWND_TOPMOST,表示窗口将被放置于所有非最高层级窗口之上。而UIAccess可以使得窗口在某些特定的系统窗口之上。 知识点三:任务管理器的窗口层级 任务管理器是一个系统工具,其窗口层级特别设置为ZBID_SYSTEM_TOOLS,高于普通窗口。如果一个程序窗口没有启用UIAccess权限,那么它的Z序将始终低于任务管理器,即使使用了SetWindowPos函数设置了HWND_TOPMOST属性。 知识点四:程序提权运行 要使程序获得UIAccess权限,程序必须以提权模式运行。提权运行意味着程序具有管理员权限。为了实现这一点,可以在程序的清单文件中设置请求管理员权限的清单,或者通过一个已经具有管理员权限的进程来启动目标程序。如果程序没有获得提权,尝试获取UIAccess权限的操作将失败,返回ERROR_NOT_FOUND错误。 知识点五:程序原理和错误处理 当一个程序尝试获取UIAccess权限时,它可能成功或失败。成功时,PrepareForUIAccess()函数会返回ERROR_SUCCESS。如果在执行过程中遇到问题,比如程序未以提权模式运行,函数将返回相应的错误代码。开发者需要根据返回的错误代码来处理不同的情况,并且提供相应的反馈。 知识点六:使用C语言和开源项目 文档提及的项目是以C语言编写的,并且是开源的。这意味着,源代码可供任何人免费使用和修改,便于社区成员学习和协作。它可能包含头文件和源文件,为开发者提供了一个基础的框架和接口,以便他们可以在自己的应用程序中实现UIAccess权限获取的功能。 知识点七:文件名称列表的含义 文件名称列表中的“uiaccess-master”可能表示这是一个开源项目中有关UIAccess权限控制的主分支或者是主版本的代码包。文件名称列表给出了压缩包中的文件结构概览,开发者可以根据这些信息来探索和构建项目。 总结,通过System令牌获取UIAccess权限是在创建某些特定的桌面应用程序时常常需要考虑的问题,尤其是在开发可能被其他窗口遮挡的应用,如屏幕录制或标记工具时。文档中描述的程序功能,提供了在满足特定条件下获得高级别Z序的一种方法,并通过C语言和开源的形式使得这一技术得以传播和应用。

#include "mainwindow.h" #include <QApplication> #include <windows.h> #include <wtsapi32.h> #include <QLibrary> typedef BOOL(WINAPI *WTSSendMessageFunc)(HANDLE, DWORD, LPWSTR, DWORD, LPWSTR, DWORD, DWORD, LPDWORD, BOOL); int main(int argc, char *argv[]) { QApplication a(argc, argv); // 加载wtsapi32.dll QLibrary lib("wtsapi32.dll"); // 判断是否加载成功 if (!lib.load()) { QMessageBox::warning(NULL, "Warning", QString("Failed to load wtsapi32.dll: %1").arg(lib.errorString())); return 1; } // 获取函数指针 WTSSendMessageFunc WTSSendMessage = (WTSSendMessageFunc)lib.resolve("WTSSendMessageW"); if (WTSSendMessage == NULL) { QMessageBox::warning(NULL, "Warning", QString("Failed to resolve WTSSendMessageW: %1").arg(lib.errorString())); return 1; } // 获取当前会话ID DWORD dwSessionId = WTSGetActiveConsoleSessionId(); if (dwSessionId == 0xFFFFFFFF) { QMessageBox::warning(nullptr, QStringLiteral("错误"), QStringLiteral("获取会话ID失败!")); return -1; } // 获取当前会话令牌 HANDLE hToken = NULL; if (!WTSQueryUserToken(dwSessionId, &hToken)) { QMessageBox::warning(nullptr, QStringLiteral("错误"), QStringLiteral("获取用户令牌失败!")); return -1; } // 创建互斥量,确保程序只能运行一个实例 HANDLE mutex = ::CreateMutex(Q_NULLPTR, true, (LPCWSTR)qApp->applicationName().toStdWString().c_str()); if (!mutex) { QMessageBox::warning(nullptr, QStringLiteral("错误"), QStringLiteral("创建互斥量失败!")); CloseHandle(hToken); return -1; } if (GetLastError() == ERROR_ALREADY_EXISTS) { QMessageBox waringBox(QMessageBox::Warning, QStringLiteral("警告"), QStringLiteral("程序[文本数据同步客户端]只能运行一个!")); waringBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定")); waringBox.setStandardButtons(QMessageBox::Ok); waringBox.exec(); ::CloseHandle(mutex); CloseHandle(hToken); return 0; } // 创建新进程,确保程序在当前会话中运行 STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.lpDesktop = (LPWSTR)L"winsta0\\default"; PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); if (!CreateProcessAsUser(hToken, NULL, (LPWSTR)qApp->applicationFilePath().toStdWString().data(), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { QMessageBox::warning(nullptr, QStringLiteral("错误"), QStringLiteral("创建进程失败!")); CloseHandle(mutex); CloseHandle(hToken); return -1; } // 关闭会话令牌和新进程句柄 CloseHandle(hToken); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); // 释放互斥量 ::ReleaseMutex(mutex); // 启动主窗口 MainWindow w; w.show(); return a.exec(); } 在以上代码中会提示:"获取用户令牌失败!",导致无法打开程序,这是什么原因,并给我解决办法

2023-05-31 上传