I have been attempting to trap printer events via the FindFirstPrinterChangeNotification and the FindNextPrinterChangeNotifcation. I am able to trap the event properly if a new job is added to the print queue, but I am unable to retrieve the PRINTER_NOFIFY_INFO and the PRINTER_NOTIFY_INFO_DATA properly after calling the FindNextPrinterChangeNotification. I have been looking at some of the samples in VB, but I am unable to get them to successfully work in C#. I believe the problem may be related to how I have my PRINTER_NOTIFY_INFO wrapper class layed out, in particular its association with the PRINTER_NOTIFY_INFO_DATA class. Any help is greatly appreciated....I have been struggling with this for more hours than I can count. Here is the code.......
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyOptionsType
{
public Int16 Type;
public Int16 wReserved0;
public Int32 dwReserved1;
public Int32 dwReserved2;
public Int32 FieldCount;
public IntPtr pFields;
public PrinterNotifyOptionsType(PrinterConstants.ChangeNotificationTypes printerNotificationTypes)
{
this.Type = (short) printerNotificationTypes;
pFields = Marshal.AllocHGlobal((16 * 2) - 1);
Marshal.WriteInt16(pFields, 0, (short) PrinterConstants.PrinterNotifyField.PRINTER_NOTIFY_FIELD_CJOBS);
FieldCount = 1;
}
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyOptions
{
public Int32 dwVersion;
public Int32 dwFlags;
public Int32 Count;
public IntPtr lpTypes;
public PrinterNotifyOptions()
{
dwVersion = 2;
Count = 1;
PrinterNotifyOptionsType pNotifyType = new PrinterNotifyOptionsType
(PrinterConstants.ChangeNotificationTypes.PRINTER_NOTIFY_TYPE);
lpTypes = Marshal.AllocHGlobal(Marshal.SizeOf(pNotifyType));
Marshal.StructureToPtr(pNotifyType, lpTypes, true);
}
}
[StructLayout(LayoutKind.Sequential)]
public class PRINTER_NOTIFY_INFO_DATA
{
public Int16 wType;
public Int16 wField;
public Int32 dwReserved;
public Int32 dwId;
public Int32 cbBuff;
public Int32 pBuff;
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyInfoData
{
private PRINTER_NOTIFY_INFO_DATA printerNotifyInfoData = new
PRINTER_NOTIFY_INFO_DATA();
public PrinterNotifyInfoData(IntPtr lpAddress)
{
if ( lpAddress.ToInt32() != 0)
{
Marshal.PtrToStructure(lpAddress, printerNotifyInfoData);
}
}
public Int16 Flags
{
get { return printerNotifyInfoData.wField; }
set { printerNotifyInfoData.wField = value; }
}
}
[StructLayout(LayoutKind.Sequential)]
public class PRINTER_NOTIFY_INFO
{
public Int16 wType;
public Int16 wField;
public Int32 dwReserved;
public Int32 version;
public Int32 Flags;
public Int32 Count;
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyInfo
{
private PRINTER_NOTIFY_INFO printerNotifyInfo = new PRINTER_NOTIFY_INFO();
public PrinterNotifyInfo(IntPtr lpAddress)
{
if ( lpAddress.ToInt32() != 0)
{
Marshal.PtrToStructure(lpAddress, printerNotifyInfo);
int lOffset = lpAddress.ToInt32() + Marshal.SizeOf(printerNotifyInfo);
for (int nInfoDataItem = 0; nInfoDataItem < 2; nInfoDataItem++)
{
PrinterNotifyInfoData printerNotifyInfoData = new PrinterNotifyInfoData(new IntPtr(lOffset));
lOffset = lOffset + Marshal.SizeOf(printerNotifyInfoData);
}
}
}
public Int32 Flags
{
get { return printerNotifyInfo.Flags; }
set { printerNotifyInfo.Flags = value; }
}
public Int32 Count
{
get { return printerNotifyInfo.Count; }
set { printerNotifyInfo.Count = value; }
}
}
//Registering for the event.............
IntPtr printerHandle = new IntPtr();
IntPtr eventHandle;
// Get the printer handle by opening the printer
if (Win32.OpenPrinter( printer.Name, ref printerHandle, IntPtr.Zero ))
{
//Specify what we want to be notified about...
printerNotifyOptions = new PrinterNotifyOptions();
Int32 flags = (int) PrinterConstants.PrinterChangeNotifications.
PRINTER_CHANGE_ADD_JOB;
// register the object for events
eventHandle = Win32.FindFirstPrinterChangeNotification(
printerHandle, flags, 0,
printerNotifyOptions);
if (!eventHandle.Equals(null))
{
printer.EventHandle = eventHandle;
this.ListenForEvents();
}
else
{
Marshal.GetLastWin32Error());
}
}
//Get the event details
long evtTriggered = new long();
PrinterNotifyInfo printerNotifyInfo;
IntPtr pPrinterNotifyInfo =
Marshal.AllocHGlobal( Marshal.SizeOf(typeof(PrinterNotifyInfo)) );
//A printer change notification has occured.....
if (Win32.FindNextPrinterChangeNotification(printer.EventHandle,
evtTriggered, printerNotifyOptions, pPrinterNotifyInfo) )
{
if (pPrinterNotifyInfo.ToInt32() != 0)
{
printerNotifyInfo = new PrinterNotifyInfo(pPrinterNotifyInfo);
//If the flags indicate that there was insufficient space to store all
//the changes we need to ask again
if ( (printerNotifyInfo.Flags & PrinterConstants.PRINTER_NOTIFY_INFO_DISCARDED) == 0)
{
printerNotifyOptions.dwFlags = printerNotifyOptions.dwFlags |
PrinterConstants.PRINTER_NOTIFY_OPTIONS_REFRESH;
evtTriggered = new long();
pPrinterNotifyInfo = new IntPtr();
Int32 count = printerNotifyInfo.Count;
pPrinterNotifyInfo = Marshal.AllocHGlobal( (Marshal.SizeOf(typeof(PrinterNotifyInfo))) +
((Marshal.SizeOf(typeof(PrinterNotifyInfoData))) * printerNotifyInfo.Count) );
Win32.FindNextPrinterChangeNotification(printer.EventHandle,
evtTriggered, printerNotifyOptions, pPrinterNotifyInfo);
if (!(Win32.FindNextPrinterChangeNotification(printer.EventHandle,
evtTriggered, printerNotifyOptions, pPrinterNotifyInfo) ) )
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
if (pPrinterNotifyInfo.ToInt32() != 0)
{
printerNotifyInfo = new PrinterNotifyInfo(pPrinterNotifyInfo);
}
else
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
}
}
else
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
}
else
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
}
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyOptionsType
{
public Int16 Type;
public Int16 wReserved0;
public Int32 dwReserved1;
public Int32 dwReserved2;
public Int32 FieldCount;
public IntPtr pFields;
public PrinterNotifyOptionsType(PrinterConstants.ChangeNotificationTypes printerNotificationTypes)
{
this.Type = (short) printerNotificationTypes;
pFields = Marshal.AllocHGlobal((16 * 2) - 1);
Marshal.WriteInt16(pFields, 0, (short) PrinterConstants.PrinterNotifyField.PRINTER_NOTIFY_FIELD_CJOBS);
FieldCount = 1;
}
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyOptions
{
public Int32 dwVersion;
public Int32 dwFlags;
public Int32 Count;
public IntPtr lpTypes;
public PrinterNotifyOptions()
{
dwVersion = 2;
Count = 1;
PrinterNotifyOptionsType pNotifyType = new PrinterNotifyOptionsType
(PrinterConstants.ChangeNotificationTypes.PRINTER_NOTIFY_TYPE);
lpTypes = Marshal.AllocHGlobal(Marshal.SizeOf(pNotifyType));
Marshal.StructureToPtr(pNotifyType, lpTypes, true);
}
}
[StructLayout(LayoutKind.Sequential)]
public class PRINTER_NOTIFY_INFO_DATA
{
public Int16 wType;
public Int16 wField;
public Int32 dwReserved;
public Int32 dwId;
public Int32 cbBuff;
public Int32 pBuff;
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyInfoData
{
private PRINTER_NOTIFY_INFO_DATA printerNotifyInfoData = new
PRINTER_NOTIFY_INFO_DATA();
public PrinterNotifyInfoData(IntPtr lpAddress)
{
if ( lpAddress.ToInt32() != 0)
{
Marshal.PtrToStructure(lpAddress, printerNotifyInfoData);
}
}
public Int16 Flags
{
get { return printerNotifyInfoData.wField; }
set { printerNotifyInfoData.wField = value; }
}
}
[StructLayout(LayoutKind.Sequential)]
public class PRINTER_NOTIFY_INFO
{
public Int16 wType;
public Int16 wField;
public Int32 dwReserved;
public Int32 version;
public Int32 Flags;
public Int32 Count;
}
[StructLayout(LayoutKind.Sequential)]
public class PrinterNotifyInfo
{
private PRINTER_NOTIFY_INFO printerNotifyInfo = new PRINTER_NOTIFY_INFO();
public PrinterNotifyInfo(IntPtr lpAddress)
{
if ( lpAddress.ToInt32() != 0)
{
Marshal.PtrToStructure(lpAddress, printerNotifyInfo);
int lOffset = lpAddress.ToInt32() + Marshal.SizeOf(printerNotifyInfo);
for (int nInfoDataItem = 0; nInfoDataItem < 2; nInfoDataItem++)
{
PrinterNotifyInfoData printerNotifyInfoData = new PrinterNotifyInfoData(new IntPtr(lOffset));
lOffset = lOffset + Marshal.SizeOf(printerNotifyInfoData);
}
}
}
public Int32 Flags
{
get { return printerNotifyInfo.Flags; }
set { printerNotifyInfo.Flags = value; }
}
public Int32 Count
{
get { return printerNotifyInfo.Count; }
set { printerNotifyInfo.Count = value; }
}
}
//Registering for the event.............
IntPtr printerHandle = new IntPtr();
IntPtr eventHandle;
// Get the printer handle by opening the printer
if (Win32.OpenPrinter( printer.Name, ref printerHandle, IntPtr.Zero ))
{
//Specify what we want to be notified about...
printerNotifyOptions = new PrinterNotifyOptions();
Int32 flags = (int) PrinterConstants.PrinterChangeNotifications.
PRINTER_CHANGE_ADD_JOB;
// register the object for events
eventHandle = Win32.FindFirstPrinterChangeNotification(
printerHandle, flags, 0,
printerNotifyOptions);
if (!eventHandle.Equals(null))
{
printer.EventHandle = eventHandle;
this.ListenForEvents();
}
else
{
Marshal.GetLastWin32Error());
}
}
//Get the event details
long evtTriggered = new long();
PrinterNotifyInfo printerNotifyInfo;
IntPtr pPrinterNotifyInfo =
Marshal.AllocHGlobal( Marshal.SizeOf(typeof(PrinterNotifyInfo)) );
//A printer change notification has occured.....
if (Win32.FindNextPrinterChangeNotification(printer.EventHandle,
evtTriggered, printerNotifyOptions, pPrinterNotifyInfo) )
{
if (pPrinterNotifyInfo.ToInt32() != 0)
{
printerNotifyInfo = new PrinterNotifyInfo(pPrinterNotifyInfo);
//If the flags indicate that there was insufficient space to store all
//the changes we need to ask again
if ( (printerNotifyInfo.Flags & PrinterConstants.PRINTER_NOTIFY_INFO_DISCARDED) == 0)
{
printerNotifyOptions.dwFlags = printerNotifyOptions.dwFlags |
PrinterConstants.PRINTER_NOTIFY_OPTIONS_REFRESH;
evtTriggered = new long();
pPrinterNotifyInfo = new IntPtr();
Int32 count = printerNotifyInfo.Count;
pPrinterNotifyInfo = Marshal.AllocHGlobal( (Marshal.SizeOf(typeof(PrinterNotifyInfo))) +
((Marshal.SizeOf(typeof(PrinterNotifyInfoData))) * printerNotifyInfo.Count) );
Win32.FindNextPrinterChangeNotification(printer.EventHandle,
evtTriggered, printerNotifyOptions, pPrinterNotifyInfo);
if (!(Win32.FindNextPrinterChangeNotification(printer.EventHandle,
evtTriggered, printerNotifyOptions, pPrinterNotifyInfo) ) )
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
if (pPrinterNotifyInfo.ToInt32() != 0)
{
printerNotifyInfo = new PrinterNotifyInfo(pPrinterNotifyInfo);
}
else
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
}
}
else
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
}
else
{
System.Console.WriteLine(Utilities.GetErrorMessage(Marshal.GetLastWin32Error()));
return;
}
}
}