使用后台打印程序监视打印作业 API
Monitoring a print job using Print Spooler API
我正在尝试使用 C# 中的后台打印程序 API 获取打印作业的一些数据。为此,我使用了以下代码片段。 (删除了错误处理)
public static int GetJobInfo(string printerUncName, int jobId)
{
var printerInfo2 = new PrinterInfo2();
var pHandle = new IntPtr();
var defaults = new PrinterDefaults();
try
{
//Open a handle to the printer
bool ok = OpenPrinter(printerUncName, out pHandle, IntPtr.Zero);
//Here we determine the size of the data we to be returned
//Passing in 0 for the size will force the function to return the size of the data requested
int actualDataSize = 0;
GetJobs(pHandle, jobId, 2, IntPtr.Zero, 0, ref actualDataSize);
int err = Marshal.GetLastWin32Error();
if (err == 122)// ERROR_INSUFFICIENT_BUFFER
{
if (actualDataSize > 0)
{
//Allocate memory to the size of the data requested
IntPtr printerData = Marshal.AllocHGlobal(actualDataSize);
//Retrieve the actual information this time
GetJobs(pHandle, jobId, 2, printerData, actualDataSize, ref actualDataSize);
//Marshal to our structure
printerInfo2 = (PrinterInfo2)Marshal.PtrToStructure(printerData, typeof(PrinterInfo2));
//We've made the conversion, now free up that memory
Marshal.FreeHGlobal(printerData);
}
}
}
finally
{
//Always close the handle to the printer
ClosePrinter(pHandle);
}
}
(取自)
为了解析来自 GetJobs 的指针 (printerData) returns,我使用以下 class.
public struct PrinterInfo2
{
public uint JobID;
[MarshalAs(UnmanagedType.LPTStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrinterName;
[MarshalAs(UnmanagedType.LPTStr)]
public string ShareName;
[MarshalAs(UnmanagedType.LPTStr)]
public string PortName;
[MarshalAs(UnmanagedType.LPTStr)]
public string DriverName;
[MarshalAs(UnmanagedType.LPTStr)]
public string Comment;
[MarshalAs(UnmanagedType.LPTStr)]
public string Location;
public IntPtr DevMode;
[MarshalAs(UnmanagedType.LPTStr)]
public string SepFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrintProcessor;
[MarshalAs(UnmanagedType.LPTStr)]
public string Datatype;
[MarshalAs(UnmanagedType.LPTStr)]
public string Parameters;
public IntPtr SecurityDescriptor;
public uint Attributes;
public uint Priority;
public uint DefaultPriority;
public uint StartTime;
public uint UntilTime;
public uint Status;
public uint Jobs;
public uint AveragePpm;
}
行 (PrinterInfo2)Marshal.PtrToStructure(printerData, typeof(PrinterInfo2)); returns 以下对象。
我不熟悉 Windows api 和 dll。可能我在创建解析器 class 时做错了什么。我怎样才能 return 来自 PtrToStructure 方法的有意义的信息?
编辑:GetJobs 定义
[DllImport("winspool.drv", SetLastError = true, EntryPoint = "GetJobA", CharSet = CharSet.Auto)]
public static extern bool GetJobs(
IntPtr printerHandle,
int jobId,
int Level,
IntPtr printerData,
int bufferSize,
ref int printerDataSize);
编辑 2:
我应用了 NetMage 的解决方案,但它也没有 return 编辑正确数量的 PagesPrinted 和 TotalPages。
(它 returned PagesPrinted = 2,TotalPages = 0 它应该是 PagesPrinted = 1,TotalPages = 2)
然后我意识到当我 运行 以下代码片段时 WMI 给出了相同的数字。
string searchQuery = "SELECT * FROM Win32_PrintJob";
ManagementObjectSearcher searchPrintJobs = new ManagementObjectSearcher(searchQuery);
ManagementObjectCollection prntJobCollection = searchPrintJobs.Get();
foreach (ManagementObject prntJob in prntJobCollection)
{
char[] splitArr = new char[1];
splitArr[0] = Convert.ToChar(",");
string prnterName = jobName.Split(splitArr)[0];
int prntJobID = Convert.ToInt32(jobName.Split(splitArr)[1]);
string documentName = prntJob.Properties["Document"].Value.ToString();
UInt32 jobSatus = (UInt32)prntJob.Properties["StatusMask"].Value;
UInt32 pagesPrinted = (UInt32)prntJob.Properties["PagesPrinted"].Value;
UInt32 totalPages = (UInt32)prntJob.Properties["TotalPages"].Value;
}
您的问题是您复制了 PRINTER_INFO_2
结构来创建 JOB_INFO_2
结构,但它们根本不一样。 JOB_INFO_2
需要以下结构:
[StructLayout(LayoutKind.Sequential)]
public struct SystemTime {
[MarshalAs(UnmanagedType.U2)] public short Year;
[MarshalAs(UnmanagedType.U2)] public short Month;
[MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
[MarshalAs(UnmanagedType.U2)] public short Day;
[MarshalAs(UnmanagedType.U2)] public short Hour;
[MarshalAs(UnmanagedType.U2)] public short Minute;
[MarshalAs(UnmanagedType.U2)] public short Second;
[MarshalAs(UnmanagedType.U2)] public short Milliseconds;
public SystemTime(DateTime dt) {
dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
Year = (short)dt.Year;
Month = (short)dt.Month;
DayOfWeek = (short)dt.DayOfWeek;
Day = (short)dt.Day;
Hour = (short)dt.Hour;
Minute = (short)dt.Minute;
Second = (short)dt.Second;
Milliseconds = (short)dt.Millisecond;
}
}
public struct JobInfo2 {
public uint JobID;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrinterName;
[MarshalAs(UnmanagedType.LPTStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string UserName;
[MarshalAs(UnmanagedType.LPTStr)]
public string DocumentName;
[MarshalAs(UnmanagedType.LPTStr)]
public string NotifyName;
[MarshalAs(UnmanagedType.LPTStr)]
public string DataType;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrintProcessor;
[MarshalAs(UnmanagedType.LPTStr)]
public string Parameters;
[MarshalAs(UnmanagedType.LPTStr)]
public string DriverName;
public IntPtr DevMode;
[MarshalAs(UnmanagedType.LPTStr)]
public string strStatus;
public IntPtr SecurityDescriptor;
public uint Status;
public uint Priority;
public uint Position;
public uint StartTime;
public uint UntilTime;
public uint TotalPages;
public uint Size;
public SystemTime Submitted;
public uint Time;
public uint PagesPrinted;
}
我正在尝试使用 C# 中的后台打印程序 API 获取打印作业的一些数据。为此,我使用了以下代码片段。 (删除了错误处理)
public static int GetJobInfo(string printerUncName, int jobId)
{
var printerInfo2 = new PrinterInfo2();
var pHandle = new IntPtr();
var defaults = new PrinterDefaults();
try
{
//Open a handle to the printer
bool ok = OpenPrinter(printerUncName, out pHandle, IntPtr.Zero);
//Here we determine the size of the data we to be returned
//Passing in 0 for the size will force the function to return the size of the data requested
int actualDataSize = 0;
GetJobs(pHandle, jobId, 2, IntPtr.Zero, 0, ref actualDataSize);
int err = Marshal.GetLastWin32Error();
if (err == 122)// ERROR_INSUFFICIENT_BUFFER
{
if (actualDataSize > 0)
{
//Allocate memory to the size of the data requested
IntPtr printerData = Marshal.AllocHGlobal(actualDataSize);
//Retrieve the actual information this time
GetJobs(pHandle, jobId, 2, printerData, actualDataSize, ref actualDataSize);
//Marshal to our structure
printerInfo2 = (PrinterInfo2)Marshal.PtrToStructure(printerData, typeof(PrinterInfo2));
//We've made the conversion, now free up that memory
Marshal.FreeHGlobal(printerData);
}
}
}
finally
{
//Always close the handle to the printer
ClosePrinter(pHandle);
}
}
(取自)
为了解析来自 GetJobs 的指针 (printerData) returns,我使用以下 class.
public struct PrinterInfo2
{
public uint JobID;
[MarshalAs(UnmanagedType.LPTStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrinterName;
[MarshalAs(UnmanagedType.LPTStr)]
public string ShareName;
[MarshalAs(UnmanagedType.LPTStr)]
public string PortName;
[MarshalAs(UnmanagedType.LPTStr)]
public string DriverName;
[MarshalAs(UnmanagedType.LPTStr)]
public string Comment;
[MarshalAs(UnmanagedType.LPTStr)]
public string Location;
public IntPtr DevMode;
[MarshalAs(UnmanagedType.LPTStr)]
public string SepFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrintProcessor;
[MarshalAs(UnmanagedType.LPTStr)]
public string Datatype;
[MarshalAs(UnmanagedType.LPTStr)]
public string Parameters;
public IntPtr SecurityDescriptor;
public uint Attributes;
public uint Priority;
public uint DefaultPriority;
public uint StartTime;
public uint UntilTime;
public uint Status;
public uint Jobs;
public uint AveragePpm;
}
行 (PrinterInfo2)Marshal.PtrToStructure(printerData, typeof(PrinterInfo2)); returns 以下对象。 我不熟悉 Windows api 和 dll。可能我在创建解析器 class 时做错了什么。我怎样才能 return 来自 PtrToStructure 方法的有意义的信息?
编辑:GetJobs 定义
[DllImport("winspool.drv", SetLastError = true, EntryPoint = "GetJobA", CharSet = CharSet.Auto)]
public static extern bool GetJobs(
IntPtr printerHandle,
int jobId,
int Level,
IntPtr printerData,
int bufferSize,
ref int printerDataSize);
编辑 2:
我应用了 NetMage 的解决方案,但它也没有 return 编辑正确数量的 PagesPrinted 和 TotalPages。 (它 returned PagesPrinted = 2,TotalPages = 0 它应该是 PagesPrinted = 1,TotalPages = 2) 然后我意识到当我 运行 以下代码片段时 WMI 给出了相同的数字。
string searchQuery = "SELECT * FROM Win32_PrintJob";
ManagementObjectSearcher searchPrintJobs = new ManagementObjectSearcher(searchQuery);
ManagementObjectCollection prntJobCollection = searchPrintJobs.Get();
foreach (ManagementObject prntJob in prntJobCollection)
{
char[] splitArr = new char[1];
splitArr[0] = Convert.ToChar(",");
string prnterName = jobName.Split(splitArr)[0];
int prntJobID = Convert.ToInt32(jobName.Split(splitArr)[1]);
string documentName = prntJob.Properties["Document"].Value.ToString();
UInt32 jobSatus = (UInt32)prntJob.Properties["StatusMask"].Value;
UInt32 pagesPrinted = (UInt32)prntJob.Properties["PagesPrinted"].Value;
UInt32 totalPages = (UInt32)prntJob.Properties["TotalPages"].Value;
}
您的问题是您复制了 PRINTER_INFO_2
结构来创建 JOB_INFO_2
结构,但它们根本不一样。 JOB_INFO_2
需要以下结构:
[StructLayout(LayoutKind.Sequential)]
public struct SystemTime {
[MarshalAs(UnmanagedType.U2)] public short Year;
[MarshalAs(UnmanagedType.U2)] public short Month;
[MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
[MarshalAs(UnmanagedType.U2)] public short Day;
[MarshalAs(UnmanagedType.U2)] public short Hour;
[MarshalAs(UnmanagedType.U2)] public short Minute;
[MarshalAs(UnmanagedType.U2)] public short Second;
[MarshalAs(UnmanagedType.U2)] public short Milliseconds;
public SystemTime(DateTime dt) {
dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
Year = (short)dt.Year;
Month = (short)dt.Month;
DayOfWeek = (short)dt.DayOfWeek;
Day = (short)dt.Day;
Hour = (short)dt.Hour;
Minute = (short)dt.Minute;
Second = (short)dt.Second;
Milliseconds = (short)dt.Millisecond;
}
}
public struct JobInfo2 {
public uint JobID;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrinterName;
[MarshalAs(UnmanagedType.LPTStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string UserName;
[MarshalAs(UnmanagedType.LPTStr)]
public string DocumentName;
[MarshalAs(UnmanagedType.LPTStr)]
public string NotifyName;
[MarshalAs(UnmanagedType.LPTStr)]
public string DataType;
[MarshalAs(UnmanagedType.LPTStr)]
public string PrintProcessor;
[MarshalAs(UnmanagedType.LPTStr)]
public string Parameters;
[MarshalAs(UnmanagedType.LPTStr)]
public string DriverName;
public IntPtr DevMode;
[MarshalAs(UnmanagedType.LPTStr)]
public string strStatus;
public IntPtr SecurityDescriptor;
public uint Status;
public uint Priority;
public uint Position;
public uint StartTime;
public uint UntilTime;
public uint TotalPages;
public uint Size;
public SystemTime Submitted;
public uint Time;
public uint PagesPrinted;
}