PDF文件内容出现重叠现象解析

背景:

针对开发过程中出现管理员权限生成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解决

相关推荐
王老师青少年编程1 天前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮1 天前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
样例过了就是过了1 天前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
谭欣辰1 天前
C++ 排列组合完整指南
开发语言·c++·算法
橙子也要努力变强1 天前
信号捕捉底层机制-机理篇2
linux·服务器·c++
盐焗鹌鹑蛋1 天前
【C++】stack和queue类
c++
郝学胜-神的一滴1 天前
罗德里格斯旋转公式(Rodrigues‘ Rotation Formula)完整推导
c++·unity·godot·图形渲染·three.js·unreal
lzh200409191 天前
深入理解进程:从PCB内核结构到写时拷贝的底层实战
linux·c++
aseity1 天前
跨平台项目中QString 与 非Qt 跨平台动态库在字符集上的一个实用的互操作约定.
c++·经验分享
CN-Dust1 天前
【C++】while语句例题专题
数据结构·c++·算法