private void DevLink_Received_CallBack(uint pbxh, StringBuilder rawDevLink)                     // CallEvent
        {
            // TODO: TRY - CATCH

            DEBUGLogger.WriteThreadInfo("DevLink_Received_CallBack");

            DEBUGLogger.WriteLine("pbxh=" + pbxh + ";  info=" + rawDevLink);

            _rawDevLinkQueue.Enqueue(new DevLinkMessage()
            {
                IpAddress = IpAddress, RawDevLink = rawDevLink.ToString(), SiteId = _iPOID
            });

            // Make thread-safe: since this method is a CallBack, it will be called by Avaya's DevLink code
            // in its's thread, which will be different from any of the possible subscriber's threads.
            // http://broadcast.oreilly.com/2010/09/understanding-c-raising-events.html
            var devLinkRecieved_threadSafe = DevLinkRecieved;

            // Multi-cast delegates are immutable, so whatever happens to DevLinkRecieved from here on will NOT affect devLinkRecieved_threadSafe
            if (devLinkRecieved_threadSafe != null)
            {
                devLinkRecieved_threadSafe(this, new DevLinkEventArgs((int)pbxh, rawDevLink.ToString()));

                // NOTE:
                // When an event fires, all of the registered handlers execute on the same thread (the one that raised the event -
                // in our case - the thread belongs to Avaya's DevLink!).
                // There's no built-in facility for events to fire on multiple threads.
                // http://stackoverflow.com/questions/3480036/multiple-threads-subscribing-same-event
            }
        }
        private void Process()
        {
            DEBUGLogger.WriteThreadInfo("Process");

            _handleDelta2Event = DevLink_Received_CallBack;

            /*This routine may return:-
             *      0 = DEVLINK_SUCCESS
             *      1 = DEVLINK_UNSPECIFIEDFAIL - Returned in the event of an error.
             *      2 = DEVLINK_LICENCENOTFOUND - If no CTI license is activated on the IP Office system. */
            long iRet = DLRegisterType2CallDeltas((uint)_iPOID, _handleDelta2Event // DLCALLLOGEVENT

                                                                                   /*	(pbxh, rawDevLink) => {	lock (thisLock)
                                                                                    *                                                      if (default(EventHandler<DevLinkEventArgs>) != DevLinkRecieved)
                                                                                    *                                                      {
                                                                                    *                                                              DevLinkRecieved(this, new DevLinkEventArgs(pbxh, rawDevLink));
                                                                                    *                                                      } }  */
                                                  );

            DEBUGLogger.WriteLine("DLRegisterType2CallDeltas return value = " + iRet);
        }
        /// <summary>
        /// DLOpen callback
        /// </summary>
        /// <param name="pbxh"></param>
        /// <param name="comms_state"></param>
        /// <param name="parm1"></param>
        private void DevLink_Connection_CallBack(uint pbxh, int comms_state, int parm1)                 // oCommsEvent   CommEvent
        {
            DEBUGLogger.WriteThreadInfo("DevLink_Connection_CallBack");

            // TODO: TRY - CATCH
            DEBUGLogger.WriteLine("DevLink_Connection_CallBack:   iPOID = " + pbxh + ";   comms_state = " + comms_state + ";   parm1 = " + parm1);
            if (_ignoreConnectionCallback)
            {
                return;                         // Whatever!
            }
            lock (_connectionLock)
            {
                if (_ignoreConnectionCallback)
                {
                    // It is too late, we have already given up on this method returning!
                    DEBUGLogger.WriteLine("DevLink_Connection_CallBack: Too late, the connection callback result (comms_state=" + comms_state + "; parm1=" + parm1 + ") is being ignored.");
                    return;
                }

                switch ((ConnectionResponse)comms_state)
                {
                // Communications established. This occurs either after the initial call to DLOpen(),
                // or after the  system unit has come back on-line after being powered off or rebooted.
                // TODO: does the above mean that this method will be called again if the system is rebooted...?? Think of how to handle this case!
                case ConnectionResponse.DEVLINK_COMMS_OPERATIONAL_0:
                {
                    ConnectionState = ConnectionStates.Connected;

                    // OK, we're done here, notify the main thread:
                    // TODO: what if this happens before the WaitOne call? OK I guess???
                    _waitConnectionOrTimeoutHandle.Set();
                    return;
                }

                // No response from system unit. This occurs either (1) after the initial call to DLOpen(), or
                // (2) if the system unit is powered off/rebooted, or (3) if network problems prevent communications.
                case ConnectionResponse.DEVLINK_COMMS_NORESPONSE_1:
                {
                    // TODO: LOG a message, and wait more for possible recovery.
                    ConnectionState = ConnectionStates.Failed;
                    return;
                }

                // Reserved for future use OR incorrect system password specified (????)
                case ConnectionResponse.DEVLINK_COMMS_REJECTED_2:
                {
                    _connectionCallbackMessage =
                        "Received response DEVLINK_COMMS_REJECTED - Reserved for future use! Do we have to implement this case too?";
                    break;
                }

                // Packets were generated by IPO, but were not received by DevLink.
                // This can occur either because the IPO is under heavy load (IPPO always prioritizes data routing and call handling above CTI events
                // - parm1 contains the number of packets missed)
                // or because the application using DevLink did not return from a callback quickly enough.
                // Applications should ensure that they do not take more than 100 milliseconds to process events.
                case ConnectionResponse.DEVLINK_COMMS_MISSEDPACKETS_3:
                {
                    _connectionCallbackMessage = "There are " + parm1 +
                                                 " lost packets! IPO may be under heavy load. Ensure that it takes no more than 100 ms to process events!";
                    break;
                }

                default:
                    _connectionCallbackMessage = "Ooops, got unexpected result! comms_state = " + comms_state;
                    break;
                }

                // Hmm, we were not able to connect successfully. We WON'T call _waitConnectionOrTimeoutHandle.Set() now, to give it some more time/chance to connect till the timeout.
                ConnectionState = ConnectionStates.Failed;
            }
        }