背景:
针对开发过程中出现管理员权限生成PDF文件不会出现重叠现象,但是普通权限下生成PDF文件不会出现重叠现象分析:
方案1:
升级管理员权限
cpp
bool createProcessWithAdmin(const wchar_t* process_name, LPPROCESS_INFORMATION process)
{
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
// 检查进程名称是否为空
if (process_name == NULL || wcslen(process_name) == 0) {
debug3("Failed to process_name");
return false;
}
// 获取当前进程的访问令牌,具有所有权限
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
{
debug3("OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)");
return false;
}
// 复制进程令牌,设置为主要令牌,供新进程使用
if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &hTokenDup))
{
debug3("DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &hTokenDup)");
CloseHandle(hToken);
return false;
}
// 定义启动信息结构体
STARTUPINFO si;
LPVOID pEnv = NULL;
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
// 初始化 STARTUPINFO 结构体
ZeroMemory(&si, sizeof(STARTUPINFO));
// 设置令牌信息
if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)))
{
debug3("SetTokenInformation");
CloseHandle(hToken);
CloseHandle(hTokenDup);
return false;
}
// 设置启动信息
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = L"WinSta0\\Default";
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
// 创建环境块
if (!CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE))
{
debug3("CreateEnvironmentBlock");
CloseHandle(hToken);
CloseHandle(hTokenDup);
return false;
}
// 使用复制的令牌创建具有管理员权限的新进程
if (!CreateProcessAsUser(hTokenDup, process_name, NULL, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
pEnv, NULL, &si, process))
{
debug3("CreateProcessAsUser");
CloseHandle(hToken);
CloseHandle(hTokenDup);
return false;
}
// 销毁环境块
if (pEnv)
{
DestroyEnvironmentBlock(pEnv);
}
// 关闭令牌句柄
CloseHandle(hToken);
CloseHandle(hTokenDup);
return true;
}
test模块:
cpp
//方法1:
void test()
{
SHELLEXECUTEINFOW shExInfo = { 0 }; // 初始化 `SHELLEXECUTEINFOW` 结构
shExInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; // 创建进程并返回进程句柄
shExInfo.lpVerb = L"runas"; // 使用管理员权限运行
shExInfo.lpFile = t; // 要运行的程序路径
shExInfo.lpParameters = NULL; // 命令行参数
shExInfo.lpDirectory = NULL; // 初始目录
shExInfo.nShow = SW_SHOWNORMAL; // 设置窗口显示模式
// 调用 ShellExecuteExW 以管理员权限运行程序
b = ShellExecuteExW(&shExInfo);
//方法2:已知管理员用户和管理员密码实现权限升级:CreateProcessWithLogonW
STARTUPINFOW si = { 0 };
PROCESS_INFORMATION pi = { 0 };
wchar_t cmdLine[MAX_PATH * 2];
wchar_t userName[] = L"SHhao";
wchar_t domain[] = L"";
wchar_t password[] = L"812617";
// 构建命令行
if (swprintf_s(cmdLine, MAX_PATH * 2, L"\"%s\" %s", cmd, t) < 0) {
wprintf(L"Failed to construct command line.\n");
return -1;
}
// 初始化 STARTUPINFOW
si.cb = sizeof(STARTUPINFOW);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
// 调用 CreateProcessWithLogonW
BOOL b = CreateProcessWithLogonW(
userName, // 用户名
domain, // 域(为空表示本地)
password, // 密码
LOGON_WITH_PROFILE, // 使用用户配置文件
NULL, // 应用程序路径(NULL 表示从命令行获取)
cmdLine, // 完整命令行
CREATE_NEW_CONSOLE, // 创建新控制台
NULL, // 环境变量(NULL 表示使用父进程环境)
NULL, // 工作目录
&si, // 启动信息
&pi // 进程信息
);
debug3("spawning %ls as administrator - 1", t);
//方法3:利用令牌实现管理员权限升级
PROCESS_INFORMATION pi = { 0 };
b = createProcessWithAdmin(t, &pi);
}
方法2:
原因:
熟悉LitePDF模块代码,最终发现由于从EMF文件中回放生成PDF时,需要利用DC来计算PDF中文本区域,而代码处理时创建了屏幕DC来计算文本区域,导致文本绘制区域计算错误,因此出现文本重叠到一起的问题
修改点:
回放时根据外部传入的参数创建设备上下文来处理文本区域
最终采用方法2解决