Got an issue where I am a COM type in c# using
this.rtwbType = Type.GetTypeFromProgID(progId, true);
this.rtwb = Activator.CreateInstance(this.rtwbType);
I am then doing some stuff, and when I am done I call exit on the rtwb - so it can close down, and then calling:
Marshal.ReleaseComObject(this.rtwb);
In 2008 R2 this is fine and dandy - but the instance we take to 2012 an exception is thrown here.
System.Runtime.InteropServices.COMException (0x800706BA): The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
like I say works fine elsewhere.
Any pointers?
The following code reproduces this error (at least under Windows 8.1):
var type = Type.GetTypeFromProgID("InternetExplorer.Application", true);
dynamic ie = Activator.CreateInstance(type);
ie.Quit(); // this disconnects the COM proxy from the out-of-proc IE object
Marshal.ReleaseComObject(ie); // throws
Apparently, the implementation of ReleaseComObject
is doing something more than calling IUnknown::Release
, when it deals with a COM proxy object. My guess is, it may be calling IRemUnknown::RemRelease
, which returns HRESULT
with an error, so ReleaseComObject
throws, because the out-of-proc object has been already disconnected and destroyed with ie.Quit()
.
Presumably, this behavior was introduced in Windows Server 2012.
The best thing you could probably do is to ignore this specific error:
try
{
Marshal.ReleaseComObject(ie);
}
catch (COMException ex)
{
// I'm getting 0x80010108, rather than 0x800706BA
// The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED)
if ((uint)ex.ErrorCode != 0x80010108)
throw;
}
Updated: this is the expected behavior for an API like Quit
, it doesn't violate any COM rules. The goal of Quit
is to provide an API for explicit shutdown. I believe it uses CoDisconnectObject
internally, as a part of the shutdown process. This disconnects all external proxy references, so the server knows it can shut down safely.
The fact that ReleaseComObject
is still trying to do some stuff after that (like, most likely, calling IUnknown::QueryInterface
on the disconnected proxy) is not a fault of the COM server.
I'm assuming that rtwb
is an InternetExplorer.Application
, as Noseratio's test seems to replicate the issue rather well.
It seems Internet Explorer's Quit()
method is not really safe to call outside the application's context, e.g. through out-of-process automation. It violates the rules of COM server applications.
For instance, Office applications keep running while there are external references, even after Quit()
, so this is really a bit unexpected.
For safety, you can let the reference go when quitting, using the OnQuit
event:
using System;
using System.Threading;
using System.Runtime.InteropServices;
public class TestIE
{
public static void Main()
{
Console.WriteLine("Creating application");
dynamic app = Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application"));
Console.WriteLine("Created application");
app.Visible = true;
app.OnQuit += new Action(() => {
Console.WriteLine("Entered OnQuit");
Marshal.ReleaseComObject(app);
app = null;
Console.WriteLine("Leaving OnQuit");
});
Console.WriteLine("Sleeping");
Thread.Sleep(5000); // enough time to see if iexplore.exe is running
Console.WriteLine("Slept");
Console.WriteLine("Quitting");
app.Quit();
Console.WriteLine("Quit");
Console.WriteLine("Sleeping");
Thread.Sleep(5000); // enough time to see if iexplore.exe is running
Console.WriteLine("Slept");
Console.WriteLine(app == null);
}
}
If you really need to use ReleaseComObject
, discard any exceptions it might throw. I'm not sure if you should discard only COMException
, try it out during development.
User contributions licensed under CC BY-SA 3.0