如何修改 DocumentProperties() 函数使用的打印机设置


概要


使用DEVMODE结构修改打印机设置是结构的比只更改的字段更加困难。具体而言,设备有效DEVMODE结构包含的私有数据,只能通过DocumentProperties()函数进行修改。

本文介绍如何修改DEVMODE结构的DocumentProperties()函数的内容。

详细信息


由 Win32 SDK 中,所述的DEVMODE结构包含公共或"设备无关数据"和私有或"设备相关数据"。DEVMODE 专用部件存在紧跟的公共部分,由在DEVMODE结构,在连续的内存缓冲区。

程序无法预测此缓冲区的大小,因为它是不同于打印机到打印机并从一个版本到另一个版本的打印机驱动程序。此外,只声明由程序的DEVMODE结构不包含足够的空间用于专用设备数据。如果缺少专用数据的 DEVMODE 缓冲区传递给函数,如CreateDC()ResetDC()DocumentProperties()时,此函数可能会失败。

DEVMODE 可靠地使用设备驱动程序,请创建并按照下面的步骤对其进行修改:

  1. 确定所需的设备缓冲区的大小,然后为它分配足够的内存。

    DocumentProperties()返回最后一个参数设置为 0 时所需的 DEVMODE 缓冲区的字节的数。这篇文章中的代码示例使用此方法来确定正确的缓冲区大小。该代码示例使用malloc() C 运行时内存分配函数分配一个足够大的缓冲区。DocumentProperties()ResetDC()CreateDC()等功能带指针至 DEVMODE 作为参数,因为大多数应用程序可以分配由一个指针的内存。

    但是,如公共函数PrintDlg()采用将全局内存的句柄所需的参数。如果一个程序使用这些函数之一的参数作为最终的 DEVMODE 缓冲区,它应该使用GlobalAlloc()分配内存并获取使用GlobalLock()的缓冲区的指针。
  2. 请求设备驱动程序初始化 DEVMODE 缓冲区的默认设置。

    示例代码第二次调用DocumentProperties()来初始化与当前的默认设置分配的缓冲区。DocumentProperties()填充被称为具有打印机的当前设置的pDevModeOutput参数时的DM_OUT_BUFFER命令将传递 fMode 参数中的缓冲区。
  3. 对 DEVMODE 的公用部分进行更改并要求的设备驱动程序,以将更改合并到 DEVMODE 专用部分,通过调用DocumentProperties()

    初始化缓冲区与在步骤 2 中的当前设置之后, 的示例代码对 DEVMODE 的公用部分进行更改。请参阅 Win32 SDK 文档的DEVMODE成员说明。此示例代码确定打印机是否可以使用方向和双面打印 (双面) 设置和能够相应地更改它们。

    注意: 在 DEVMODE dmFields成员的标志是仅指示打印机使用相关联的结构成员。打印机有多种不同的物理特性,因此,可能只支持 DEVMODE 记录功能的一个子集。若要确定受支持的 DEVMODE 字段设置,应用程序应使用DeviceCapabilities()



    示例代码然后使第三个调用DocumentProperties()并的 pDevModeInput 和 pDevModeOutput 的参数中传递的 DEVMODE 缓冲区。它还通过使用 OR("|") 运算符传递 fMode 参数中 DM_IN_BUFFER 和 DM_OUT_BUFFER 的组合命令。这些命令会告诉函数以执行任何设置都包含在输入缓冲区,将它们与该设备的当前设置合并。然后它将结果写入输出参数中指定的缓冲区。
DocumentProperties()指特定打印机的打印机句柄: hPrinter。此句柄被来自OpenPrinter(),该代码示例还演示了。OpenPrinter()需要一台打印机,这通常是打印机的友好名称出现在操作系统外壳程序的名称。此名称可以从EnumPrinters()PrintDlg(),由返回DEVNAMES结构或默认打印机。

有关默认打印机的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:

246772如何检索和设置 Windows 中的默认打印机
注意: 在本文中,用DocumentProperties()来执行了分配缓冲区的正确大小和初始化缓冲区的前两个步骤。通过使用GetPrinter(),您也可以按照下列步骤操作。其他信息和示例,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:

140285如何使用 SetPrinter 修改打印机设置

示例代码

该代码示例遵循以下三个步骤来获取和更改 DEVMODE 缓冲区。该函数将指定的打印机并配置 DEVMODE 打印双面和以横向方式,如果它支持这些功能。返回到调用方的生成特性是适合使用 DEVMODE 缓冲区,如CreateDC()SetPrinter()PrintDlg()ResetDC()的其他 API 调用。完成后使用 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;

}