Im trying to make getJob() working from printerspooler api in 64bit.
I use the following definition (as other people are using on SO)
[DllImport("winspool.drv", EntryPoint = "GetJob", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetJob([In] IntPtr hPrinter, [In] Int32 dwJobId, [In] Int32 Level, [Out] IntPtr lpJob, [In] Int32 cbBuf, ref IntPtr lpbSizeNeeded);
But this only works when im not debugging and i'm not in 64bit.
In 64 bit i get the windows Error: The parameter is incorrect.
How to i fix this?
I tried changing Int32 to IntPtr (4=>8 bytes in 64bit) and the reverse IntPtr => Int32. to no avail..
The docs are here: https://learn.microsoft.com/en-us/windows/desktop/printdocs/getjob:
BOOL GetJob(
_In_ HANDLE hPrinter,
_In_ DWORD JobId,
_In_ DWORD Level,
_Out_ LPBYTE pJob,
_In_ DWORD cbBuf,
_Out_ LPDWORD pcbNeeded
);
I also tried changing ref to out and putting ref/out to lpJob parameter but even this seems not to work.
What could I try next?
Edit
what seems to work is:
[DllImport("winspool.drv", EntryPoint = "GetJob", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetJob([In] IntPtr hPrinter, [In] Int32 dwJobId, [In] Int32 Level, [Out] byte[] lpJob, [In] Int32 cbBuf, ref Int32 lpbSizeNeeded);
and using it as follows:
public JOB_INFO_1(IntPtr hPrinter, Int32 dwJobId)
{
var BytesWritten = new Int32();
var ptBuf = new byte[0];
if (PrinterMonitorComponent.ComponentTraceSwitch.TraceVerbose)
Console.WriteLine("JOB_INFO_1 new(" + hPrinter.ToString() + "," + dwJobId.ToString() + ")");
// \\ Get the required buffer size
if (!UnsafeNativeMethods.GetJob(hPrinter, dwJobId, 1, ptBuf, 0, ref BytesWritten))
{
if (BytesWritten == 0)
{
var ex = new Win32Exception();
if (PrinterMonitorComponent.ComponentTraceSwitch.TraceError)
Console.WriteLine("{0} GetJob for JOB_INFO_1 failed on handle: {1} for job: {2} - {3}", this.GetType().ToString(), hPrinter, dwJobId, ex.Message);
throw ex;
}
}
// \\ Allocate a buffer the right size
if (BytesWritten > 0)
ptBuf = new byte[BytesWritten]; // Marshal.AllocHGlobal(BytesWritten);
//Console.WriteLine($"Buffer {BytesWritten} x"); // uncommenting this code somehow breaks it again -.-
// \\ Populate the JOB_INFO_1 structure
if (!UnsafeNativeMethods.GetJob(hPrinter, dwJobId, 1, ptBuf, BytesWritten, ref BytesWritten))
{
if (PrinterMonitorComponent.ComponentTraceSwitch.TraceError)
Console.WriteLine("GetJob for JOB_INFO_1 failed on handle: " + hPrinter.ToString() + " for job: " + dwJobId, this.GetType().ToString());
throw new Win32Exception();
}
else
{
GCHandle handle = GCHandle.Alloc(ptBuf, GCHandleType.Pinned);
Marshal.PtrToStructure(handle.AddrOfPinnedObject(), this);
handle.Free();
//Marshal.PtrToStructure(ptBuf, this);
}
// \\ Free the allocated memory
//Marshal.FreeHGlobal(ptBuf);
}
edit2
seems to not work, sometimes it seemd to work but unit test didn't notice changes in csproj file so i was still testing against 32 bit in the end.
adding following line to csproj makes it works (it runs in 32bit, putting it in 64bit, it fails)
<PlatformTarget>x86</PlatformTarget>
It seems to have been mostly an timing issue...
I was testing with a null printer, somehow in 32bits it mostly worked, but than going to 64bits something must have gone slower thats why it would fail, same for debugging.
The job would already ahve been spooled and thus requesting the job info is no longer available.
To fix this you can set: Keep printed documents.