You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下使用C++获取打印机数据失败求助

获取打印机信息时GetPrinter()报错(错误码87/未知异常)的解决方向

在Windows 10的Visual Studio控制台项目中调用GetPrinter()获取打印机信息时,遇到两个问题:要么抛出未知类型异常,要么调用失败且GetLastError()返回错误码87。原代码如下:

int main()
{
    PRINTER_DEFAULTS pd = {};
    pd.DesiredAccess = PRINTER_ALL_ACCESS;

    HANDLE hPrinter;
    WCHAR pname[] = L"KONICA MINOLTA C368SeriesPCL";
    if (OpenPrinter( pname, &hPrinter, &pd) == 0) {
        return 1;
    }

    PRINTER_INFO_2 printerInfo = {};
    
    DWORD bytesNeeded = 0;
    GetPrinter(hPrinter, 2, 0, 0, &bytesNeeded); 
    // bytesNeeded is now aprox 9k

    printerInfo.pDevMode = (DEVMODE*)GlobalAlloc(GPTR, bytesNeeded); // pointer seems valid

    /* uncommending this call throws an exception - do not kno why */
//    if( !GetPrinter(hPrinter, 2, (LPBYTE)&printerInfo, bytesNeeded, &bytesNeeded))
//        return 1;

    /* this call does not throw but fails with GetLastError() returing 87 */
    if (!GetPrinter(hPrinter, 2, (LPBYTE)&printerInfo, bytesNeeded, NULL))
        return 1;
 
   return(0)
}

问题核心原因

错误码87对应ERROR_INVALID_PARAMETER,本质是内存分配逻辑错误:
PRINTER_INFO_2结构体包含多个指针字段(如pDevMode、pPrinterName、pComment等),第一次调用GetPrinter()得到的bytesNeeded是整个结构体+所有关联数据(字符串、DEVMODE等)的总大小,你只单独给pDevMode分配内存,导致缓冲区结构不完整,参数不符合函数要求。

修正方案

关键思路

  1. 调用GetPrinter()获取完整数据所需的总内存大小
  2. 一次性分配足够大的内存块,用于存储整个PRINTER_INFO_2及所有关联数据
  3. 将内存块地址传给GetPrinter(),完成数据读取

修正后代码

int main()
{
    PRINTER_DEFAULTS pd = {};
    // 按需降低权限,避免权限过高导致的问题
    pd.DesiredAccess = PRINTER_ACCESS_USE;

    HANDLE hPrinter;
    WCHAR pname[] = L"KONICA MINOLTA C368SeriesPCL";
    if (OpenPrinter(pname, &hPrinter, &pd) == 0) {
        return 1;
    }

    DWORD bytesNeeded = 0;
    // 第一次调用获取总内存需求,忽略ERROR_INSUFFICIENT_BUFFER错误
    if (!GetPrinter(hPrinter, 2, NULL, 0, &bytesNeeded)) {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
            ClosePrinter(hPrinter);
            return 1;
        }
    }

    // 分配完整的内存块
    PRINTER_INFO_2* pPrinterInfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, bytesNeeded);
    if (!pPrinterInfo) {
        ClosePrinter(hPrinter);
        return 1;
    }

    // 第二次调用读取完整打印机信息
    if (!GetPrinter(hPrinter, 2, (LPBYTE)pPrinterInfo, bytesNeeded, &bytesNeeded)) {
        GlobalFree(pPrinterInfo);
        ClosePrinter(hPrinter);
        return 1;
    }

    // 使用打印机信息示例
    wprintf(L"打印机名称:%s\n", pPrinterInfo->pPrinterName);
    wprintf(L"打印机状态:%u\n", pPrinterInfo->Status);

    // 释放资源
    GlobalFree(pPrinterInfo);
    ClosePrinter(hPrinter);
 
    return 0;
}

额外注意事项

  • 避免使用过高权限:PRINTER_ALL_ACCESS权限要求较高,实际按需使用PRINTER_ACCESS_USE或PRINTER_ACCESS_ADMINISTER即可
  • 资源释放:必须手动释放分配的内存和关闭打印机句柄,防止资源泄漏
  • 异常处理:第一次调用GetPrinter()必然返回失败(因为缓冲区为0),只需判断错误码是否为ERROR_INSUFFICIENT_BUFFER即可

内容的提问来源于stack exchange,提问作者affenärschle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:36:21