【问题标题】:Why might DeviceCapabilities() return 4294967295 for DC_BINS?为什么 DeviceCapabilities() 可能会为 DC_BINS 返回 4294967295?
【发布时间】:2021-11-18 00:52:19
【问题描述】:

我正在从对PrintDlgEx() 的 WIN32 调用中获取选定的打印机托盘。这似乎在大多数时间都可以成功运行,但最近我在我的机器上添加了一台新打印机(DYMO LabelWriter 450),这导致我的简单软件失败。

经调查,DC_BINSDeviceCapabilities() 的调用返回 4294967295,而到目前为止我测试过的所有其他打印机都返回个位数的 bin 计数。

我的第一个倾向是在 bin 计数大于给定阈值(比如...20?)时省略 bin 名称,但我不喜欢这个解决方案。

打印机是否会为此返回最大UNSIGNED INT 值?只是驱动程序写得不好,还是有其他含义?或者我完全误解了预期的价值。

如果我必须写一个任意的上限,我会,但我想更好地理解为什么会出现这种情况。显然,这台打印机没有数十亿个不同的打印机托盘。

这是一个 MRE:

    HINSTANCE hinst = GetModuleHandle(NULL);
    HRESULT hResult;
    PRINTDLGEX pdx = {0};
    LPPRINTPAGERANGE pPageRanges = NULL;
    HWND hWndOwner = GetForegroundWindow();

    if(!hWndOwner){
        hWndOwner = GetDesktopWindow();
    }

    // Allocate an array of PRINTPAGERANGE structures.
    pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
    if(!pPageRanges){
        return wprintf(L"{\"error\": \"%s\"}", GetLastError()); // "Your computer does not have enough memory to complete this operation:"
    }

    //  Initialize the PRINTDLGEX structure.
    pdx.lStructSize = sizeof(PRINTDLGEX);
    pdx.hwndOwner = hWndOwner;
    pdx.hDevMode = NULL;
    pdx.hDevNames = NULL;
    pdx.hDC = NULL;
    pdx.Flags = PD_RETURNDC | PD_COLLATE;
    pdx.Flags2 = 0;
    pdx.ExclusionFlags = 0;
    pdx.nPageRanges = 0;
    pdx.nMaxPageRanges = 10;
    pdx.lpPageRanges = pPageRanges;
    pdx.nMinPage = 1;
    pdx.nMaxPage = 1000;
    pdx.nCopies = 1;
    pdx.hInstance = 0;
    pdx.lpPrintTemplateName = NULL;
    pdx.lpCallback = NULL;
    pdx.nPropertyPages = 0;
    pdx.lphPropertyPages = NULL;
    pdx.nStartPage = START_PAGE_GENERAL;
    pdx.dwResultAction = 0;

    //  Invoke the Print property sheet.
    hResult = PrintDlgEx(&pdx);

    DEVMODE * myDevMode     = (DEVMODE *)GlobalLock(pdx.hDevMode);
    DWORD binCount = DeviceCapabilities((CHAR*)myDevMode->dmDeviceName, nullptr, DC_BINS, nullptr, nullptr);
    DWORD binNameCount = DeviceCapabilities((CHAR*)myDevMode->dmDeviceName, nullptr, DC_BINNAMES, nullptr, nullptr);
    wprintf(L"\"binCount\":\"%lu\",", binCount);
    wprintf(L"\"binNameCount\":\"%lu\",", binNameCount);

【问题讨论】:

  • 在没有看到您的代码的情况下,很难回答有关为什么某些东西不能正常工作的问题。您应该发布一个 minimal reproducible example 来演示该问题。很有可能您只是在调用DeviceCapabilities 之前未能初始化某些内容。而且由于纸箱是物理纸盘,即使是大型打印机也很少有超过四个或五个。
  • @KenWhite - 谢谢。请注意,我不是在问为什么代码不起作用,而是在什么情况下打印机驱动程序会返回 4294967295 作为纸盘的数量。也许代码的原因,但我不相信。
  • 你输入的太多了。 :-) 如果您使用 ZeroMemory 将整个结构清零,然后只填充您正在使用的结构,您可以将 21 行代码(初始化 pdx 的代码)减少到 10 行。它还可以确保您不要错过任何东西。不过,我在您的代码中看不到任何明显的问题(除了它不是minimal reproducible example,因为它不完整)。
  • @Kenwhite - 我的代码完全有问题。现在把我的脚从嘴里拿出来:)
  • 是的,我看到 Remy 抓到了一些我没有抓到的东西,比你抓到的更多。 :-) 很高兴你把它整理好了。不过,我对ZeroMemory 的建议仍然适用。

标签: winapi printing


【解决方案1】:

DeviceCapabilities() 返回 已签名 int,而不是未签名 DWORD

无符号值4294967295 是十六进制0xFFFFFFFF,与有符号-1 是相同的数值。

根据DeviceCapabilities() 文档:

返回值

如果函数成功,返回值取决于fwCapability参数的设置。返回值为零通常表示,虽然功能成功完成,但存在某种类型的故障,例如不支持的功能。有关详细信息,请参阅 fwCapability 值的说明。

如果函数返回 -1,这可能意味着不支持该功能或存在一般函数故障。

您没有考虑到DeviceCapabilities() 失败(或者PrintDlgEx())的可能性。

试试这个:

HWND hWndOwner = GetForegroundWindow();
if (!hWndOwner){
    hWndOwner = GetDesktopWindow();
}

// Allocate an array of PRINTPAGERANGE structures.
LPPRINTPAGERANGE pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
if (!pPageRanges){
    // NOTE: GetLastError() returns DWORD, not TCHAR*! So, if you
    // want to translate the error code in a human-readable string,
    // use FormatMessage() instead...
    return wprintf(L"{\"error\": %lu}", GetLastError());
}

//  Initialize the PRINTDLGEX structure.
PRINTDLGEX pdx = {0};
pdx.lStructSize = sizeof(PRINTDLGEX);
pdx.hwndOwner = hWndOwner;
pdx.Flags = PD_RETURNDC | PD_COLLATE;
pdx.nMaxPageRanges = 10;
pdx.lpPageRanges = pPageRanges;
pdx.nMinPage = 1;
pdx.nMaxPage = 1000;
pdx.nCopies = 1;
pdx.nStartPage = START_PAGE_GENERAL;

HRESULT hResult = PrintDlgEx(&pdx);
if (hResult != S_OK)
{
    GlobalFree(reinterpret_cast<HGLOBAL>(pPageRanges));
    return wprintf(L"{\"error\": %d}", hResult);
}

if (pdx.dwResultAction == PD_RESULT_CANCEL)
{
    GlobalFree(reinterpret_cast<HGLOBAL>(pPageRanges));
    return wprintf(L"{\"error\": \"cancelled\"}");
}

DEVMODE *myDevMode = (DEVMODE*) GlobalLock(pdx.hDevMode);

int binCount = DeviceCapabilities(reinterpret_cast<TCHAR*>(myDevMode->dmDeviceName), nullptr, DC_BINS, nullptr, nullptr);
wprintf(L"\"binCount\":%d,", binCount);

int binNameCount = DeviceCapabilities(reinterpret_cast<TCHAR*>(myDevMode->dmDeviceName), 
nullptr, DC_BINNAMES, nullptr, nullptr);
wprintf(L"\"binNameCount\":%d,", binNameCount);

if (binCount == -1)
{
    ...
}

if (binNameCount == -1)
{
    ...
}

...

GlobalUnlock(pdx.hDevMode);
GlobalFree(reinterpret_cast<HGLOBAL>(pPageRanges));

return ...;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 2013-08-09
    相关资源
    最近更新 更多