windows 用 printdlg 弹出标准打印对话框需初始化 printdlg、获取 hdc 并设 pd_returndc;gdi 打印须完整执行 startdoc/startpage/endpage/enddoc;unicode 打印必须用 textoutw 配合 multibytetowidechar 转码。

Windows 上用 PrintDlg 弹出标准打印对话框
Windows API 提供的 PrintDlg 是最轻量、最兼容的起点,它不负责实际渲染,只帮你拿到用户选的打印机、页数、份数等配置。直接调用它,比自己拼 GDI 打印逻辑安全得多。
常见错误是传入空或未初始化的 PRINTDLG 结构体——必须先 memset 为 0,再设 lStructSize 和 hDevMode/hDevNames(可用 GlobalAlloc 配合 DocumentProperties 获取)。
- 必须在调用前调用
GetPrinterDC或CreateDC获取设备上下文(HDC),否则对话框可能崩溃或静默失败 -
PD_RETURNDC标志要设上,否则返回的hDC无效;但别忘了后续用完后调用DeleteDC - 如果程序是多线程的,
PrintDlg必须在 UI 线程调用,否则对话框不显示或卡死
用 StartDoc + StartPage + GDI 绘制真实内容
拿到 HDC 后,得走完整 GDI 打印流程:启动文档 → 启动页面 → 绘图 → 结束页面 → 结束文档。跳过任意一步,输出可能为空、错页或触发驱动报错。
典型现象是“打印任务进队列但没纸出来”,大概率是漏了 EndPage 或 EndDoc;而“文字模糊/缩放异常”往往因为没查 GetDeviceCaps 的 LOGPIXELSX/Y,直接按屏幕 DPI 渲染。
立即学习“C++免费学习笔记(深入)”;
- 每次
StartPage后必须配对EndPage,即使只打一页 - 文本绘制优先用
TextOut或DrawText,避免SetTextColor后忘记SetBkMode导致背景遮盖 - 打印时禁用双缓冲(
WM_PRINT不适用),所有绘图必须直写到打印HDC
Linux/macOS 没有统一 API,得走 CUPS 或系统命令
C++ 在非 Windows 平台没有内建打印抽象层。硬连 CUPS 库(libcups.so)太重,更现实的做法是生成 PDF 或文本,再调 lp 命令交给系统处理。
常见坑是路径含空格或中文时,system("lp file.pdf") 直接失败;还有默认打印机变更后,lpstat -d 返回空导致程序误判。
- 用
popen替代system,能捕获lp的 stderr 输出(比如lp: No such file or directory) - 生成 PDF 推荐用轻量库如
libharu或直接写简单 PDF 结构(仅文本+字体+页面尺寸),别依赖 Qt / GTK - macOS 可用
lpr,但需注意默认队列名(lpstat -p查),且某些 M1 机器需加-o printer-is-shared=false
Unicode 文本打印容易乱码的根源
不是字体问题,而是 GDI 打印 HDC 默认用 OEM 字符集(CP_OEMCP)。哪怕你传的是 UTF-8 字符串,TextOut 也会按本地 ANSI 编码解释,中文直接变问号或方块。
解决方法不是换字体,是显式用宽字符接口 + 正确编码转换:
- 必须用
TextOutW(不是TextOutA),且字符串是wchar_t* - UTF-8 输入需先用
MultiByteToWideChar(CP_UTF8, ...)转,别用mbstowcs(locale 依赖,不可靠) - 打印 HDC 的字体建议用
CreateFont指定DEFAULT_CHARSET,而非GB2312_CHARSET(后者在部分打印机驱动里不识别)
真正麻烦的是:同一段代码,在不同品牌打印机上,对 TrueType 字体的支持程度天差地别。有些只认点阵字体,有些拒收嵌入子集——这没法靠代码绕过,只能实机测。











