Hook EndDoc调用GDI LineTo画线错误生成新页的解决方法
问题根因
你现在的实现把线条画到末尾新增页面,核心问题是Hook的函数触发时机完全错误:
EndDoc是整个打印作业所有页面绘制、提交完成后才执行的最终收尾接口,代码走到EndDoc时,PDF虚拟打印驱动已经把所有已生成页面的内容写入PDF流,此时再调用LineTo这类GDI绘图接口,驱动会判定你要追加新的绘制内容,自动创建空白页承载这部分绘图,根本不可能把线条画到已经提交完成的原有页面上。
实现方案
要在所有现有页面上画线且不新增页面,按以下逻辑调整即可:
- 把Hook目标从
EndDoc换成EndPage:这个接口是单页级别的收尾函数,每打印完一页内容、提交当前页之前就会触发一次,整个打印流程里有多少页就会触发多少次。此时当前页的HDC上下文还处于可绘制状态,在调用原始EndPage接口前执行画线逻辑,线条会直接落在当前页上,完全不会触发新页面创建。 - 补上GDI资源回收逻辑:你原来的代码创建画笔后没有还原DC原有对象、也没有删除自定义画笔,会造成GDI资源泄漏,打印任务多了会耗尽系统GDI资源,导致绘图、打印功能异常。
参考实现代码
// Hook EndPage 而非 EndDoc int StopPrint::hookEndPage(HDC hdc) { // 创建实线画笔 HPEN hLinePen = CreatePen(PS_SOLID, 1, BLACK_PEN); // 将自定义画笔选入DC,保存DC原有画笔对象 HGDIOBJ hOldPen = SelectObject(hdc, hLinePen); // 执行画线逻辑,坐标可根据实际业务需求调整 MoveToEx(hdc, 500, 500, NULL); LineTo(hdc, 2000, 2000); // 还原DC原有对象 SelectObject(hdc, hOldPen); // 释放自定义画笔资源,避免泄漏 DeleteObject(hLinePen); // 调用原始EndPage接口提交当前页面 return getOriginalEndPageFunc()(hdc); }
额外提示:如果要画固定位置的线条(比如页眉线、作业行线、页脚分割线),建议提前通过
GetDeviceCaps接口获取当前打印DC的水平/垂直分辨率、可打印区域尺寸,按比例换算绘图坐标,避免不同纸张尺寸、不同打印DPI下线条位置错位。
内容的提问来源于stack exchange,提问作者Mohammadreza Hojatoleslami
相关产品推荐
相关产品推荐

