public virtual void StartAdvise(string item, int format, bool hot, bool acknowledge, int timeout, object adviseState)
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().ToString());
            }
            if (!IsConnected)
            {
                throw new InvalidOperationException(Resources.NotConnectedMessage);
            }
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (item.Length > Ddeml.MAX_STRING_SIZE)
            {
                throw new ArgumentException(Resources.StringParameterInvalidMessage, "item");
            }
            if (timeout <= 0)
            {
                throw new ArgumentException(Resources.TimeoutParameterInvalidMessage, "timeout");
            }
            if (_AdviseLoopTable.ContainsKey(item))
            {
                string message = Resources.AlreadyBeingAdvisedMessage;
                message = message.Replace("${service}", _Service);
                message = message.Replace("${topic}", _Topic);
                message = message.Replace("${item}", item);
                throw new InvalidOperationException(message);
            }

            // Create a AdviseLoop object to associate with this advise loop and add it to the advise loop table.
            // The object is added to the advise loop table first because an advisory could come in synchronously during the call
            // DdeClientTransaction.  The assumption is that the advise loop will be initiated successfully.  If it is not then the object must
            // be removed from the advise loop table prior to leaving this method.
            AdviseLoop adviseLoop = new AdviseLoop(this);
            adviseLoop.Item = item;
            adviseLoop.Format = format;
            adviseLoop.State = adviseState;
            _AdviseLoopTable.Add(item, adviseLoop);

            // Determine whether the client should acknowledge an advisory before the server posts another.
            bool ack = acknowledge;

            // Create a string handle for the item name.
            IntPtr itemHandle = Ddeml.DdeCreateStringHandle(_InstanceId, item, Ddeml.CP_WINANSI);

            // Initiate an advise loop.
            int type = Ddeml.XTYP_ADVSTART;
            type = !hot ? type | Ddeml.XTYPF_NODATA : type;
            type =  ack ? type | Ddeml.XTYPF_ACKREQ : type;
            int returnFlags = 0;
            IntPtr result = Ddeml.DdeClientTransaction(
                IntPtr.Zero,
                0,
                _ConversationHandle,
                itemHandle,
                format,
                type,
                timeout,
                ref returnFlags);

            // Free the string handle created earlier.
            Ddeml.DdeFreeStringHandle(_InstanceId, itemHandle);

            // If the result is null then the server did not initate the advise loop.
            if (result == IntPtr.Zero)
            {
                // Remove the AdviseLoop object created earlier from the advise loop table.  It is no longer valid.
                _AdviseLoopTable.Remove(item);

                int error = Ddeml.DdeGetLastError(_InstanceId);
                string message = Resources.StartAdviseFailedMessage;
                message = message.Replace("${service}", _Service);
                message = message.Replace("${topic}", _Topic);
                message = message.Replace("${item}", item);
                throw new DdemlException(message, error);
            }
        }
            protected override IntPtr ProcessCallback(
                int uType, int uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, IntPtr dwData1, IntPtr dwData2)
            {
                // If the data handle is null then the server did not initiate the advise loop.
                if (hData == IntPtr.Zero)
                {
                    string message = Resources.StartAdviseFailedMessage;
                    message = message.Replace("${service}", this.Client._Service);
                    message = message.Replace("${topic}", this.Client._Topic);
                    message = message.Replace("${item}", _Item);
                    this.ExceptionObject = new DdemlException(message);
                }
                else
                {
                    // Create a AdviseLoop object to associate with this advise loop and add it to the owner's advise loop table.
                    AdviseLoop adviseLoop = new AdviseLoop(this.Client);
                    adviseLoop.Item = _Item;
                    adviseLoop.Format = _Format;
                    adviseLoop.State = _State;
                    this.Client._AdviseLoopTable.Add(_Item, adviseLoop);
                }

                // Return zero to indicate that there are no problems.
                return IntPtr.Zero;
            }