有时候需要修改打印机驱动的端口为本地文件,以方便对打印数据进行修改。
注:代码来源于互联网
1、枚举本地端口,查找是否有需要的本地文件端口(file_path)
LPBYTE p_port_info = 0; // 接收端口信息结构体数组指针
DWORD pcbNeeded = 0; // 缓冲区字节指针(必需)
DWORD pcReturned = 0; // 返回结果PORT_INFO_* 结构体缓冲区数量
if (EnumPortsA(NULL, 2, p_port_info, 0, &pcbNeeded, &pcReturned) && pcbNeeded != 0)
{
p_port = new BYTE[pcbNeeded];
if (!EnumPortsA(nullptr, 2, p_port_info, pcbNeeded, &pcbNeeded, &pcReturned))
{
PORT_INFO_2A* p_port_info_2 = (PORT_INFO_2A*)p_port_info;
for (DWORD i = 0; i < pcReturned; i++)
{
if (_stricmp(p_port_info_2[i].pPortName, file_path.c_str()) == 0)
{
b_found = true;
break;
}
}
}
delete[] p_port;
}
2、如果未找到本地文件(file_path)端口,则增加
HANDLE hXcv = nullptr;
PRINTER_DEFAULTSA pPrintDef;
memset(&pPrintDef, 0, sizeof(pPrintDef));
pPrintDef.DesiredAccess = SERVER_ACCESS_ADMINISTER;
WCHAR pszPortName[512] = {0};
WCHAR dwReturn[512];
DWORD cbNeeded;
DWORD dwStatus;
OpenPrinterA(",XcvMonitor Local Port", &hXcv, &pPrintDef);
if (hXcv == nullptr)
{
sprintf_s(error_info_, "Open XcvMonitor Local Port Error:%d", GetLastError());
return false;
}
wcscpy_s(pszPortName, CStrA2CStrW(file_path.c_str()).GetBuffer());
if (!XcvData(hXcv, L"AddPort", (PBYTE)pszPortName, (int)(wcslen(pszPortName) + 1) * sizeof(WCHAR),
(PBYTE)dwReturn, 0, &cbNeeded, &dwStatus) || dwStatus != 0) //注意这里使用宽字节
{
sprintf_s(error_info_, "Add Local Port Error:%d", GetLastError());
ClosePrinter(hXcv);
return false;
}
ClosePrinter(hXcv);
3、设置打印机的端口。
HANDLE hPrinter = nullptr;
PRINTER_DEFAULTSA pd = { 0 };
PRINTER_INFO_2A *p_info2 = nullptr;
DWORD pcbNeeded = 0; // 缓冲区字节指针(必需)
pd.DesiredAccess = PRINTER_ALL_ACCESS;
BOOL bFlag = OpenPrinterA(const_cast<char*>(printer_name.c_str()), &hPrinter, &pd);
if (!bFlag || (hPrinter == nullptr))
{
sprintf_s(error_info_, "Open Printer Error:%d", GetLastError());
return false;
}
bFlag = GetPrinterA(hPrinter, 2, 0, 0, &pcbNeeded);
if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
(pcbNeeded == 0))
{
sprintf_s(error_info_, "Get Printer Info Error:%d", GetLastError());
ClosePrinter(hPrinter);
return false;
}
// Allocate enough space for PRINTER_INFO_2...
p_info2 = (PRINTER_INFO_2A *)GlobalAlloc(GPTR, pcbNeeded);
if (p_info2 == nullptr)
{
sprintf_s(error_info_, "GlobalAlloc Error:%d", GetLastError());
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 = GetPrinterA(hPrinter, 2, (LPBYTE)p_info2, pcbNeeded, &pcbNeeded);
if (!bFlag)
{
GlobalFree(p_info2);
sprintf_s(error_info_, "Get Printer Info Error:%d", GetLastError());
ClosePrinter(hPrinter);
return false;
}
if (_stricmp(p_info2->pPortName, file_path.c_str()) == 0) //如果已经是本地文件端口,则退出
{
GlobalFree(p_info2);
ClosePrinter(hPrinter);
return true;
}
p_info2->pPortName = const_cast<char*>(file_path.c_str());
bFlag = SetPrinterA(hPrinter, 2, (LPBYTE)p_info2, 0);
if (!bFlag)
// The driver doesn't support, or it is unable to make the change...
{
GlobalFree(p_info2);
sprintf_s(error_info_, "Set Printer Info Error:%d", GetLastError());
ClosePrinter(hPrinter);
return false;
}
GlobalFree(p_info2);
ClosePrinter(hPrinter);
return true;