Question

I have the following code and do not understand why I am periodically getting an AccessViolationException or COMException. Any help would be much appreciated. Thank you.

        IntPtr eventObject = IntPtr.Zero;
        NativeOverlapped HidOverlapped = new NativeOverlapped();
        Byte[] inputReportBuffer = null;
        Int32 numberOfBytesRead = 0;
        Int32 result = 0;
        Boolean success = false;
        IntPtr unManagedBuffer = IntPtr.Zero;
        IntPtr unManagedOverlapped = IntPtr.Zero;

        Array.Resize(ref inputReportBuffer, Capabilities.InputReportByteLength);

        eventObject = CreateEvent
            (IntPtr.Zero,
            false,
            false,
            String.Empty);

        HidOverlapped.OffsetLow = 0;
        HidOverlapped.OffsetHigh = 0;
        HidOverlapped.EventHandle = eventObject;

        unManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
        unManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(HidOverlapped));
        Marshal.StructureToPtr(HidOverlapped, unManagedOverlapped, false);

        success = ReadFile
            (readHandle,
            unManagedBuffer,
            inputReportBuffer.Length,
            ref numberOfBytesRead,
            unManagedOverlapped);

        while (!busyWait()) ;
        // If ReadFile returned true, report is available. Otherwise, check for completion
        if (!success)
        {
            result = WaitForSingleObject(eventObject, 1000);

            switch (result)
            {
                case WAIT_OBJECT_0:
                    success = true;
                    GetOverlappedResult
                        (readHandle,
                        unManagedOverlapped,
                        ref numberOfBytesRead,
                        false);
                    break;
                case WAIT_TIMEOUT:
                    CancelIo(readHandle);
                    break;
                default:
                    CancelIo(readHandle);
                    break;
            }
        }
        if (success)
        {
            // Report was received.
            // Copy Received data to inputReportBuffer for application use
            Marshal.Copy(unManagedBuffer, inputReportBuffer, 0, numberOfBytesRead);
            ProcessUSB(inputReportBuffer);
        }
        Marshal.FreeHGlobal(unManagedOverlapped);  // <-- AccessViolationException Here.
        Marshal.FreeHGlobal(unManagedBuffer);
        success = HidD_FreePreparsedData(preparsedData);

Also, here is the stack trace from the Exception:

   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at System.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtr hglobal)
   at TWEEQ.MainWindow.ReadUSB()
   at TWEEQ.MainWindow.myTimer_Elapsed(Object sender, ElapsedEventArgs e)
   at System.Timers.Timer.MyTimerCallback(Object state)
   at System.Threading.TimerQueueTimer.CallCallbackInContext(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.TimerQueue.FireNextTimers()
   at System.Threading.TimerQueue.AppDomainTimerCallback()
Was it helpful?

Solution

Per Raymond Chen's blog at http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx

It's quite possible that I/O hasn't completed after a call to CancelIO and you are breaking the cardinal rule stated in the blog. Namely, "the OVERLAPPED structure must remain valid until I/O completes".

Try adding WaitForSingleObject(eventObject, 0xFFFFFFFF) (or whatever const you use for INFINITE) before your call to FreeHGlobal.

Also, you can simplify your switch statement as follows:

            case WAIT_TIMEOUT:
            default:
                CancelIo(readHandle);
                break;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top