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分配内存,导致缓冲区结构不完整,参数不符合函数要求。
修正方案
关键思路
- 调用
GetPrinter()获取完整数据所需的总内存大小 - 一次性分配足够大的内存块,用于存储整个
PRINTER_INFO_2及所有关联数据 - 将内存块地址传给
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
相关产品推荐
相关产品推荐

