private static void ToPtr(IntPtr pos, NotifyOptions options) { PRINTER_NOTIFY_OPTIONS st; st.Flags = options.Flags; st.Count = (uint)options.Types.Count; st.Version = 2; st.pTypes = pos + Marshal.SizeOf <PRINTER_NOTIFY_OPTIONS>(); Marshal.StructureToPtr(st, pos, false); pos += Marshal.SizeOf <PRINTER_NOTIFY_OPTIONS>(); var fieldsPos = pos + (options.Types.Count * Marshal.SizeOf <PRINTER_NOTIFY_OPTIONS_TYPE>()); foreach (var optionsType in options.Types) { PRINTER_NOTIFY_OPTIONS_TYPE str = default; str.Type = (UInt16)optionsType.Type; str.Count = (UInt32)optionsType.Fields.Count; str.pFields = fieldsPos; Marshal.StructureToPtr(str, pos, false); pos += Marshal.SizeOf <PRINTER_NOTIFY_OPTIONS_TYPE>(); foreach (var field in optionsType.Fields) { Marshal.WriteInt32(fieldsPos, field); fieldsPos += Marshal.SizeOf(field.GetType()); } } }
private static int SizeOfNotifyOptions(NotifyOptions options) { var size = Marshal.SizeOf <PRINTER_NOTIFY_OPTIONS>(); foreach (var printerNotifyOptionsType in options.Types) { size += Marshal.SizeOf <PRINTER_NOTIFY_OPTIONS_TYPE>(); size += printerNotifyOptionsType.Fields.Count * Marshal.SizeOf <UInt32>(); } return(size); }
public static IChangeNotification Create(PRINTER_CHANGE changes, string printerName = null, PRINTER_NOTIFY_CATEGORY category = PRINTER_NOTIFY_CATEGORY.PRINTER_NOTIFY_CATEGORY_ALL, NotifyOptions options = null) { var notification = new ChangeNotification { _printerHandle = OpenPrinter(printerName) }; var ptrNotifyOptions = IntPtr.Zero; try { if (options != null) { var size = SizeOfNotifyOptions(options); ptrNotifyOptions = Marshal.AllocHGlobal(size); ToPtr(ptrNotifyOptions, options); } notification._changeHandle = NativeMethods.FindFirstPrinterChangeNotification( notification._printerHandle, (UInt32)changes, (UInt32)category, ptrNotifyOptions); if (notification._changeHandle == INVALID_HANDLE_VALUE) { throw new Win32Exception(); } // Don't let SafeWaitHandle own the handle as it can't close it notification.SafeWaitHandle = new SafeWaitHandle(notification._changeHandle, false); } catch { NativeMethods.ClosePrinter(notification._printerHandle); throw; } finally { Marshal.FreeHGlobal(ptrNotifyOptions); } return(notification); }