COM `HRESULT` is wrapped into an Exception in .NET
Asked Answered
R

1

7

(preliminary note: I'm not yet fully up to speed with the whole 'interop' thing...)

When using a COM library from within .NET, all HRESULT methods are wrapped into something that throws when the return code is not SUCCEEDED.

//ATL magic exluded
class C {
    HRESULT foo(){ return E_FAIL; }
};

// usage code:
if( SUCCEEDED( c.foo() ) ) {
   // success code
} else {
   // failure code
}

The .NET counterpart of this code reads:

try {
   c.foo();
   // success code
} catch ( Exception e ) {
   // failure code
}

Is there a way to access the COM return code directly in .NET, so that no exception handling is needed?

Rooney answered 16/6, 2011 at 11:31 Comment(0)
H
7

Yes, but you'll have to manually define the interop interface (rather than use tlbimp.exe) and use the PreserveSig attribute on the methods in question.

For example:

[ComImport]
[Guid("your-guid-here")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMyComInterface
{
     [PreserveSig]
     int DoSomething(out int result);
}

That is the equivalent of a COM method with the signature HRESULT DoSomething([out, retval] int *result);

If your interface is very complicated or you get stuck on how to define the interop interface, I recommend using tlbimp.exe, then using Reflector or ILSpy or something similar to decompile the generated interfaces, and then edit those to your liking. Saves work, too. :)

Heaume answered 16/6, 2011 at 11:47 Comment(3)
i just wanted to point out more plainly that [PreserveSig] is the attribute that is used to say if you want HRESULTS converted to exceptions or not. It should also be noted that you generally want to use exceptions. HRESULTS only exist because not all languages handle exceptions the same way, so they needed a non-exception-based mechanism to report exceptions. Once you're inside your own language the HRESULT should (ideally) be converted to your language's native exception mechanism.Bisque
That is not the only reason why you'd want to use [PreserveSig]. There are some COM interfaces that for better or worse use the HRESULT as a boolean; these functions can return either S_OK, S_FALSE or an error value. If you don't use [PreserveSig] there is no way to know if it returned S_OK or S_FALSE. That goes not just for S_FALSE, but for any non-error HRESULT. COM classes that do this are fortunately rare, but they do exist.Heaume
There is also the very odd IProgressDialog.HasUserCancelled method that doesn't even return an HRESULT (as the rest of the interface's methods do), but instead returns a BOOL. (Almost certainly a bug in the original interface in Windows 95, and is now frozen for compatibility)Bisque

© 2022 - 2024 — McMap. All rights reserved.