I have a base library created in VB6 that exposes a standard COM interface that is used in a number of applications.
This also exposed a number of error code constants, used with Err.Raise
to indicate certain conditions.
Public Enum IOErrors
IOErrorBase = 45000
IOErrorConnectionFailed
IOErrorAuthFailed
IOErrorNotConnected
IOErrorInvalidPortDirection
IOErrorGettingValue
IOErrorNoValueYet
End Enum
Come on 10 years and we're creating C# objects implementing the same set of interfaces and want to throw exceptions in a way that the calling application will recognise them.
I can only find two relevant classes, Win32Exception
and COMException
.
Throwing Win32Exception((int)IOErrors.IOErrorConnectionFailed, "Connect failed")
passes the message back correctly but the error code is ignored and Err.Number
is &H80004005
.
Throwing COMException("Connect failed", IOErrors.IOErrorConnectionFailed)
results in no error being picked up in the calling application, presumably because the error code is not an HRESULT
and is positive, meaning success.
TL;DR How can I throw an exception from C# such that COM interop will translate it into one of the recognised (positive) error codes above?
The "positive" VB style error numbers are translated to HRESULT
s with a "FAILURE" severity and a facility of FACILITY_CONTROL
/0xA
, i.e. 0x800AAFC9
.
You can get a suitable HRESULT
using:
int HResult = (int)(0x800A0000 | (int)errorCode);
This can then be raised back to the calling process using a plain COMException
, or by throwing your own subclass of COMException
:
/// <summary>
/// Exception that returns an ICIO error wrapped in an exception.
/// </summary>
internal class ICIOErrorException : COMException {
internal ICIOErrorException(ICIO.IOErrors errorCode, string message)
: base(message) {
this.HResult = (int)(0x800A0000 | (int)errorCode);
}
}