Ejemplo n.º 1
0
        /// <summary>
        /// Checks printer(s) for notifications.
        /// </summary>
        private void ListenForChanges()
        {
            // Check for cancellation.
            _cancelSource.Token.ThrowIfCancellationRequested();

            SafePrinterChangeNotificationHandle hChange = null;

            try
            {
                hChange = WaitForMultipleObjects(_hChanges);
            }
            catch (TimeoutException)
            {
                // No object changed within the timeout period.
                // This could mean that there was really no change,
                // or because the spooler is no longer sending updates to us.
                // Since we can't tell the difference, clean up existing structures and sign up for events again.

                // If the cancel token has been set, it might be a bit before we get back to checking it again,
                // so check it here before resetting.  If it has been set, bail out so the monitor can stop.
                _cancelSource.Token.ThrowIfCancellationRequested();

                LogDebug("No job changes detected.  Resetting listener.");
                Reset();
                Initialize();
                return;
            }
            catch (ArgumentOutOfRangeException ex)
            {
                // Unsuccessful in getting the change notification handle.  Bail out.
                LogDebug(ex);
                return;
            }

            // WaitForMultipleObjects could have taken a while, so check for cancellation again.
            _cancelSource.Token.ThrowIfCancellationRequested();

            // Get the notify information that changed.
            PrinterNotifyInfoReader infoReader = FindNextPrinterChangeNotification(hChange);

            if (infoReader == null)
            {
                LogDebug("Lost job data.  Trying a refresh.");
                infoReader = FindNextPrinterChangeNotification(hChange, _options);
            }

            using (infoReader)
            {
                foreach (PrinterNotifyInfoData infoData in infoReader.ReadInfoData())
                {
                    if (infoData.NotifyType == NotifyType.Job)
                    {
                        JobNotificationReceived?.Invoke(this, new JobNotificationEventArgs(infoData));
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a change notification object and returns a handle to the object.
        /// </summary>
        /// <param name="hPrinter">A handle to the printer or print server to monitor.</param>
        /// <param name="filter">The <see cref="PrinterChanges" /> that should trigger new events.</param>
        /// <param name="options">The <see cref="PrinterNotifyOptions" /> that dictate which notifications should be sent.</param>
        /// <returns>A handle to a change notification object associated with the specified printer or print server.</returns>
        /// <exception cref="Win32Exception">The underlying operation failed.</exception>
        private static SafePrinterChangeNotificationHandle FindFirstPrinterChangeNotification(SafePrinterHandle hPrinter, PrinterChanges filter, PrinterNotifyOptions options)
        {
            uint fdwOptions = 0; // Must always be zero for 2D printers.
            SafePrinterChangeNotificationHandle result = NativeMethods.FindFirstPrinterChangeNotification(hPrinter, (uint)filter, fdwOptions, ref options);

            if (Marshal.GetLastWin32Error() > 0)
            {
                throw new Win32Exception();
            }

            return(result);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Initializes all fields in the print job monitor.
        /// </summary>
        private void Initialize()
        {
            // In the event that the monitor is started while the spooler is offline,
            // keep retrying until the spooler becomes available.
            SafePrinterHandle hPrinter = null;

            while (true)
            {
                try
                {
                    void action() => hPrinter = OpenPrinter(null);

                    Retry.WhileThrowing <Win32Exception>(action, 5, TimeSpan.FromSeconds(30));
                    break;
                }
                catch (Win32Exception ex)
                {
                    switch (ex.NativeErrorCode)
                    {
                    // Ignore these errors.
                    case RPC_S_SERVER_UNAVAILABLE:
                    case RPC_S_CALL_FAILED:
                    case ERROR_INVALID_PRINTER_NAME:
                        Thread.Sleep(TimeSpan.FromSeconds(1));
                        break;

                    default:
                        throw;
                    }
                }
            }

            _options = CreatePrinterNotifyOptions();
            SafePrinterChangeNotificationHandle hChange = FindFirstPrinterChangeNotification(hPrinter, PrinterChanges.Job, _options);

            _hPrinters.Add(hPrinter);
            _hChanges.Add(hChange);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Retrieves information about the most recent notification for a change notification object associated with a printer or print server.
        /// Call this function when a wait operation on the change notification object is satisfed.
        /// </summary>
        /// <param name="hChange">A handle to a change notification object associated with a printer or print server.</param>
        /// <param name="options">The <see cref="PrinterNotifyOptions" />.</param>
        /// <returns>A <see cref="PrinterNotifyInfoReader" /> containing the notification details.</returns>
        /// <exception cref="Win32Exception">The underlying operation failed.</exception>
        /// <exception cref="System.Exception">
        /// No notification available at this time.
        /// or
        /// Info has been discarded.
        /// </exception>
        private static PrinterNotifyInfoReader FindNextPrinterChangeNotification(SafePrinterChangeNotificationHandle hChange, PrinterNotifyOptions options = new PrinterNotifyOptions())
        {
            if (!NativeMethods.FindNextPrinterChangeNotification(hChange, out _, ref options, out SafePrinterNotifyInfoHandle infoHandle))
            {
                throw new Win32Exception();
            }

            if (infoHandle == null || infoHandle.IsInvalid)
            {
                // Apparently there was no notification after all.  Just return an empty reader.
                return(new PrinterNotifyInfoReader());
            }

            PrinterNotifyInfoReader result = new PrinterNotifyInfoReader(infoHandle);

            // Check to see if data has been discarded.
            if (result.InfoDiscarded)
            {
                result.Dispose();
                return(null);
            }

            return(result);
        }
Ejemplo n.º 5
0
 internal static extern bool FindNextPrinterChangeNotification(SafePrinterChangeNotificationHandle hChange, [Out] out uint pdwChange, ref PrinterNotifyOptions pPrinterNotifyOptions, [Out] out SafePrinterNotifyInfoHandle ppPrinterNotifyInfo);