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?

xtofl
  • 40,723
  • 12
  • 105
  • 192

1 Answers1

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. :)

Sven
  • 21,903
  • 4
  • 56
  • 63
  • 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. – Ian Boyd Jun 27 '11 at 14:44
  • 1
    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. – Sven Jun 27 '11 at 17:07
  • 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) – Ian Boyd Jun 30 '11 at 13:33