BUG: Error message when you call an OleDbDataReader object: System.InvalidCastException: QueryInterface for interface IRowset failed (313510)



The information in this article applies to:

  • Microsoft ADO.NET (included with the .NET Framework)
  • Microsoft Visual Studio .NET (2002), Professional Edition, when used with:
    • Microsoft Visual C# .NET (2002)

This article was previously published under Q313510

SYMPTOMS

When you call an OleDbDataReader object that invokes the Read method from a different single-threaded apartment (STA) thread than the object was created in, you receive the following exception:
System.InvalidOperationException: The OleDbDataReader.Read must be used from the same thread on which is was created if that thread's ApartmentState was not ApartmentState.MTA

CAUSE

This behavior occurs because the component that implements IRowset does not aggregate the free-threaded marshaller, even though it is marked with a threading model of both. This causes OLE32 to use its own IMarshal, which requires either a typelib or a proxy and stub to be registered for the interface.

RESOLUTION

To work around this issue, make sure that you use an OleDB object only from the STA thread that it is created in, or from any multithreaded apartment (MTA) if it was created on an MTA.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

Steps to Reproduce the Problem

  1. Use Notepad or another text editor to create a C# file named STA_bug.cs with the following code:
    using System;
    using System.Data;
    using System.Data.OleDb;
    using System.Diagnostics;
    using System.Threading;
    
    public class Class1 {
    
        static public ManualResetEvent s_resetevent;
        static public OleDbDataReader s_datareader;
    
        static public void Main(string[] args) {
            Thread.CurrentThread.ApartmentState = ApartmentState.STA; // MTA works
            try {
                BugMultiThread();
            }
            catch(Exception e) {
                Console.WriteLine(e.ToString());
            }
        }
    static public void BugMultiThread() {
            // We use NT authentication here.
            OleDbConnection connection = new OleDbConnection("Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=pubs;Data Source=(local)");
    
            // If you want to use SQL Mode authentication, 
            // make necessary changes to point to your SQL Server.
            // OleDbConnection connection = new OleDbConnection("Provider=SQLOLEDB;Data Source=myserver;Initial Catalog=pubs;User ID=username;Password=password;");
    
            connection.Open();
            try {
                OleDbCommand command = new OleDbCommand("select top 2 * from authors; select top 2 * from publishers;", connection);
                s_datareader = command.ExecuteReader();
    
                s_resetevent = new ManualResetEvent(false);
                (new Thread(new ThreadStart(BugMultiThreadRead))).Start();
                s_resetevent.WaitOne();
            }
            finally {
                if ((null != s_datareader) && !s_datareader.IsClosed) {
                    s_datareader.Close();
                }
                connection.Close();
            }
        }
    
        static public void BugMultiThreadRead() {
            try {
                Console.WriteLine("BugMultiThreadRead: start");
                if (null != s_datareader) {
                    try {
                        do {
                            while (s_datareader.Read()) {
                                Console.Write(".");
                            }
                            Console.Write("*");
                        } while (s_datareader.NextResult());
                    }
                    catch(Exception e) {
                        Console.WriteLine();
                        Console.WriteLine(e.ToString());
                    }
                    Console.WriteLine();
                }
            }
            finally {
                Console.WriteLine("BugMultiThreadRead: signal finish");
                s_resetevent.Set();
            }
        }
    }
    					
  2. Use the Visual Studio .NET command prompt to execute the following command:
    csc.exe /r:system.dll /r:system.data.dll STA_bug.cs & STA_bug.exe
    						
    Note that you receive the following exceptions:
    BugMultiThreadRead: start
    
    System.InvalidOperationException: The OleDbDataReader.Read must be used from the same thread on which is was created if that thread's
    ApartmentState was not ApartmentState.MTA ---> System.InvalidCastException:
    QueryInterface for interface IRowset failed.
       at System.Data.Common.IRowset.GetNextRows(IntPtr hChapter, Int32 lRowsOffset, Int32 cRows, Int32& pcRowsObtained, IntPtr& pprghRows)
       at System.Data.OleDb.OleDbDataReader.GetRowHandles()
       --- End of inner exception stack trace ---
       at System.Data.OleDb.OleDbDataReader.GetRowHandles()
       at System.Data.OleDb.OleDbDataReader.ReadRowset()
       at System.Data.OleDb.OleDbDataReader.Read()
       at Class1.BugMultiThreadRead()
    
    BugMultiThreadRead: signal finish
    					
  3. If you make a revision to use MTA, as follows
    Thread.CurrentThread.ApartmentState = ApartmentState.MTA;
    						
    you receive the correct result:
    BugMultiThreadRead: start
    ..*..*
    BugMultiThreadRead: signal finish
    					

Modification Type:MinorLast Reviewed:3/10/2006
Keywords:kbvs2002sp1sweep kbbug kberrmsg KB313510