예제 #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));
                    }
                }
            }
        }
예제 #2
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);
        }