When I try to instantiate a PDF browser control like this in C#:
AcroPDFLib.AcroPDFClass acrobat = new AcroPDFLib.AcroPDFClass();
I get a COMException
with this message:
Creating an instance of the COM component with CLSID {CA8A9780-280D-11CF-A24D-444553540000} from the IClassFactory failed due to the following error: 80004005.
I have made a reference to AcroPDF.dll which has the component name Adobe Acrobat 7.0 Browser Control Type Library 1.0.
When I run Visual C# 2008 Express Edition as administrator I get another error message:
Unable to cast COM object of type 'AcroPDFLib.AcroPDFClass' to interface type 'AcroPDFLib.IAcroAXDocShim'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{3B813CE7-7C10-4F84-AD06-9DF76D97A9AA}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
This happens at the next line when I try to use the object:
acrobat.LoadFile("book.pdf");
I can't figure out what is wrong. Help most appreciated!
Best Answer
.net COM interop doesn't route all COM messages directly back to the caller. If you called COM from an STA, it won't understand how you app can handle re-entrance. This means that failure messages that could just be handled with a retry, end up causing exceptions.
Try implementing IMessageFilter interface. This will allow COM to understand how to pass messages back to your app. In particular, implement the RetryRejectedCall and check if the failure flags and possibly return a timeout value (something like 1000ms) to allow COM to retry after a brief pause.
It's a COM type, so this is the code you'll need to define the interface:
And this is an example of how you would implement it:
Once you've implemented a message filter you will need to register it using CoRegisterMessageFilter. This is a per-thread registration, so be aware of what thread you are calling it on. The PInvoke signiture is:
Even if this doesn't work, at the very least, if you log all the messages in the filter you should hopefully get some more information about what is going wrong. Look at the values of the parameters being passed into the message filter. If you look them up they will relate to error/state codes.
[Be aware, the IMessageFilter I'm referring to here is different from the System.Windows.Forms.IMessageFilter, so make sure you don't accidentally use the winforms one.]