pro*_*ach 1 c# windows print-spooler-api
我从托管代码(C#)调用Win32函数EnumJobs(http://msdn.microsoft.com/en-us/library/windows/desktop/dd162625 (v=vs.85 ) .aspx ).
[DllImport("Winspool.drv", SetLastError = true, EntryPoint = "EnumJobsA")]
public static extern bool EnumJobs(
IntPtr hPrinter, // handle to printer object
UInt32 FirstJob, // index of first job
UInt32 NoJobs, // number of jobs to enumerate
UInt32 Level, // information level
IntPtr pJob, // job information buffer
UInt32 cbBuf, // size of job information buffer
out UInt32 pcbNeeded, // bytes received or required
out UInt32 pcReturned // number of jobs received
);
EnumJobs(_printerHandle, 0, 99, 1, IntPtr.Zero, 0, out nBytesNeeded, out pcReturned);
Run Code Online (Sandbox Code Playgroud)
我指定级别1接收JOB_INFO_1,但我遇到的问题是上面的函数返回nBytesNeeded为每个结构240个,而Marshal.SizeOf(typeof(JOB_INFO_1))
64个字节在我运行时导致内存异常Marshal.PtrToStructure
.手动为结构计算字节给出了64,所以我有点不知道为什么我从函数接收240字节结构,任何见解都会受到赞赏.
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet=CharSet.Unicode)]
public struct JOB_INFO_1
{
public UInt32 JobId;
public string pPrinterName;
public string pMachineName;
public string pUserName;
public string pDocument;
public string pDatatype;
public string pStatus;
public UInt32 Status;
public UInt32 Priority;
public UInt32 Position;
public UInt32 TotalPages;
public UInt32 PagesPrinted;
public SYSTEMTIME Submitted;
}
Run Code Online (Sandbox Code Playgroud)
大小64
确实是正确的,JOB_INFO_1
但如果仔细观察文档,它会讨论一组结构:
pJob [out]
A pointer to a buffer that receives an array of JOB_INFO_1, JOB_INFO_2, or JOB_INFO_3 structures.
Run Code Online (Sandbox Code Playgroud)
另外它写道:
The buffer must be large enough to receive the array of structures and any strings or other data to which the structure members point.
所以这里有一些字节用于结构本身旁边的额外数据.
解:
填充结构,增加下一个结构的指针并忽略剩余的字节.
完整的例子:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
namespace WpfApplication3
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
// Get handle to a printer
var hPrinter = new IntPtr();
bool open = NativeMethods.OpenPrinterW("Microsoft XPS Document Writer", ref hPrinter, IntPtr.Zero);
Debug.Assert(open);
/* Query for 99 jobs */
const uint firstJob = 0u;
const uint noJobs = 99u;
const uint level = 1u;
// Get byte size required for the function
uint needed;
uint returned;
bool b1 = NativeMethods.EnumJobsW(
hPrinter, firstJob, noJobs, level, IntPtr.Zero, 0, out needed, out returned);
Debug.Assert(!b1);
uint lastError = NativeMethods.GetLastError();
Debug.Assert(lastError == NativeConstants.ERROR_INSUFFICIENT_BUFFER);
// Populate the structs
IntPtr pJob = Marshal.AllocHGlobal((int) needed);
uint bytesCopied;
uint structsCopied;
bool b2 = NativeMethods.EnumJobsW(
hPrinter, firstJob, noJobs, level, pJob, needed, out bytesCopied, out structsCopied);
Debug.Assert(b2);
var jobInfos = new JOB_INFO_1W[structsCopied];
int sizeOf = Marshal.SizeOf(typeof (JOB_INFO_1W));
IntPtr pStruct = pJob;
for (int i = 0; i < structsCopied; i++)
{
var jobInfo_1W = (JOB_INFO_1W) Marshal.PtrToStructure(pStruct, typeof (JOB_INFO_1W));
jobInfos[i] = jobInfo_1W;
pStruct += sizeOf;
}
Marshal.FreeHGlobal(pJob);
// do something with your structs
}
}
public class NativeConstants
{
public const int ERROR_INSUFFICIENT_BUFFER = 122;
}
public partial class NativeMethods
{
[DllImport("kernel32.dll", EntryPoint = "GetLastError")]
public static extern uint GetLastError();
}
public partial class NativeMethods
{
[DllImport("Winspool.drv", EntryPoint = "OpenPrinterW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OpenPrinterW([In] [MarshalAs(UnmanagedType.LPWStr)] string pPrinterName,
ref IntPtr phPrinter, [In] IntPtr pDefault);
[DllImport("Winspool.drv", EntryPoint = "EnumJobsW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumJobsW([In] IntPtr hPrinter, uint FirstJob, uint NoJobs, uint Level, IntPtr pJob,
uint cbBuf, [Out] out uint pcbNeeded, [Out] out uint pcReturned);
}
[StructLayout(LayoutKind.Sequential)]
public struct JOB_INFO_1W
{
public uint JobId;
[MarshalAs(UnmanagedType.LPWStr)] public string pPrinterName;
[MarshalAs(UnmanagedType.LPWStr)] public string pMachineName;
[MarshalAs(UnmanagedType.LPWStr)] public string pUserName;
[MarshalAs(UnmanagedType.LPWStr)] public string pDocument;
[MarshalAs(UnmanagedType.LPWStr)] public string pDatatype;
[MarshalAs(UnmanagedType.LPWStr)] public string pStatus;
public uint Status;
public uint Priority;
public uint Position;
public uint TotalPages;
public uint PagesPrinted;
public SYSTEMTIME Submitted;
}
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
工作1:
工作2:
编辑
看起来你必须得到比我更强大的检查,因为EnumJobs
似乎true
在队列中没有作业时返回.在我的例子中,断言将失败,但这并不意味着代码是错误的; 只是确保队列中有一些作业用于测试功能.
归档时间: |
|
查看次数: |
1123 次 |
最近记录: |