Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a COM object to throw an exception on any result except S_OK (0) in C#

Tags:

c#

com

I'm currently working on an upgrade to a project that extensively uses COM / MFC / (who knows how many other technologies). As part of the upgrade, we're trying to move as much functionality as we can into managed C# code, but unfortunately some stuff just can't move (for reasons I won't go into). One of those things is a section of code that grossly abuses COM, and returns pointers in the HRESULTs that later get cast to various other COM-interface implementing objects. I've tried the following code to convert an HRESULT into a pointer that I can then get an interface from :

        MyComInterfaceInCS myObj = null;

        try
        {
            world.GetTD_MyComInterfaceInCS();
        }
        catch (COMException comException)
        {
            int pointerValue = Marshal.GetHRForException(comException);

            IntPtr myObjPointer = new IntPtr(pointerValue);

            myObj = (MyComInterfaceInCS) Marshal.GetObjectForIUnknown(myObjPointer);
        }

.... but, no COM exception gets thrown, and I'm guessing it's because the pointer is not a negative value, and hence isn't technically a COM error. Is there any way to configure COM on the object to throw a COM exception on anything BUT S_OK (0) ?

like image 597
Alex Marshall Avatar asked Jun 06 '11 23:06

Alex Marshall


1 Answers

Two thoughts:

  1. Find and kill (or severely maim) whoever implemented this library
  2. Implement a wrapper in managed C++ as you will need to get at the method call's HResult directly and I cannot think of a way to do that using interop.

EDIT

Another option is to declare the COM interfaces in C# such that the signature of each method returns an HRESULT and uses [out retval] for return values. This will alow you to get and examine the HRESULT of all method calls, not just ones that throw a COMException.

By default COM interop typeimport "fixes up" the method signatures such that the HRESULT return is removed on the managed side and the interop layer throws exceptions for E_FAIL etc, essentially throwing away S_OK, S_FALSE and the like.

This article has some explanation and the PreserveSig attriubte documentation has some additoinal detail.

This will likely require that you declare all of the COM interfaces manually rather than using tlbimp but you may be able to get tlbimp to preserve the signature of the COM methods.

This would allow you to stay purely in C# but in your shoes I'd go with managed C++ as it is just easier to interact with COM in this non-standard fashion from there.

like image 120
dkackman Avatar answered Oct 21 '22 03:10

dkackman