我编写了一个 dll,它调用 windows spooler api 来获取打印机名称和打印机驱动程序名称,它在控制台应用程序中运行良好。但是,当我在 Windows 服务应用程序中调用 dll 时,我什么也没得到。
这是我的dll源代码(即printerUtility):
PRINTER_ENUM_LOCAL = 0x00000002,
PRINTER_ENUM_CONNECTIONS = 0x00000004,
public ArrayList getAllLocalPrinterInfo(LogWriter logger)
{
ArrayList printerInfoList = getAllLocalPrinterInfoV2(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_CONNECTIONS);
foreach (PrinterInfoV2 printerInfo in printerInfoList)
{
logger.write("In dll Printer Name pointer:" + printerInfo.pPrinterName+"\nIn dll Printer Name:" + Marshal.PtrToStringAnsi(printerInfo.pPrinterName));
logger.write("In dll Driver Name pointer:" + printerInfo.pDriverName+"\nIn dll Driver Name:" + Marshal.PtrToStringAnsi(printerInfo.pDriverName));
}
//return allLocalPrinterInfo;
return printerInfoList;
}
public ArrayList getAllLocalPrinterInfoV2(PrinterEnumFlags Flags)
{
return enumPrinters(Flags, 2);
}
private ArrayList enumPrinters(PrinterEnumFlags Flags, UInt32 level)
{
bool result;
ArrayList printerInfo = new ArrayList();
UInt32 returned, needed = 0;
UInt32 flags = Convert.ToUInt32(Flags);
//find required size for the buffer
result = EnumPrinters(flags, null, level, IntPtr.Zero, 0, out needed, out returned);
if (Marshal.GetLastWin32Error() != Convert.ToUInt32(CredUIReturnCodes.ERROR_INSUFFICIENT_BUFFER))
{
throw new Exception("EnumPrinters 1 failure, error code=" + Marshal.GetLastWin32Error());
}
else
{
IntPtr buffer = Marshal.AllocHGlobal((int)needed);
result = EnumPrinters(flags, null, level, buffer, needed, out needed, out returned);
if (result)
{
if ((level > 0) || (level < 5))
{
Type type = typeof(PrinterInfoV1);
switch (level)
{
case 1:
type = typeof(PrinterInfoV1);
break;
case 2:
type = typeof(PrinterInfoV2);
break;
case 3:
type = typeof(PrinterInfoV3);
break;
case 4:
type = typeof(PrinterInfoV4);
break;
}
int offset = buffer.ToInt32();
int increment = Marshal.SizeOf(type);
for (int i = 0; i < returned; i++)
{
printerInfo.Add(Marshal.PtrToStructure(new IntPtr(offset), type));
offset += increment;
}
Marshal.FreeHGlobal(buffer);
return printerInfo;
}
else
{
Marshal.FreeHGlobal(buffer);
throw new Exception("The value of level is out of range");
}
}
else
{
Marshal.FreeHGlobal(buffer);
throw new Exception("EnumPrinters 2 failure, error code=" + Marshal.GetLastWin32Error());
}
}
}
[DllImport("winspool.drv", SetLastError = true)]
static extern bool EnumPrinters([InAttribute()] UInt32 Flags,
[InAttribute()] string pPrinterName,
[InAttribute()] UInt32 Level,
[OutAttribute()] IntPtr pPrinter,
[InAttribute()] UInt32 cbBuf,
[OutAttribute()] out UInt32 pcbNeeded,
[OutAttribute()] out UInt32 pcReturned);
LogWriter 源代码:
public class LogWriter
{
EventLog eventLog = null;
public LogWriter(System.Diagnostics.EventLog elog)
{
this.eventLog = elog;
}
public void write(String msg)
{
if (eventLog != null)
{
eventLog.WriteEntry(msg);
}
}
}
这是服务源代码:
protected override void OnStart(string[] args)
{
serviceStatus.dwWaitHint = 100000;
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
printerMonitorList = new ArrayList();
try
{
ArrayList printerInfoList = printerUtility.getAllLocalPrinterInfo(logger);
foreach (PrinterInfoV2 printerInfo in printerInfoList)
{
logger.write("In service Printer Name pointer:" + printerInfo.pPrinterName+"\nIn service Printer Name:" + Marshal.PtrToStringAnsi(printerInfo.pPrinterName));
logger.write("In service Driver Name pointer:" + printerInfo.pDriverName+"\nIn service Driver Name:" + Marshal.PtrToStringAnsi(printerInfo.pDriverName));
}
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
logger.write(this.ServiceName + " Has Been Started");
}
catch (Exception err)
{
logger.write("Print Alert Service cannot be started:"+err.Message);
}
在事件查看器中,我得到了打印机名称和打印机驱动程序名称的空字符串。但是,我发现 dll 返回打印机名称和打印机驱动程序名称的指针。因此,我怀疑 Marshal.PtrToStringAnsi 函数是否在窗口服务环境中不起作用。