使用 SetPrinter 函数修改打印机设置
03/09/2020
本文内容
该 SetPrinter 函数允许应用程序更改各种打印机属性。 但是,如本文中的代码所示,一定数量的准备工作是正确调用所必需的 SetPrinter 。
原始产品版本: 时间
原始 KB 数: 140285
SetPrinter 的 hPrinter 参数
第一个参数是要更改其设置的打印机的句柄。 应从检索此参数 OpenPrinter() 。
SetPrinter 的 dwLevel 参数
第二个参数指定传递到的数据的结构 SetPrinter() 。 参数值可以是0、 2、 3、 4、5、 6、 7、 8或9。
SetPrinter 的 lpbPrinter 参数
第三个参数是 PRINTER_INFO_n n 与第二个参数中的数字相对应的结构。 此结构可能会引起混淆,因为它并不只是结构大小的缓冲区。 这些结构包含与设备无关的信息,但随后会在内存中根据设备驱动程序提供的一些可变的设备相关信息。 因此,需要执行一些工作来确定此缓冲区的有效程度。 这是通过调用来实现的 GetPrinter() ,它将设置 pcbNeeded 为所需的总大小。
此外,缓冲区通常包含大量独立于设备的信息和与设备相关的信息。 您的应用程序不知道或关心大多数这些结构成员中的值。 因此,当您进行感兴趣的更改时,必须为所有其他数据段插入正确的值。 在第二次调用时设置其他数据片段 GetPrinter() 。
SetPrinter 的 DwCommand 参数
第四个参数用于暂停打印、恢复打印或清除所有打印作业。 通常不在使用时使用此参数 lpbPrinter 。 本文与设置打印机状态不相关,因此示例代码将此参数设置为零。
关于 DEVMODE
通常, DEVMODE 指向的结构的元素 pDevMode 将被修改(而不是的元素 PRINTER_INFO_n )。 在这种情况下,这些 pDevMode->dmFields 标志将告知应用程序可以更改哪些字段。 由于这是由你为你提供的 GetPrinter() ,你可以在 dmFields 尝试更改前检查此标志。
此外,由于在独立于设备的部件中修改字段 DEVMODE 可能也会影响设备相关部件中的更改,因此在调用之前需要先调用,以便为 DocumentProperties() SetPrinter() 设置一致 DEVMODE 的结构 SetPrinter() 。
示例代码
// MySetPrinter
// Demonstrates how to use the SetPrinter API. This particular function changes the orientation
// for the printer specified in pPrinterName to the orientation specified in dmOrientation.
// Valid values for dmOrientation are:
// DMORIENT_PORTRAIT (1) or DMORIENT_LANDSCAPE (2)
BOOL MySetPrinter(LPTSTR pPrinterName, short dmOrientation)
{
HANDLE hPrinter = NULL;
DWORD dwNeeded = 0;
PRINTER_INFO_2 *pi2 = NULL;
DEVMODE *pDevMode = NULL;
PRINTER_DEFAULTS pd;
BOOL bFlag;
LONG lFlag;
// Open printer handle (on Windows NT, you need full-access because you
// will eventually use SetPrinter)...
ZeroMemory(&pd, sizeof(pd));
pd.DesiredAccess = PRINTER_ALL_ACCESS;
bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
if (!bFlag || (hPrinter == NULL))
return FALSE;
// The first GetPrinter tells you how big the buffer should be in
// order to hold all of PRINTER_INFO_2. Note that this should fail with
// ERROR_INSUFFICIENT_BUFFER. If GetPrinter fails for any other reason
// or dwNeeded isn't set for some reason, then there is a problem...
SetLastError(0);
bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
{
ClosePrinter(hPrinter);
return FALSE;
}
// Allocate enough space for PRINTER_INFO_2...
pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
if (pi2 == NULL)
{
ClosePrinter(hPrinter);
return FALSE;
}
// The second GetPrinter fills in all the current settings, so all you
// need to do is modify what you're interested in...
bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
if (!bFlag)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
// If GetPrinter didn't fill in the DEVMODE, try to get it by calling
// DocumentProperties...
if (pi2->pDevMode == NULL)
{
dwNeeded = DocumentProperties(NULL, hPrinter,
pPrinterName,
NULL, NULL, 0);
if (dwNeeded <= 0)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
if (pDevMode == NULL)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
lFlag = DocumentProperties(NULL, hPrinter,
pPrinterName,
pDevMode, NULL,
DM_OUT_BUFFER);
if (lFlag != IDOK || pDevMode == NULL)
{
GlobalFree(pDevMode);
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
pi2->pDevMode = pDevMode;
}
// Driver is reporting that it doesn't support this change...
if (!(pi2->pDevMode->dmFields & DM_ORIENTATION))
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return FALSE;
}
// Specify exactly what we are attempting to change...
pi2->pDevMode->dmFields = DM_ORIENTATION;
pi2->pDevMode->dmOrientation = dmOrientation;
// Do not attempt to set security descriptor...
pi2->pSecurityDescriptor = NULL;
// Make sure the driver-dependent part of devmode is updated...
lFlag = DocumentProperties(NULL, hPrinter,
pPrinterName,
pi2->pDevMode, pi2->pDevMode,
DM_IN_BUFFER | DM_OUT_BUFFER);
if (lFlag != IDOK)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return FALSE;
}
// Update printer information...
bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
if (!bFlag)
// The driver doesn't support, or it is unable to make the change...
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return FALSE;
}
// Tell other apps that there was a change...
SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L,
(LPARAM)(LPCSTR)pPrinterName,
SMTO_NORMAL, 1000, NULL);
// Clean up...
if (pi2)
GlobalFree(pi2);
if (hPrinter)
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
return TRUE;
}