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

相关推荐
不想写代码的星星几秒前
C++ 折叠表达式:“我写递归你写折叠,咱俩代码差十年”
c++
Titan20241 小时前
map和set的封装学习笔记
数据结构·c++
懒惰的bit1 小时前
MFC常见消息映射(简洁版)
c++·mfc
Yupureki1 小时前
《算法竞赛从入门到国奖》算法基础:动态规划-路径dp
数据结构·c++·算法·动态规划
321.。2 小时前
Linux 进程控制深度解析:从创建到替换的完整指南
linux·开发语言·c++·学习
小Tomkk2 小时前
怎么配置 Visual Studio Code 配置 C/C++
c语言·c++·vscode
CheerWWW2 小时前
C++学习笔记——枚举、继承、虚函数、可见性
c++·笔记·学习
比昨天多敲两行3 小时前
C++ AVL树
开发语言·c++
小糯米6013 小时前
C++ 并查集
java·c++·算法
weixin_441003643 小时前
2027徐涛《核心考案+优题库》电子版pdf
pdf