如何在Windows上唯一标识打印队列,即使该队列已重命名
本文关键字:队列 重命名 打印 Windows 标识 唯一 | 更新日期: 2023-09-27 18:08:49
如何唯一可靠地识别给定服务器上的Windows打印队列,包括跨打印队列重命名?
我想处理如下情况:
- Jdoe创建打印机A
- 我的程序在某个点收集打印机A的信息
- Jdoe将打印机A重命名为打印机AA
- 我的程序在某个时刻再次收集打印机AA的信息
我怎么知道打印机A和打印机AA是同一台打印机(只是名称改变了)?
我想在c#中支持Windows XP/2003及更高版本。
我尝试过的事情:
在Windows 8/Server 2012上,似乎我可以通过WMI查看CIM_LogicalDevice->DeviceID来做到这一点,这似乎在重命名中保持一致,但在早期版本的操作系统中,此属性仅包含队列名称并在队列重命名时更改。
我也看了Win32_PnPEntity类(它不包含Windows 8之前的打印机)和Win32_Printer类(它不包含任何类型的ID除了名称)。
在注册表HKEY_LOCAL_MACHINE'SOFTWARE'Microsoft'Windows NT'CurrentVersion'Print'Printers[打印机名称]中有一个QueueInstanceId字段包含GUID,但仅适用于Windows 8/Server 2012。在早期的操作系统中不存在。
打印假脱机程序API和GDI打印API似乎都通过名称识别队列,所以我没有发现任何有用的东西。
下面是我在一个旧项目中用于确定打印机名称和驱动程序名称(以及打印机的其他一些细节)的一些代码。我不确定匹配司机的名字对你来说是否足够。我知道我已经在Win7上测试过了,我有80%的把握我在XP上测试过了(这是不久前的事了):
返回系统上的打印机名称/驱动程序名称的辅助方法:
public static List<PrinterDriverItem> GetCardPrinterList()
{
List<PrinterDriverItem> returnValue = new List<PrinterDriverItem>();
uint cbNeeded = 0;
uint cReturned = 0;
bool ret = Win32PrintApi.EnumPrinters(Win32PrintApi.PRINTER_ENUM_LOCAL, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned);
IntPtr addr = Marshal.AllocHGlobal((int)cbNeeded);
ret = Win32PrintApi.EnumPrinters(Win32PrintApi.PRINTER_ENUM_LOCAL, null, 2, addr, cbNeeded, ref cbNeeded, ref cReturned);
if (ret)
{
Win32PrintApi.PRINTER_INFO_2[] printerInfo = new Win32PrintApi.PRINTER_INFO_2[cReturned];
int offset = addr.ToInt32();
for (int i = 0; i < cReturned; i++)
{
printerInfo[i].pServerName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pPrinterName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pShareName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pPortName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pDriverName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pComment = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pLocation = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pDevMode = Marshal.ReadIntPtr(new IntPtr(offset));
offset += 4;
printerInfo[i].pSepFile = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pPrintProcessor = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pDatatype = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pParameters = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
offset += 4;
printerInfo[i].pSecurityDescriptor = Marshal.ReadIntPtr(new IntPtr(offset));
offset += 4;
printerInfo[i].Attributes = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].Priority = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].DefaultPriority = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].StartTime = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].UntilTime = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].Status = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].cJobs = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
printerInfo[i].AveragePPM = (uint)Marshal.ReadInt32(new IntPtr(offset));
offset += 4;
returnValue.Add(new PrinterDriverItem() { PrinterName = printerInfo[i].pPrinterName, DriverName = printerInfo[i].pDriverName });
}
}
Marshal.FreeHGlobal(addr);
return returnValue;
}
Win32PrintApi类:
public class Win32PrintApi
{
public const int PRINTER_ENUM_LOCAL = 0x00000002;
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool EnumPrinters(int Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned);
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_2
{
public string pServerName;
public string pPrinterName;
public string pShareName;
public string pPortName;
public string pDriverName;
public string pComment;
public string pLocation;
public IntPtr pDevMode;
public string pSepFile;
public string pPrintProcessor;
public string pDatatype;
public string pParameters;
public IntPtr pSecurityDescriptor;
public uint Attributes;
public uint Priority;
public uint DefaultPriority;
public uint StartTime;
public uint UntilTime;
public uint Status;
public uint cJobs;
public uint AveragePPM;
}
}
编辑:为了它的价值,我只是通过这段代码,看看我是否能找到任何独特的"看起来……对我来说,这些值大多数都是null或空白,但这里有一些东西:
Printer Name: XPS Card Printer - NEW
Driver Name: XPS Card Printer
Port Name: USB DXP01 Port
Attributes: 2624
DevMode: 3562584
不确定这是否有帮助
您需要使用的是setup类中的以下函数:
- SetupDiGetClassDevs
- SetupDiEnumDeviceInfo
- SetupDiGetDeviceRegistryProperty
- 硬件类id
这是我写的一个粗略的示例Cpp代码。无论打印机是本地/网络/重定向rdp打印机,硬件Id总是相同的,即使名称不同。
#include <Windows.h>
#include <stdio.h>
#include <SetupAPI.h>
#pragma comment(lib, "setupapi.lib")
void PrintPrinterIds(REFGUID ClassGuid)
{
HDEVINFO hDevInfo = SetupDiGetClassDevs(&ClassGuid, NULL, NULL, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
wprintf(L"Cannot get devices : %d'n", GetLastError());
return;
}
int idx = 0;
DWORD errorVal = ERROR_SUCCESS;
while (true)
{
SP_DEVINFO_DATA devInfoData = {};
WCHAR regProp[512];
devInfoData.cbSize = sizeof(devInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, idx, &devInfoData))
{
errorVal = GetLastError();
break;
}
if (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfoData,
SPDRP_FRIENDLYNAME,
NULL,
(PBYTE)regProp,
sizeof(regProp),
NULL))
{
errorVal = GetLastError();
break;
}
wprintf(L"Friendly name = %s'n", regProp);
if (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfoData,
SPDRP_HARDWAREID,
NULL,
(PBYTE)regProp,
sizeof(regProp),
NULL))
{
errorVal = GetLastError();
break;
}
// hardwareId is reg_multi_sz
// Print all of the hardware ids for this device
PWCHAR pId = regProp;
do
{
wprintf(L"HardwareId = %s'n", pId);
pId += wcslen(pId) + 1;
} while (pId[0] != 0);
// Point to next device
idx++;
}
if (errorVal != ERROR_NO_MORE_ITEMS)
{
printf("Error : %d'n", errorVal);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
int main()
{
// {4d36e979-e325-11ce-bfc1-08002be10318}
static const GUID PrinterClass =
{ 0x4d36e979, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
PrintPrinterIds(PrinterClass);
// L"{1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}"
static const GUID PrinterQueue =
{ 0x1ed2bbf9, 0x11f0, 0x4084, { 0xb2, 0x1f, 0xad, 0x83, 0xa8, 0xe6, 0xdc, 0xdc } };
PrintPrinterIds(PrinterQueue);
}