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解决

相关推荐
程序喵大人5 小时前
【C++入门】编译链接模型 - 01 一个 C++ 程序是怎样变成可执行文件的
开发语言·c++·编译链接模型
by209997 小时前
vector 的模拟实现:扩容与边界的详细阐述(下)
c++·经验分享·vector·动态数组
余额瞒着我当琳9 小时前
红黑树的实现--红黑树的概念、规则、效率、结构、旋转、查找、验证
数据结构·c++·算法
青少儿编程课堂10 小时前
AC自动机多模式串匹配精讲:校园关键词巡检实战解析
c++·python·算法·bfs·信息学竞赛
longlongzihan10 小时前
LeetCode 5. 最长回文子串:从暴力匹配到中心扩展的思维演进
c++·算法·leetcode
多弗朗皮卡丘10 小时前
C++继承
c++·继承
汉克老师11 小时前
GESP2026年9月认证C++七级( 第三部分编程题(2、括号序列))精讲
c++·gesp·小学生·学c++编程
jimy113 小时前
虚函数vtable,链接时看到构造函数,linker把符号地址写入vtable(三)
开发语言·c++
潼心1412o14 小时前
C++初阶(长期更新)第9讲:string(上)
开发语言·c++
朝朝辞暮i14 小时前
C++ 第 39 章: 阶段性总复习——类、对象、构造、继承、this、指针与智能指针
开发语言·c++·算法·ros2