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

相关推荐
yong99902 小时前
C++实现LBM模拟Couette流
开发语言·c++
卡提西亚3 小时前
C++笔记-23-类和对象-多态
c++·笔记
玖笙&4 小时前
✨WPF编程进阶【7.1】动画基础
c++·c#·wpf·visual studio
QT 小鲜肉5 小时前
【C++基础与提高】第一章:走进C++的世界——从零开始的编程之旅
开发语言·c++·笔记·qt
@木辛梓5 小时前
模版 c++
开发语言·c++
oioihoii5 小时前
C++中的线程同步机制浅析
开发语言·c++
枫叶丹45 小时前
【Qt开发】布局管理器(五)-> QSpacerItem 控件
开发语言·数据库·c++·qt
月下倩影时5 小时前
ROS1基础入门:从零搭建机器人通信系统(Python/C++)
c++·python·机器人
_OP_CHEN5 小时前
C++进阶:(八)基于红黑树泛型封装实现 map 与 set 容器
开发语言·c++·stl·set·map·红黑树·泛型编程