BeginGetRequest(
            AsyncCallback requestCallback,
            Object stateObject)
        {
            //
            // Validation
            //

            if (m_AppPoolHandle == NativeMethods.INVALID_HANDLE_VALUE)
            {
                throw new InvalidOperationException("The AppPool handle is invalid");
            }

            //
            // prepare the ListenerAsyncResult object ( this will have it's own
            // event that the user can wait on for IO completion - which means we
            // need to signal it when IO completes )
            //

            GlobalLog.Print("BeginGetRequest() creating ListenerAsyncResult");

            ListenerAsyncResult AResult = new ListenerAsyncResult(
                stateObject,
                requestCallback);

            AutoResetEvent m_Event = new AutoResetEvent(false);

            Marshal.WriteIntPtr(
                AResult.m_Overlapped,
                Win32.OverlappedhEventOffset,
                m_Event.Handle);

            //
            // issue unmanaged call until we read enough data:
            // usually starting with a InitialBufferSize==4096 bytes we should be
            // able to get all the headers ( and part of the entity body, if any
            // is present ), if we don't, if the call didn't fail for othe reasons,
            // we get indication in BytesReturned, on how big the buffer should be
            // to receive the data available, so usually the second call will
            // succeed, but we have to consider the case of two competing calls
            // for the same RequestId, and that's why we need a loop and not just
            // a try/retry-expecting-success fashion
            //

            int result;

            for (;;)
            {
                //
                // check if we're in a healthy state
                //
                if (AResult.m_Retries++ > m_MaxRetries)
                {
                    throw new InvalidOperationException("UlReceiveHttpRequest() Too many retries");
                }

                result =
                    ComNetOS.IsWinNt ?

                    UlSysApi.UlReceiveHttpRequest(
                        m_AppPoolHandle,
                        AResult.m_RequestId,
                        UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY,
                        AResult.m_Buffer,
                        AResult.m_BufferSize,
                        ref AResult.m_BytesReturned,
                        AResult.m_Overlapped)

                :

                    UlVxdApi.UlReceiveHttpRequestHeaders(
                        m_AppPoolHandle,
                        AResult.m_RequestId,
                        0,
                        AResult.m_Buffer,
                        AResult.m_BufferSize,
                        ref AResult.m_BytesReturned,
                        AResult.m_Overlapped);

                GlobalLog.Print("UlReceiveHttpRequest() returns:"
                                + Convert.ToString(result));

                if (result == NativeMethods.ERROR_SUCCESS || result == NativeMethods.ERROR_IO_PENDING)
                {
                    //
                    // synchronous success or successfull pending: we are done
                    //

                    break;
                }

                if (result == NativeMethods.ERROR_INVALID_PARAMETER)
                {
                    //
                    // we might get this if somebody stole our RequestId,
                    // set RequestId to null
                    //

                    AResult.m_RequestId = 0;

                    //
                    // and start all over again with the buffer we
                    // just allocated
                    //

                    continue;
                }

                if (result == NativeMethods.ERROR_MORE_DATA)
                {
                    //
                    // the buffer was not big enough to fit the headers, we need
                    // to read the RequestId returned, grow the buffer, keeping
                    // the data already transferred
                    //

                    AResult.m_RequestId = Marshal.ReadInt64(IntPtrHelper.Add(AResult.m_Buffer, m_RequestIdOffset));

                    //
                    // allocate a new buffer of the required size
                    //

                    IntPtr NewBuffer = Marshal.AllocHGlobal(AResult.m_BytesReturned);

                    //
                    // copy the data already read from the old buffer into the
                    // new one
                    //

                    NativeMethods.CopyMemory(NewBuffer, AResult.m_Buffer, AResult.m_BufferSize);


                    //
                    // free the old buffer
                    //

                    Marshal.FreeHGlobal(AResult.m_Buffer);

                    //
                    // update buffer pointer and size
                    //

                    AResult.m_Buffer        = NewBuffer;
                    AResult.m_BufferSize    = AResult.m_BytesReturned;
                    AResult.m_BytesReturned = 0;

                    //
                    // and start all over again with the new buffer
                    //

                    continue;
                }

                //
                // someother bad error, possible( ? ) return values are:
                //
                // ERROR_INVALID_HANDLE
                // ERROR_INSUFFICIENT_BUFFER
                // ERROR_OPERATION_ABORTED
                // ERROR_IO_PENDING
                //

                throw new InvalidOperationException("UlReceiveHttpRequest() failed, err#" + Convert.ToString(result));
            }

            //
            // we get here only if a break happens, i.e.
            // 1) syncronous completion
            // 2) the IO pended
            //

            if (result == NativeMethods.ERROR_SUCCESS)
            {
                //
                // set syncronous completion to true
                //

                AResult.Complete(true);

                //
                // and call the internal callback
                //

                WaitCallback(AResult, false);
            }
            else
            {
                //
                // create a new delegate
                // and spin a new thread from the thread pool to wake up when the
                // event is signaled and call the delegate
                //

                ThreadPool.RegisterWaitForSingleObject(
                    m_Event,
                    new WaitOrTimerCallback(WaitCallback),
                    AResult,
                    -1,
                    true);
            }

            GlobalLog.Print("returning AResult");

            return(AResult);
        } // StartListen()
        GetRequest()
        {
            //
            // Validation
            //

            if (m_AppPoolHandle == NativeMethods.INVALID_HANDLE_VALUE)
            {
                throw new InvalidOperationException("The AppPool handle is invalid");
            }

            int result;

            int retries = 0;

            //
            // defined in ulcommonapi.cs
            //

            int RcvHeadersBufferSize = UlConstants.InitialBufferSize;

            //
            // prepare ( allocate/pin ) buffers and data for the first unmanaged call
            //

            GCHandle PinnedBuffer;
            GCHandle NewPinnedBuffer;

            IntPtr AddrOfPinnedBuffer    = IntPtr.Zero;
            IntPtr NewAddrOfPinnedBuffer = IntPtr.Zero;

            int  BytesReturned = 0;
            long RequestId     = 0;

            byte[] RcvHeadersBuffer = new byte[RcvHeadersBufferSize];

            //
            // pin buffers and data for the unmanaged call
            //

            PinnedBuffer       = GCHandle.Alloc(RcvHeadersBuffer, GCHandleType.Pinned);
            AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject();

            //
            // issue unmanaged blocking call until we read enough data:
            // usually starting with a InitialBufferSize==4096 bytes we should be
            // able to get all the headers ( and part of the entity body, if any
            // is present ), if we don't, if the call didn't fail for othe reasons,
            // we get indication in BytesReturned, on how big the buffer should be
            // to receive the data available, so usually the second call will
            // succeed, but we have to consider the case of two competing calls
            // for the same RequestId, and that's why we need a loop and not just
            // a try/retry-expecting-success fashion
            //

            for (;;)
            {
                //
                // check if we're in a healthy state
                //
                if (retries++ > m_MaxRetries)
                {
                    throw new InvalidOperationException("UlReceiveHttpRequest() Too many retries");
                }

                result =
                    ComNetOS.IsWinNt ?

                    UlSysApi.UlReceiveHttpRequest(
                        m_AppPoolHandle,
                        RequestId,
                        UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY,
                        AddrOfPinnedBuffer,
                        RcvHeadersBufferSize,
                        ref BytesReturned,
                        IntPtr.Zero)

                :

                    UlVxdApi.UlReceiveHttpRequestHeaders(
                        m_AppPoolHandle,
                        RequestId,
                        0,
                        AddrOfPinnedBuffer,
                        RcvHeadersBufferSize,
                        ref BytesReturned,
                        IntPtr.Zero);

                if (result == NativeMethods.ERROR_SUCCESS)
                {
                    //
                    // success, we are done.
                    //

                    break;
                }

                if (result == NativeMethods.ERROR_INVALID_PARAMETER)
                {
                    //
                    // we might get this if somebody stole our RequestId,
                    // set RequestId to null
                    //

                    RequestId = 0;

                    //
                    // and start all over again with the buffer we
                    // just allocated
                    //

                    continue;
                }

                //
                // let's check if ul is in good shape:
                //

                if (BytesReturned < RcvHeadersBufferSize)
                {
                    throw new InvalidOperationException("UlReceiveHttpRequest() sent bogus BytesReturned: " + Convert.ToString(BytesReturned));
                }

                if (result == NativeMethods.ERROR_MORE_DATA)
                {
                    //
                    // the buffer was not big enough to fit the headers, we need
                    // to read the RequestId returned, grow the buffer, keeping
                    // the data already transferred
                    //

                    RequestId = Marshal.ReadInt64(IntPtrHelper.Add(AddrOfPinnedBuffer, m_RequestIdOffset));

                    //
                    // CODEWORK: wait for the answer from LarrySu
                    //

                    //
                    // if the buffer size was too small, grow the buffer
                    // this reallocation dereferences the old buffer, but since
                    // this was previously pinned, it won't be garbage collected
                    // until we unpin it ( which we do below )
                    //

                    RcvHeadersBuffer = new byte[BytesReturned];

                    //
                    // pin the new one
                    //

                    NewPinnedBuffer       = GCHandle.Alloc(RcvHeadersBuffer, GCHandleType.Pinned);
                    NewAddrOfPinnedBuffer = NewPinnedBuffer.AddrOfPinnedObject();

                    //
                    // copy the valid data
                    //

                    Marshal.Copy(AddrOfPinnedBuffer, RcvHeadersBuffer, 0, RcvHeadersBufferSize);
                    RcvHeadersBufferSize = BytesReturned;

                    //
                    // unpin the old buffer, reset pinned/unmanaged pointers
                    //

                    PinnedBuffer.Free();

                    PinnedBuffer       = NewPinnedBuffer;
                    AddrOfPinnedBuffer = NewAddrOfPinnedBuffer;

                    //
                    // and start all over again with the new buffer
                    //

                    continue;
                }

                //
                // someother bad error, possible( ? ) return values are:
                //
                // ERROR_INVALID_HANDLE
                // ERROR_INSUFFICIENT_BUFFER
                // ERROR_OPERATION_ABORTED
                // ERROR_IO_PENDING
                //

                throw new InvalidOperationException("UlReceiveHttpRequest() failed, err#" + Convert.ToString(result));
            }

            GlobalLog.Print("GetRequest RequestId:" + Convert.ToString(RequestId));            //
            // translate unmanaged results into a new managed object
            //

            HttpListenerWebRequest
                myWebRequest =
                new HttpListenerWebRequest(AddrOfPinnedBuffer, RcvHeadersBufferSize, m_AppPoolHandle);

            //
            // free the unmanaged buffer ( deallocate/unpin ) after unmanaged call
            //

            PinnedBuffer.Free();

            return(myWebRequest);
        } // GetRequest()