Monitoring WinSpool (HELP)

340 views
Skip to first unread message

Marcelo Barra

unread,
Mar 12, 2014, 10:10:25 AM3/12/14
to jna-...@googlegroups.com
Hello guys, sorry for my english.

I'm trying to write an application in JNA which monitoring the winspool using the Print Spooler API Functions.
I need to know when a job is sent to the spool, need job information (name, user which printed, printer name, machine name, number of pages printed, date, etc.)
For this I am using the FindFirstPrinterChangeNotification and FindNextPrinterChangeNotification functions. I happen to not knowing mapping and obtain the information through the object 
PRINTER_NOTIFY_INFO which contains an array of PRINTER_NOTIFY_INFO_DATA, where I believe I get this information.

Does anyone know how can I map and get information?

I'm using:
- Intel Core2 Duo CPU;
- windows 7 (64-bit);

Links to the functions (Print Spooler API Functions):


Mapping:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public interface WinSpool2 extends Winspool {
WinSpool2 INSTANCE = (WinSpool2) Native.loadLibrary("Winspool.drv", WinSpool2.class, W32APIOptions.UNICODE_OPTIONS);
...
HANDLE FindFirstPrinterChangeNotification(HANDLE hPrinter, int fdwFilter, int fdwOptions, Pointer pPrinterNotifyOptions);
boolean FindNextPrinterChangeNotification(HANDLE hChange, IntByReference pdwChange, Pointer pPrinterNotifyOptions, Pointer ppPrinterNotifyInfo);
public static class PRINTER_NOTIFY_OPTIONS extends Structure {
public static class ByReference extends PRINTER_NOTIFY_OPTIONS implements Structure.ByReference { }
public int Version;
public int Flags;
public int Count;
public PRINTER_NOTIFY_OPTIONS_TYPE.ByReference pTypes;
public PRINTER_NOTIFY_OPTIONS() {
}
public PRINTER_NOTIFY_OPTIONS(int size) {
super(new Memory(size));
}
public PRINTER_NOTIFY_OPTIONS(int Version, int Flags, int Count, PRINTER_NOTIFY_OPTIONS_TYPE.ByReference pTypes) {
this.Version = Version;
this.Flags = Flags;
this.Count = Count;
this.pTypes = pTypes;
}
@SuppressWarnings("rawtypes")
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[] {"Version", "Flags", "Count", "pTypes"});
}
}
public static class PRINTER_NOTIFY_OPTIONS_TYPE extends Structure {
public static class ByReference extends PRINTER_NOTIFY_OPTIONS_TYPE implements Structure.ByReference { }
public short Type;
public short Reserved0;
public int Reserved1;
public int Reserved2;
public int Count;
public Pointer pFields;
public PRINTER_NOTIFY_OPTIONS_TYPE() {
}
public PRINTER_NOTIFY_OPTIONS_TYPE(int size) {
super(new Memory(size));
}
@SuppressWarnings("rawtypes")
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[] {"Type","Reserved0","Reserved1","Reserved2","Count","pFields"});
}
}
public static class PRINTER_NOTIFY_INFO extends Structure {

public int Version;
public int Flags;
public int Count;
public PRINTER_NOTIFY_INFO_DATA[] aData = new PRINTER_NOTIFY_INFO_DATA[1];
public PRINTER_NOTIFY_INFO() {
super();
}
public PRINTER_NOTIFY_INFO(int Version, int Flags, int Count, PRINTER_NOTIFY_INFO_DATA aData[]) {
super();
this.Version = Version;
this.Flags = Flags;
this.Count = Count;
if ((aData.length != this.aData.length)) 
throw new IllegalArgumentException("Wrong array size !");
this.aData = aData;
}
public static class ByReference extends PRINTER_NOTIFY_INFO implements Structure.ByReference {}
public static class ByValue extends PRINTER_NOTIFY_INFO implements Structure.ByValue {}
@SuppressWarnings("rawtypes")
protected List getFieldOrder() {
return Arrays.asList("Version", "Flags", "Count", "aData");
}
}
public static class PRINTER_NOTIFY_INFO_DATA extends Structure {

public short Type;
public short Field;
public int Reserved;
public int Id;
public NotifyData_union NotifyData;
public static class NotifyData_union extends Union {
public int[] adwData = new int[2];
public Data_struct Data;
public static class Data_struct extends Structure {

public int cbBuf;
public PVOID pBuf;
public Data_struct() {
super();
}
public Data_struct(int cbBuf, PVOID pBuf) {
super();
this.cbBuf = cbBuf;
this.pBuf = pBuf;
}
protected List<? > getFieldOrder() {
return Arrays.asList("cbBuf", "pBuf");
}
public static class ByReference extends Data_struct implements Structure.ByReference {}
public static class ByValue extends Data_struct implements Structure.ByValue {}
}
public NotifyData_union() {
super();
}
public NotifyData_union(Data_struct Data) {
super();
this.Data = Data;
setType(Data_struct.class);
}
public NotifyData_union(int adwData[]) {
super();
if ((adwData.length != this.adwData.length)) 
throw new IllegalArgumentException("Wrong array size !");
this.adwData = adwData;
setType(int[].class);
}
public static class ByReference extends NotifyData_union implements Structure.ByReference {}
public static class ByValue extends NotifyData_union implements Structure.ByValue {}
}
public PRINTER_NOTIFY_INFO_DATA() {
super();
}
public PRINTER_NOTIFY_INFO_DATA(short Type, short Field, int Reserved, int Id, NotifyData_union NotifyData) {
super();
this.Type = Type;
this.Field = Field;
this.Reserved = Reserved;
this.Id = Id;
this.NotifyData = NotifyData;
}
public static class ByReference extends PRINTER_NOTIFY_INFO_DATA implements Structure.ByReference {}
public static class ByValue extends PRINTER_NOTIFY_INFO_DATA implements Structure.ByValue {}
@SuppressWarnings("rawtypes")
protected List getFieldOrder() {
return Arrays.asList("Type", "Field", "Reserved", "Id", "NotifyData");
}
}
int PRINTER_CHANGE_ADD_FORM = 0x00010000;
int PRINTER_CHANGE_SET_FORM = 0x00020000;
int PRINTER_CHANGE_DELETE_FORM = 0x00040000;
int PRINTER_CHANGE_FORM = 0x00070000;
int PRINTER_CHANGE_ADD_JOB = 0x00000100;
int PRINTER_CHANGE_SET_JOB = 0x00000200;
int PRINTER_CHANGE_DELETE_JOB = 0x00000400;
int PRINTER_CHANGE_WRITE_JOB = 0x00000800;
int PRINTER_CHANGE_JOB = 0x0000FF00;
int PRINTER_CHANGE_ADD_PORT = 0x00100000;
int PRINTER_CHANGE_CONFIGURE_PORT = 0x00200000;
int PRINTER_CHANGE_DELETE_PORT = 0x00400000;
int PRINTER_CHANGE_PORT = 0x00700000;
int PRINTER_CHANGE_ADD_PRINT_PROCESSOR = 0x01000000;
int PRINTER_CHANGE_DELETE_PRINT_PROCESSOR = 0x04000000;
int PRINTER_CHANGE_PRINT_PROCESSOR = 0x07000000;
int PRINTER_CHANGE_ADD_PRINTER = 0x00000001;
int PRINTER_CHANGE_SET_PRINTER = 0x00000002;
int PRINTER_CHANGE_DELETE_PRINTER = 0x00000004;
int PRINTER_CHANGE_FAILED_CONNECTION_PRINTER = 0x00000008;
int PRINTER_CHANGE_PRINTER = 0x000000FF;
int PRINTER_CHANGE_ADD_PRINTER_DRIVER = 0x10000000;
int PRINTER_CHANGE_SET_PRINTER_DRIVER = 0x20000000;
int PRINTER_CHANGE_DELETE_PRINTER_DRIVER = 0x40000000;
int PRINTER_CHANGE_PRINTER_DRIVER = 0x70000000;
int PRINTER_CHANGE_ALL = 0x7777FFFF;
}
public static void main(String[] args) {
...
PRINTER_NOTIFY_OPTIONS options = new PRINTER_NOTIFY_OPTIONS();
options.Flags = 1; //PRINTER_NOTIFY_OPTIONS_REFRESH
options.Version = 2;
HANDLE handle = WinSpool2.INSTANCE.FindFirstPrinterChangeNotification(handleByRef.getValue(), WinSpool2.PRINTER_CHANGE_ADD_JOB, 0, options.getPointer());
if(handle == null)
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
// Wait until you send a job to the print queue
if (Kernel32.INSTANCE.WaitForSingleObject(handle, WinBase.INFINITE) == WinBase.WAIT_OBJECT_0) {
// Job sent to print queue
IntByReference pdwChange = new IntByReference();
PRINTER_NOTIFY_INFO ppPrinterNotifyInfo = new PRINTER_NOTIFY_INFO();
if (WinSpool2.INSTANCE.FindNextPrinterChangeNotification(handle, pdwChange, options.getPointer(), ppPrinterNotifyInfo.getPointer())) {
PRINTER_NOTIFY_INFO_DATA jobData = ppPrinterNotifyInfo.aData[0];
System.out.println(jobData.Field); // NullPointerException
}
}

}

Daniel Doubrovkine

unread,
Mar 14, 2014, 8:10:02 AM3/14/14
to jna-...@googlegroups.com
The FindNextPrinterChangeNotification takes a pointer to a pointer that receives a system-allocated buffer. I think `options` needs to be passed in "as is", not as .getPointer, JNA will take care of marshalling that correctly, and the notify info should be a ByReference pointer type to the structure you expect back. Again, in neither case you should need to explicitly call getPointer.

If you add this to JNA proper with a test (even failing), and still can't figure it out, I'd be inclined to debug it :)


--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

dB. | Moscow - Geneva - Seattle - New York
code.dblock.org - @dblockdotorg - artsy.net - github/dblock

Marcelo Barra

unread,
Mar 19, 2014, 9:24:23 AM3/19/14
to jna-...@googlegroups.com
Thanks for your response Daniel, i´ll try this!

Marcelo Barra

unread,
Mar 24, 2014, 2:55:07 PM3/24/14
to jna-...@googlegroups.com
Hello Daniel, I changed my code to the following (in red), but still I am unable to get the results.

any help would be welcome:

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public interface WinSpool2 extends Winspool {
WinSpool2 INSTANCE = (WinSpool2) Native.loadLibrary("Winspool.drv", WinSpool2.class, W32APIOptions.UNICODE_OPTIONS);
...
HANDLE FindFirstPrinterChangeNotification(HANDLE hPrinter, int fdwFilter, int fdwOptions, PRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions);
boolean FindNextPrinterChangeNotification(HANDLE hChange, IntByReference pdwChange, PRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions, PRINTER_NOTIFY_INFO ppPrinterNotifyInfo);
HANDLE handle = WinSpool2.INSTANCE.FindFirstPrinterChangeNotification(handleByRef.getValue(), WinSpool2.PRINTER_CHANGE_ADD_JOB, 0, options);
if(handle == null)
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
// Wait until you send a job to the print queue
if (Kernel32.INSTANCE.WaitForSingleObject(handle, WinBase.INFINITE) == WinBase.WAIT_OBJECT_0) {
// Job sent to print queue
IntByReference pdwChange = new IntByReference();
PRINTER_NOTIFY_INFO ppPrinterNotifyInfo = new PRINTER_NOTIFY_INFO();
if (WinSpool2.INSTANCE.FindNextPrinterChangeNotification(handle, pdwChange, options, ppPrinterNotifyInfo)) {
PRINTER_NOTIFY_INFO_DATA jobData = ppPrinterNotifyInfo.aData[0];
System.out.println(jobData.Field); // stopped giving NullPointerException, but the ADATA field of PRINTER_NOTIFY_INFO object does not return the expected results, comes empty
}
}

}




--
You received this message because you are subscribed to a topic in the Google Groups "Java Native Access" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jna-users/V8gF2SaksG0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jna-users+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Atenciosamente,

Marcelo Barra

Daniel Doubrovkine

unread,
Mar 27, 2014, 7:19:08 AM3/27/14
to jna-...@googlegroups.com

Can you post a project with this that I can just run or, better, add to JNA tests? I can check it out.

wolf....@gmx.net

unread,
May 23, 2014, 4:00:08 AM5/23/14
to jna-...@googlegroups.com
I`ve added a sample project which shows exactly what you are looking for. Please take a look into "/jnalib/contrib/w32printing/src" for further details.

Marcelo Barra

unread,
May 23, 2014, 12:34:31 PM5/23/14
to jna-...@googlegroups.com
Thank you, I had already solved this problem and my solution was very similar to yours. 

Thanks again


--
You received this message because you are subscribed to a topic in the Google Groups "Java Native Access" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jna-users/V8gF2SaksG0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jna-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Atenciosamente,

Marcelo Barra

simone bello'

unread,
Aug 6, 2014, 4:41:46 AM8/6/14
to jna-...@googlegroups.com
Hello,
I've stumbled on the same issue Marcello had, and I was trying to get the code you posted (/jnalib/contrib/w32printing/src). 
Can you please give me an hint how to get that code? It would be really helpful!!

thanks,
Simone

Timothy Wall

unread,
Aug 6, 2014, 7:49:48 AM8/6/14
to jna-...@googlegroups.com
https://github.com/twall/jna/tree/master/contrib/w32printing/src
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages