Resolution for (many if not all) weird COM errors with .NET

 

Hi!

I was struggling (like some others) with COM errors; mostly annouting being "Application Busy".

This is a "handled" COM case, where the COM provider responds back that it's busy, please try later. However it's a bit difficult to handle on client side... unless you implement the interface that gets called, when its happening and can request the reply within your control!

This is MSDN copied block mostly, but wrapped for more convinient use. Also including the GC.Collect() to possibly help with COM reservations; that portion I've used as an experimental.

The current implementation retries back to retry in 200 milliseconds... customize as see fit.

 

I hope this will help people, the call is as simple as:

 

 ComMessageFilter.ExecuteComFiltered(delegate()

  {

     // Do your SE related custom stuff here... call libraries, go wild!

     PartDocument partDocument = (PartDocument) proc.OpenSEDoc(file, true);

     partDocument.Close(false, null, null);

     partDocument = null;

  });

Br,

Kalle Launiala

 

Posted by: Kalle Launiala
Post date: 4/29/2009 6:49:36 PM

6 REPLIES

RE: Resolution for (many if not all) weird COM errors with .NET

Hi Kalle

 

Thanks a lot for this. I've been meaning to try this for a while now but just got around to it now when I was having problems with a batch program. It worked perfectly. I did notice that if I had any class-wide COM variables in the ExecuteComFiletered block whose scope went beyond the block then the underlying ComObject was released when the code left the block. I just restructured a bit to work around this but I'll go back and have a look at why this is happening soon.

 

Cheers

Calum

 

Posted by: Calum McLellan
Post date: 9/3/2009 2:19:52 AM

RE: Resolution for (many if not all) weird COM errors with .NET

 

Ok, I just thought about it now. The delegate code is executed on a new thread so there is no way that COM objects outside the block can be used inside the block. I must have misinterpreted what was going on with my code as it looked to me as though the objects were just being released after the delegate code exited.

 

Posted by: Calum McLellan
Post date: 9/3/2009 2:23:13 AM

RE: Resolution for (many if not all) weird COM errors with .NET

Actually the way we use is, that we have the elsewhere globally initialized application COM object, that is indeed used within the block. However if I recall right the ones initiated within the block seem to die later on; that is likely when they go out of scope.

 

I didn't dig into this in any way deeper other than I noticed difficulties getting init/quit scoped within the COM block for some reason, and thus those can still give us retry-errors.

 

I think our current code is structured so that the highest level execution method builds its own references as-it-goes, so that their dieing is not an issue. But they do infact refer to global variables (reading only, not assinging to) and those references work fine.

 

Br,

 

Kalle

 

Posted by: Kalle Launiala
Post date: 9/3/2009 2:34:53 AM

RE: Resolution for (many if not all) weird COM errors with .NET

 

Hi Kalle,

this code causes the problem we're talking about. What I don't understand is why the application variable can be used on a seperate thread to the one on which it was created. Maybe the RCW marshals the call to the correct thread, but I didn't think that this sort of thing was done... . Anyway, the partDocument variable is probably released by the garbage collector when the thread used in ExecuteComFiltered finishes its work./* Connect to a running instance of Solid Edge */

application = (Application)Marshal.GetActiveObject("SolidEdge.Application");

ComMessageFilter.ExecuteComFiltered(delegate()

{

/* Don't use the application variable here -> wrong thread */

partDocument = (PartDocument)application.Documents.Add("SolidEdge.PartDocument", Type.Missing);

});

/* Don't use the partDocument variable here -> wrong thread */

partDocument.SaveAs("C:\\Temp.par", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

Cheers

Calum

 

Posted by: Calum McLellan
Post date: 9/3/2009 3:13:36 AM

RE: Resolution for (many if not all) weird COM errors with .NET

 

Hi!

I was trying to find a way to AddRef(), as this seems to be possible, but found this instead:

http://social.msdn.microsoft.com/Forums/en-US/clr/thread/27ef341b-c182-46f7-bba0-20d164e62d8c

While I understand that this may cause difficulties, you might get that one circumvented by putting more code inside the delegate code.

... or actually I was thinking myself to change the code so that it keeps the thread alive, but lets it wait until it is passed another delegate to execute. This way the references elsewhere might stay alive.

If it indeed does release all the COM references, it's huge benefit for longer term executing processes. As it seems based on that MSDN thread, that the constantly increasing reference counts eat up resources on the COM server side (that is in the Solid Edge).

Let me know if you'd need assistance for keeping the thread alive (or actually even have multiple threads with different life cycles, and kill the "lifekeeper" last... that is to have one thread initialize the resources for others)... and I'll see if I can put some time to improve the example.

Br,

Kalle

 

Posted by: Kalle Launiala
Post date: 9/3/2009 7:57:54 AM

RE: Resolution for (many if not all) weird COM errors with .NET

Hi Kalle,

 

I think your code is good as it is. Your correct that the releasing of com ojects is good for longer running apps (such as batch programs), in fact this is really the only time I would use the code at the moment (SE is [usually] reasonably stable until you start looping throught hundreds of files).

I wouldn't bother keeping the threads alive unless you are including your delegate inside a loop - if this is the case then you will create a new thread for each iteration which could get pretty heavy if the loop code is executed quickly. For my current scenario I have enclosed the loop inside the delegate, meaning that only one thread is created for the entire process.

I'm still interested to know why the variables are being released, and why this is only happening 'one-way' (my application variable in the last example was successfully marshalled to the new message filter thread, but the document variable was released when being marshalled back to the main thread.

 

I will have to do a bit more digging/debugging to figure this out, but this is just purely out of interest as the code works fine as it is (as long as you don't have it inside a tight loop where it will be heavy on resources).

 

Thanks again for this gem

Calum

 

Posted by: Calum McLellan
Post date: 9/3/2009 10:30:14 AM