Como: Mapear HRESULTs e exceções

Métodos COM relatam erros retornando HRESULTs; métodos .NET os relatam gerando exceções. O runtime manipula a transição entre os dois. Cada classe de exceção do .NET Framework mapeia para um HRESULT.

Classes de exceção definidas pelo usuário podem especificar qualquer HRESULT apropriado. Essas classes de exceção podem alterar dinamicamente o HRESULT a ser retornado quando a exceção é gerada definindo o campo HResult no objeto de exceção. Informações adicionais sobre a exceção são fornecidas ao cliente por meio da interface IErrorInfo, que é implementada no objeto .NET no processo não gerenciado.

Se você criar uma classe que estenda System.Exception, deverá definir o campo HRESULT durante a construção. Caso contrário, a classe base atribui o valor de HRESULT. Você pode mapear as novas classes de exceção para um HRESULT existente, fornecendo o valor no construtor da exceção.

Observe que o runtime, às vezes, ignorará um HRESULT em casos nos quais um IErrorInfo estiver presente no thread. Esse comportamento poderá ocorrer nos casos em que o HRESULT e o IErrorInfo não representarem o mesmo erro.

Para criar uma nova classe de exceção e mapeá-la para um HRESULT

  1. Use o código a seguir para criar uma nova classe de exceção chamada NoAccessException e mapeá-la para o HRESULT E_ACCESSDENIED.

    Class NoAccessException : public ApplicationException
    {
        NoAccessException () {
        HResult = E_ACCESSDENIED;
    }
    }
    CMyClass::MethodThatThrows
    {
    throw new NoAccessException();
    }
    

Você pode encontrar um programa (em qualquer linguagem de programação) que usa o código gerenciado e não gerenciado simultaneamente. Por exemplo, o marshaller personalizado no exemplo de código a seguir usa o método Marshal.ThrowExceptionForHR(int HResult) para lançar uma exceção com um valor HRESULT específico. O método pesquisa o HRESULT e gera o tipo de exceção apropriado. Por exemplo, o HRESULT no fragmento de código a seguir gera ArgumentException.

CMyClass::MethodThatThrows
{
    Marshal.ThrowExceptionForHR(COR_E_ARGUMENT);
}

A tabela a seguir fornece os mapeamentos comuns do HRESULT para sua classe de exceção comparável no .NET. Os valores HRESULT sem mapeamentos explícitos são mapeados para COMException. O mapeamento completo e atualizado pode ser encontrado no repositório dotnet/runtime.

HRESULT Exceção do .NET
COR_E_APPLICATION ApplicationException
COR_E_ARGUMENT ou E_INVALIDARG ArgumentException
COR_E_ARGUMENTOUTOFRANGE ArgumentOutOfRangeException
COR_E_ARITHMETIC or ERROR_ARITHMETIC_OVERFLOW ArithmeticException
COR_E_ARRAYTYPEMISMATCH ArrayTypeMismatchException
COR_E_BADIMAGEFORMAT or ERROR_BAD_FORMAT BadImageFormatException
COR_E_DIRECTORYNOTFOUND or ERROR_PATH_NOT_FOUND DirectoryNotFoundException
COR_E_DIVIDEBYZERO DivideByZeroException
COR_E_DUPLICATEWAITOBJECT DuplicateWaitObjectException
COR_E_ENDOFSTREAM EndOfStreamException
COR_E_ENTRYPOINTNOTFOUND EntryPointNotFoundException
COR_E_EXCEPTION Exception
COR_E_EXECUTIONENGINE ExecutionEngineException
COR_E_FIELDACCESS FieldAccessException
COR_E_FILENOTFOUND or ERROR_FILE_NOT_FOUND FileNotFoundException
COR_E_FORMAT FormatException
COR_E_INDEXOUTOFRANGE IndexOutOfRangeException
COR_E_INVALIDCAST or E_NOINTERFACE InvalidCastException
COR_E_INVALIDFILTERCRITERIA InvalidFilterCriteriaException
COR_E_INVALIDOPERATION InvalidOperationException
COR_E_IO IOException
COR_E_MEMBERACCESS AccessException
COR_E_METHODACCESS MethodAccessException
COR_E_MISSINGFIELD MissingFieldException
COR_E_MISSINGMANIFESTRESOURCE MissingManifestResourceException
COR_E_MISSINGMEMBER MissingMemberException
COR_E_MISSINGMETHOD MissingMethodException
COR_E_NOTFINITENUMBER NotFiniteNumberException
E_NOTIMPL NotImplementedException
COR_E_NOTSUPPORTED NotSupportedException
COR_E_NULLREFERENCE orE_POINTER NullReferenceException
COR_E_OUTOFMEMORY or

E_OUTOFMEMORY
OutOfMemoryException
COR_E_OVERFLOW OverflowException
COR_E_PATHTOOLONG or ERROR_FILENAME_EXCED_RANGE PathTooLongException
COR_E_RANK RankException
COR_E_REFLECTIONTYPELOAD ReflectionTypeLoadException
COR_E_SECURITY SecurityException
COR_E_SERIALIZATION SerializationException
COR_E_STACKOVERFLOW orERROR_STACK_OVERFLOW StackOverflowException
COR_E_SYNCHRONIZATIONLOCK SynchronizationLockException
COR_E_SYSTEM SystemException
COR_E_TARGET TargetException
COR_E_TARGETINVOCATION TargetInvocationException
COR_E_TARGETPARAMCOUNT TargetParameterCountException
COR_E_THREADINTERRUPTED ThreadInterruptedException
COR_E_THREADSTATE ThreadStateException
COR_E_TYPELOAD TypeLoadException
COR_E_TYPEINITIALIZATION TypeInitializationException
COR_E_VERIFICATION VerificationException

Para recuperar informações sobre erros estendidos, o cliente gerenciado deve examinar os campos do objeto de exceção gerado. Para que o objeto de exceção forneça informações úteis sobre um erro, o objeto COM deve implementar a interface IErrorInfo. O tempo de execução usa as informações fornecidas por IErrorInfo para inicializar o objeto de exceção.

Se o objeto COM não oferecer suporte a IErrorInfo, o tempo de execução inicializará um objeto de exceção com valores padrão. A tabela a seguir lista cada campo associado a um objeto de exceção e identifica a fonte de informações padrão quando o objeto COM oferece suporte a IErrorInfo.

Observe que o runtime, às vezes, ignorará um HRESULT em casos nos quais um IErrorInfo estiver presente no thread. Esse comportamento poderá ocorrer nos casos em que o HRESULT e o IErrorInfo não representarem o mesmo erro.

Campo de exceção Origem das informações do COM
ErrorCode HRESULT retornado da chamada.
HelpLink Se IErrorInfo->HelpContext for diferente de zero, a cadeia de caracteres será formada pela concatenação de IErrorInfo->GetHelpFile e "#" e IErrorInfo->GetHelpContext. Caso contrário, a cadeia de caracteres é retornada de IErrorInfo->GetHelpFile.
InnerException Sempre uma referência nula (Nothing no Visual Basic).
Message Cadeia de caracteres retornada de IErrorInfo->GetDescription.
Source Cadeia de caracteres retornada de IErrorInfo->GetSource.
StackTrace O rastreamento de pilha.
TargetSite O nome do método que retornou o HRESULT com falha.

Campos de exceção, como Message, Source e StackTrace não estão disponíveis para o StackOverflowException.

Confira também