桌面应用打印
本部分介绍如何从本机 Windows 桌面程序打印。
概述
若要在从本机 Windows 程序打印时提供最佳用户体验,必须将程序设计为从专用线程打印。 在本机 Windows 程序中,程序负责管理用户界面事件和消息。 打印操作可能需要一段时间的密集计算,因为为打印机呈现应用程序内容,这可能会阻止程序响应用户交互,如果此处理是在与用户交互的事件处理相同的线程中执行的。
如果你已经熟悉如何编写多线程本机 Windows 程序,请直接转到 如何从 Windows 应用程序打印 并了解如何向程序添加打印功能。
基本 Windows 计划要求
为了获得最佳性能和程序响应能力,请勿在处理用户交互的线程中执行程序的打印作业处理。
这种打印与用户交互的分离将影响程序管理应用程序数据的方式。 在开始编写应用程序之前,应全面了解这些含义。 以下主题介绍在程序的单独线程中处理打印的基本要求。
Windows 程序基础知识
本机 Windows 程序必须提供main窗口过程来处理它从操作系统接收的窗口消息。 Windows 程序中的每个窗口都有相应的 WndProc 函数,用于处理这些窗口消息。 运行此函数的线程称为用户界面或 UI 线程。
将资源用于字符串。
对于支持其他语言时可能需要更改的字符串,请使用程序资源文件中的字符串资源,而不是字符串常量。 程序必须先从资源文件检索资源并将其复制到本地内存缓冲区,然后程序才能将字符串资源用作字符串。 这需要在开始时进行一些额外的编程,但允许将来更轻松地修改、翻译和本地化程序。
分步处理数据。
按照可中断的步骤处理打印作业。 此设计使用户能够在长时间处理操作完成之前取消该操作,并阻止程序阻止可能同时运行的其他程序。
使用窗口用户数据。
打印应用程序通常有多个窗口和线程。 若要在不使用静态全局变量的情况下使数据在线程和处理步骤之间保持可用,请通过数据指针引用数据结构,该指针是使用它们的窗口的一部分。
下面的代码示例演示打印应用程序的main入口点。 此示例演示如何使用字符串资源而不是字符串常量,还演示处理程序窗口消息的main消息循环。
int APIENTRY
wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow
)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
HACCEL hAccelTable;
HRESULT hr = S_OK;
// Register the main window class name
WCHAR szWindowClass[MAXIMUM_RESOURCE_STRING_LENGTH];
LoadString(
hInstance,
IDC_PRINTSAMPLE,
szWindowClass,
MAXIMUM_RESOURCE_STRING_LENGTH);
MyRegisterClass(hInstance, szWindowClass);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
// Unable to initialize this instance of the application
// so display error message and exit
MessageBoxWithResourceString (
hInstance,
GetDesktopWindow(),
IDS_ERROR_INSTINITFAIL,
IDS_CAPTION_ERROR,
(MB_OK | MB_ICONEXCLAMATION));
return FALSE;
}
// Init COM for printing interfaces
if (FAILED(hr = CoInitializeEx(0, COINIT_MULTITHREADED)))
{
// Unable to initialize COM
// so display error message and exit
MessageBoxWithResourceString (
hInstance,
GetDesktopWindow(),
IDS_ERROR_COMINITFAIL,
IDS_CAPTION_ERROR,
(MB_OK | MB_ICONEXCLAMATION));
return FALSE;
}
hAccelTable = LoadAccelerators(
hInstance,
MAKEINTRESOURCE(IDC_PRINTSAMPLE));
// Main message handling loop
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Uninitialize (close) the COM interface
CoUninitialize();
return (int) msg.wParam;
}
文档信息
打印的本机 Windows 程序应设计为多线程处理。 多线程设计的要求之一是保护程序的数据元素,以便多个线程可以安全地同时使用它们。 可以通过使用同步对象和组织数据来保护数据元素,以避免线程之间的冲突。 同时,程序必须防止在打印程序数据时更改程序数据。 示例程序使用几种不同的多线程编程技术。
同步事件
示例程序使用事件、线程句柄和等待函数来同步打印线程与main程序之间的处理,并指示数据正在使用中。
特定于应用程序的 Windows 消息
示例程序使用特定于应用程序的窗口消息,使程序与其他本机 Windows 程序更兼容。 将处理分解为较小的步骤并在窗口消息循环中排队这些步骤可使 Windows 更轻松地管理处理,而不会阻止可能也在计算机上运行的其他应用程序。
数据结构
示例程序不是使用对象和类以面向对象的样式编写的,尽管它确实将数据元素分组到数据结构中。 此示例不使用面向对象的方法,以避免暗示一种方法比另一种方法更好或更差。
设计程序时,可以使用示例程序的函数和数据结构作为起点。 无论你是否决定设计面向对象的程序,要记住的重要设计注意事项是对相关的数据元素进行分组,以便可以根据需要在不同的线程中安全地使用这些元素。
打印机设备上下文
打印时,可能需要呈现要打印到设备上下文的内容。 如何:检索打印机设备上下文 介绍了获取打印机设备上下文的不同方法。
相关主题