COM Interops on MTA's...

D

Daniel Bass

Greetings!

I'm trying to use the SQLXML BulkLoad COM object from a .net multithreaded
application... I'm currently getting an error when I try to use this object
saying:

System.InvalidCastException: Unable to cast COM object of type
'SQLXMLBULKLOADLib.SQLXMLBulkLoad4Class' to interface type
'SQLXMLBULKLOADLib.ISQLXMLBulkLoad4'. This operation failed because the
QueryInterface call on the COM component for the interface with IID
'{88465BA7-AEEE-49A1-9499-4416287A0160}' failed due to the following error:
No such interface supported (Exception from HRESULT: 0x80004002
(E_NOINTERFACE)).
at SQLXMLBULKLOADLib.SQLXMLBulkLoad4Class.set_ConnectionString(String
pbstrConnectionString)
at Olympus.Integrate.Client.SqlServerClient.SendMessage(String message)
in C:\Projects\prototype\Integrate\SqlServerClient\SqlServerClient.vb:line
62
at Olympus.Integrate.Core.Core.MonitorFlow(Object flowObj) in
C:\Projects\prototype\Integrate\Integrate\Core.vb:line 152


Now I'm guessing that this COM object does support multiple threads.
So the question is how to get around this. Would wrapping this function in a
singleton, for example, do the trick? Or maybe having a static function in
an object?
What would be the best approach?

thanks for your time.
Daniel.
 
W

Willy Denoyette [MVP]

Daniel Bass said:
Greetings!

I'm trying to use the SQLXML BulkLoad COM object from a .net multithreaded
application... I'm currently getting an error when I try to use this
object saying:

System.InvalidCastException: Unable to cast COM object of type
'SQLXMLBULKLOADLib.SQLXMLBulkLoad4Class' to interface type
'SQLXMLBULKLOADLib.ISQLXMLBulkLoad4'. This operation failed because the
QueryInterface call on the COM component for the interface with IID
'{88465BA7-AEEE-49A1-9499-4416287A0160}' failed due to the following
error: No such interface supported (Exception from HRESULT: 0x80004002
(E_NOINTERFACE)).
at SQLXMLBULKLOADLib.SQLXMLBulkLoad4Class.set_ConnectionString(String
pbstrConnectionString)
at Olympus.Integrate.Client.SqlServerClient.SendMessage(String message)
in C:\Projects\prototype\Integrate\SqlServerClient\SqlServerClient.vb:line
62
at Olympus.Integrate.Core.Core.MonitorFlow(Object flowObj) in
C:\Projects\prototype\Integrate\Integrate\Core.vb:line 152


Now I'm guessing that this COM object does support multiple threads.
So the question is how to get around this. Would wrapping this function in
a singleton, for example, do the trick? Or maybe having a static function
in an object?
What would be the best approach?

thanks for your time.
Daniel.

Make sure your thread is initilaize to enter a STA before starting (see
SetApartmentState(ApartmentState.STA) in System.Threading).

Willy.
 
D

Daniel Bass

Willy,

Thanks for your reply.
In my application I dynamically create multiple threads according to some
configuration. At this point in the application the knowledge doesn't exist
as to whether the thread that is created will use the COM object... Is it
recommended that I just mark each thread as STA?

For Each myObj As MyObjectType In myObjects

' launch a seperate thread for each configured message flow
Dim t As Thread = New Thread(AddressOf MyThreadStartFunction)
t.Name = myObj.myName
t.SetApartmentState(ApartmentState.STA) // <--------- ?? Is
this okay ??
MyThreadHandler.Instance.AddThread(t)
t.Start(myParameter)

Next

Cheers.
Dan.
 
W

Willy Denoyette [MVP]

Daniel Bass said:
Willy,

Thanks for your reply.
In my application I dynamically create multiple threads according to some
configuration. At this point in the application the knowledge doesn't
exist as to whether the thread that is created will use the COM object...
Is it recommended that I just mark each thread as STA?

For Each myObj As MyObjectType In myObjects

' launch a seperate thread for each configured message flow
Dim t As Thread = New Thread(AddressOf MyThreadStartFunction)
t.Name = myObj.myName
t.SetApartmentState(ApartmentState.STA) // <--------- ?? Is
this okay ??
MyThreadHandler.Instance.AddThread(t)
t.Start(myParameter)

Next

Cheers.
Dan.
Dan, The apartment state is a COM only thing, it doesn't affect .NET. An STA
apartment is valid for single and apartment threaded COM object types, so in
your case it is safe to initialize your threads to enter an STA .

Willy.
 
D

Daniel Bass

Willy Denoyette said:
Dan, The apartment state is a COM only thing, it doesn't affect .NET. An
STA apartment is valid for single and apartment threaded COM object types,
so in your case it is safe to initialize your threads to enter an STA .

Willy.

Thanks. I keep getting a ContextSwtichDeadlock, but reading up it sounds
like a bogus message. My process spends a lot of time looping around in
other parts of the code while polling which suggests the reason for this
error coming up.

Thanks for your help.
Dan.
 
W

Willy Denoyette [MVP]

Daniel Bass said:
Thanks. I keep getting a ContextSwtichDeadlock, but reading up it sounds
like a bogus message. My process spends a lot of time looping around in
other parts of the code while polling which suggests the reason for this
error coming up.

Thanks for your help.
Dan.



This is not necessarily bogus message, don't take this too lightly. One
possible reason for the MDA is that your thread fails to pump the message
queue, if that's the case you will have problems whenever the finalizer
needs to release the COM object references you are holding in this thread,
this will block the finalizer thread with as a result that finalizable
objects stay in memory, finally leading into OOM and other kind of failures.

Willy.
 
D

Daniel Bass

Thanks. I keep getting a ContextSwtichDeadlock, but reading up it sounds
This is not necessarily bogus message, don't take this too lightly. One
possible reason for the MDA is that your thread fails to pump the message
queue, if that's the case you will have problems whenever the finalizer
needs to release the COM object references you are holding in this thread,
this will block the finalizer thread with as a result that finalizable
objects stay in memory, finally leading into OOM and other kind of
failures.

Willy.

I've kept the process running, keeping an eye on memory and handles, and it
appears to destory and release the COM object correctly as there's no
increase in the resources used.
How would I check whether I'm "failing to pump the message queue"? This is
not a GUI app, but a backend service. Is there any way in .Net to check the
COM reference count?

I do explicitly disgard the object after creating and using...

' clear up
System.Runtime.InteropServices.Marshal.ReleaseComObject(bulkLoadComObject)
bulkLoadComObject = Nothing

Thanks.
Daniel.
 
Top