本文介绍如何使用 DocumentProperties()
函数修改打印机设置。
原始产品版本: 打印机
原始 KB 数: 167345
总结
使用 DEVMODE 结构修改打印机设置比更改结构字段更困难。 具体而言,设备的有效 DEVMODE 结构包含只能由函数修改的 DocumentProperties()
专用数据。
本文介绍如何使用 DocumentProperties()
函数修改 DEVMODE 结构的内容。
详细信息
由 Win32 SDK 记录的 DEVMODE 结构包含公共或“设备无关数据”和专用或“设备依赖数据”。 DEVMODE 的专用部分紧跟在由 DEVMODE 结构定义的公共部件之后,该部分位于连续内存缓冲区中。
程序无法预测此缓冲区的大小,因为它不同于打印机和打印机驱动程序的版本。 此外,由程序声明的 DEVMODE 结构不包含足够的空间用于专用设备数据。 如果缺少专用数据的 DEVMODE 缓冲区传递给函数,CreateDC()
ResetDC()
并且DocumentProperties()
该函数可能会失败。
若要可靠地将 DEVMODE 与设备驱动程序配合使用,请按照以下步骤创建和修改它:
确定设备中缓冲区的所需大小,然后为其分配足够的内存。
DocumentProperties()
返回将最后一个参数设置为 0 时 DEVMODE 缓冲区所需的字节数。 本文中的示例代码使用此技术来确定缓冲区的正确大小。 然后,示例代码使用 C 运行时内存分配函数malloc()
来分配足够大的缓冲区。 由于DocumentProperties()
和函数类似ResetDC()
并CreateDC()
采用指向 DEVMODE 的指针作为参数,因此大多数应用程序都可以分配由指针处理的内存。但是,常见
PrintDlg()
采用参数等函数需要处理全局内存。 如果程序使用最终的 DEVMODE 缓冲区作为这些函数之一的参数,则应使用它分配内存并使用GlobalAlloc()
获取指向缓冲区GlobalLock()
的指针。要求设备驱动程序使用默认设置初始化 DEVMODE 缓冲区。
示例代码第二次调用
DocumentProperties()
,以使用当前默认设置初始化分配的缓冲区。DocumentProperties()
在 fMode 参数中传递命令时DM_OUT_BUFFER
,使用打印机的当前设置填充称为 pDevModeOutput 参数的缓冲区。更改 DEVMODE 的公共部分,并要求设备驱动程序通过调用
DocumentProperties()
将更改合并到 DEVMODE 的专用部分。使用步骤 2 中的当前设置初始化缓冲区后,示例代码会更改 DEVMODE 的公共部分。 有关 DEVMODE 成员的说明,请参阅 Win32 SDK 文档。 此示例代码确定打印机是否可以使用方向和双面(双面)设置,并相应地更改它们。
注意
DEVMODE 的 dmFields 成员中的标志只是指示打印机使用关联的结构成员。 打印机具有多种不同的物理特征,因此,可能仅支持 DEVMODE 记录功能的子集。 若要确定 DEVMODE 字段支持的设置,应用程序应使用
DeviceCapabilities()
。然后,示例代码对 pDevModeInput 和 pDevModeOutput 参数进行第三次调用
DocumentProperties()
并传递 DEVMODE 缓冲区。 它还使用 OR(“|”) 运算符在 fMode 参数中传递DM_IN_BUFFER和DM_OUT_BUFFER的组合命令。 这些命令告知函数采用输入缓冲区中包含的任何设置,并将其与设备的当前设置合并。 然后将结果写入输出参数中指定的缓冲区。
注意
DocumentProperties()
通过打印机句柄引用特定打印机:hPrinter。 从中获取 OpenPrinter()
此句柄,示例代码也演示了该句柄。 OpenPrinter()
需要打印机的名称,该名称通常是操作系统 shell 中显示的打印机的友好名称。 可以从 、DEVNAMES 结构返回PrintDlg()
或从默认打印机获取EnumPrinters()
此名称。
在本文中,分配正确的缓冲区大小以及初始化缓冲区的前两个步骤。DocumentProperties()
也可以使用以下步骤 GetPrinter()
操作。
有关详细信息和示例,请参阅 使用 SetPrinter 函数修改打印机设置。
代码示例
示例代码遵循以下三个步骤来获取和更改 DEVMODE 缓冲区。 该函数采用命名打印机,并配置 DEVMODE 以打印双面和横向(如果它支持这些功能)。 返回给调用方的结果 DEVMODE 适用于使用 DEVMODE 缓冲区的其他 API 调用,例如CreateDC()
,SetPrinter()
或PrintDlg()
ResetDC()
。 当调用方使用 DEVMODE 缓冲区完成时,调用方负责释放内存。
LPDEVMODE GetLandscapeDevMode(HWND hWnd, char *pDevice)
{
HANDLE hPrinter;
LPDEVMODE pDevMode;
DWORD dwNeeded, dwRet;
/* Start by opening the printer */
if (!OpenPrinter(pDevice, &hPrinter, NULL))
return NULL;
/*
* Step 1:
* Allocate a buffer of the correct size.
*/
dwNeeded = DocumentProperties(hWnd,
hPrinter, /* Handle to our printer. */
pDevice, /* Name of the printer. */
NULL, /* Asking for size, so */
NULL, /* these are not used. */
0); /* Zero returns buffer size. */
pDevMode = (LPDEVMODE)malloc(dwNeeded);
/*
* Step 2:
* Get the default DevMode for the printer and
* modify it for your needs.
*/
dwRet = DocumentProperties(hWnd,
hPrinter,
pDevice,
pDevMode, /* The address of the buffer to fill. */
NULL, /* Not using the input buffer. */
DM_OUT_BUFFER); /* Have the output buffer filled. */
if (dwRet != IDOK)
{
/* If failure, cleanup and return failure. */
free(pDevMode);
ClosePrinter(hPrinter);
return NULL;
}
/*
* Make changes to the DevMode which are supported.
*/
if (pDevMode->dmFields & DM_ORIENTATION)
{
/* If the printer supports paper orientation, set it.*/
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
}
if (pDevMode->dmFields & DM_DUPLEX)
{
/* If it supports duplex printing, use it. */
pDevMode->dmDuplex = DMDUP_HORIZONTAL;
}
/*
* Step 3:
* Merge the new settings with the old.
* This gives the driver an opportunity to update any private
* portions of the DevMode structure.
*/
dwRet = DocumentProperties(hWnd,
hPrinter,
pDevice,
pDevMode, /* Reuse our buffer for output. */
pDevMode, /* Pass the driver our changes. */
DM_IN_BUFFER | /* Commands to Merge our changes and */
DM_OUT_BUFFER); /* write the result. */
/* Finished with the printer */
ClosePrinter(hPrinter);
if (dwRet != IDOK)
{
/* If failure, cleanup and return failure. */
free(pDevMode);
return NULL;
}
/* Return the modified DevMode structure. */
return pDevMode;
}