为什么 DC_BINS 的 DeviceCapabilities() return 4294967295?

Why might DeviceCapabilities() return 4294967295 for DC_BINS?

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

经调查,DC_BINSDeviceCapabilities() 的调用是 returning 4294967295,而到目前为止我测试过的所有其他打印机 return 个位数垃圾箱计数。

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

是否有已知原因打印机会为此 return 最大 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);

DeviceCapabilities() returns signed int,不是 unsigned DWORD.

无符号值 4294967295 是十六进制 0xFFFFFFFF,与有符号 -1.

的数值相同

根据 DeviceCapabilities() 文档:

Return value

If the function succeeds, the return value depends on the setting of the fwCapability parameter. A return value of zero generally indicates that, while the function completed successfully, there was some type of failure, such as a capability that is not supported. For more details, see the descriptions for the fwCapability values.

If the function returns -1, this may mean either that the capability is not supported or there was a general function failure.

您没有考虑 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 ...;