internal PrintJobChangeEventArgs(int intJobID, string unicJobId, string strJobName, JOBSTATUS jStatus, JobDetail detail, PrintSystemJobInfo objJobInfo)
 {
     _jobId         = intJobID;
     _jobName       = strJobName;
     _jobStatus     = jStatus;
     _jobInfo       = objJobInfo;
     _jobDetail     = detail;
     UnicIdentOfJob = unicJobId;
 }
        /// <summary>
        /// Отлавливается нужное задание и вызывается событие, на которое подписались в вызывающем коде
        /// </summary>
        /// <param name="state"></param>
        /// <param name="timedOut"></param>
        internal void PrinterNotifyWaitCallback(object state, bool timedOut)
        {
            if (_printerHandle == IntPtr.Zero)
            {
                return;
            }

            #region read notification details

            _notifyOptions.Count = 1;
            var    pdwChange = 0;
            IntPtr pNotifyInfo;
            var    bResult = FindNextPrinterChangeNotification(_changeHandle, out pdwChange, _notifyOptions,
                                                               out pNotifyInfo);
            _notifyOptions.dwFlags = 0;
            //If the Printer Change Notification Call did not give data, exit code
            if ((bResult == false) || (((int)pNotifyInfo) == 0))
            {
                return;
            }

            //If the Change Notification was not relgated to job, exit code
            var bJobRelatedChange = ((pdwChange & PRINTER_CHANGES.PRINTER_CHANGE_ADD_JOB) ==
                                     PRINTER_CHANGES.PRINTER_CHANGE_ADD_JOB) ||
                                    ((pdwChange & PRINTER_CHANGES.PRINTER_CHANGE_SET_JOB) ==
                                     PRINTER_CHANGES.PRINTER_CHANGE_SET_JOB) ||
                                    ((pdwChange & PRINTER_CHANGES.PRINTER_CHANGE_DELETE_JOB) ==
                                     PRINTER_CHANGES.PRINTER_CHANGE_DELETE_JOB) ||
                                    ((pdwChange & PRINTER_CHANGES.PRINTER_CHANGE_WRITE_JOB) ==
                                     PRINTER_CHANGES.PRINTER_CHANGE_WRITE_JOB);
            if (!bJobRelatedChange)
            {
                return;
            }

            #endregion

            #region populate Notification Information

            //Now, let us initialize and populate the Notify Info data
            var info  = (PRINTER_NOTIFY_INFO)Marshal.PtrToStructure(pNotifyInfo, typeof(PRINTER_NOTIFY_INFO));
            var pData = (long)pNotifyInfo + (long)Marshal.OffsetOf(typeof(PRINTER_NOTIFY_INFO), "aData");
            var data  = new PRINTER_NOTIFY_INFO_DATA[info.Count];
            for (uint i = 0; i < info.Count; i++)
            {
                data[i] =
                    (PRINTER_NOTIFY_INFO_DATA)Marshal.PtrToStructure((IntPtr)pData, typeof(PRINTER_NOTIFY_INFO_DATA));
                pData += Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO_DATA));
            }

            #endregion

            #region iterate through all elements in the data array

            for (var i = 0; i < data.Count(); i++)
            {
                if (data[i].Field == (ushort)PRINTERJOBNOTIFICATIONTYPES.JOB_NOTIFY_FIELD_STATUS
                    &&
                    (data[i].Type == (ushort)PRINTERNOTIFICATIONTYPES.JOB_NOTIFY_TYPE ||
                     data[i].Type == (ushort)PRINTERJOBNOTIFICATIONTYPES.JOB_NOTIFY_FIELD_TOTAL_PAGES)
                    )
                {
                    var jStatus = (JOBSTATUS)Enum.Parse(typeof(JOBSTATUS), data[i].NotifyData.Data.cbBuf.ToString());
                    if ((jStatus & JOBSTATUS.JOB_STATUS_DELETING) != 0 ||
                        (jStatus & JOBSTATUS.JOB_STATUS_DELETED) != 0 ||
                        (jStatus & JOBSTATUS.JOB_STATUS_ERROR) != 0)
                    {
                        return;
                    }

                    var                intJobId = (int)data[i].Id;
                    string             strJobName;
                    PrintSystemJobInfo pji = null;

                    try
                    {
                        _spooler = new PrintQueue(new PrintServer(), SpoolerName);
                        pji      = _spooler.GetJob(intJobId);
                        if (!_objJobDict.ContainsKey(intJobId))
                        {
                            _objJobDict[intJobId] = $"'n:{pji.Name}|js:{pji.JobStatus}|pn:{pji.NumberOfPages}|ji:{intJobId}|{Guid.NewGuid().ToString()}'";
                        }
                        strJobName = pji.Name;
                        pji.Refresh();
                    }
                    catch (Exception ex)
                    {
                        pji = null;
                        _objJobDict.TryGetValue(intJobId, out strJobName);
                        if (strJobName == null)
                        {
                            strJobName = string.Empty;
                        }

                        Registry.GetValue <Logger>().Error(ex, "When extract job");
                        return;
                    }

                    if (OnJobStatusChange != null)
                    {
                        //Let us raise the event calls: pqm_OnJobStatusChange
                        JobDetail jobDetails = GetJobDetail(data[i].Id);                                                                             //Get detalis about job
                        OnJobStatusChange(this, new PrintJobChangeEventArgs(intJobId, _objJobDict[intJobId], strJobName, jStatus, jobDetails, pji)); //Set pause for job
                    }
                }
            }

            #endregion

            #region reset the Event and wait for the next event

            _mrEvent.Reset();
            _waitHandle = ThreadPool.RegisterWaitForSingleObject(_mrEvent, PrinterNotifyWaitCallback, _mrEvent, -1, true);

            #endregion
        }