2011-06-16 13 views
5

(nota preliminar: No estoy todavía completamente al día con todo el asunto 'interoperabilidad' ...)COM `HRESULT` se envuelve en una excepción en .NET

Cuando se utiliza una biblioteca COM desde dentro .NET, todos los métodos HRESULT se envuelven en algo que se lanza cuando el código de retorno no se CONSIGUE EXITOSAMENTE.

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

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

La contraparte .NET de este código lee:

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

¿Hay una manera de acceder al código de retorno COM directamente en .NET, por lo que no es necesario el manejo de excepciones?

Respuesta

4

Sí, pero deberá definir manualmente la interfaz de interoperabilidad (en lugar de usar tlbimp.exe) y usar el atributo PreserveSig en los métodos en cuestión.

Por ejemplo:

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

Eso es el equivalente de un método COM con la firma HRESULT DoSomething([out, retval] int *result);

Si su interfaz es muy complicado o se queda atascado en la forma de definir la interfaz de interoperabilidad, lo recomiendo usando tlbimp.exe, luego usando Reflector o ILSpy o algo similar para descompilar las interfaces generadas, y luego edítelas a su gusto. Guarda el trabajo, también. :)

+0

solo quería señalar más claramente que '[PreserveSig]' es el atributo que se utiliza para decir si quiere que HRESULTS se convierta en excepciones o no. También debe tenerse en cuenta que generalmente * desea * usar excepciones. Los HRESULTS solo existen porque no todos los idiomas manejan las excepciones de la misma manera, por lo que necesitaban un mecanismo no basado en excepciones para informar excepciones. Una vez que esté dentro de su propio idioma, HRESULT debe (idealmente) convertirse al mecanismo de excepción nativo de su idioma. –

+1

Esa no es la única razón por la que te gustaría usar '[PreserveSig]'. Hay algunas interfaces COM que, para mejor o peor, usan HRESULT como booleano; estas funciones pueden devolver S_OK, S_FALSE o un valor de error. Si no usa '[PreserveSig]', no hay manera de saber si devolvió S_OK o S_FALSE. Eso no es solo para S_FALSE, sino para cualquier HRESULT que no sea un error. Las clases COM que hacen esto son afortunadamente raras, pero existen. – Sven

+0

También existe el muy extraño método 'IProgressDialog.HasUserCancelled' que ni siquiera devuelve un' HRESULT' (como el resto de los métodos de la interfaz), sino que devuelve un 'BOOL'. (Casi seguro es un error en la interfaz original en Windows 95, y ahora está congelado para compatibilidad) –

Cuestiones relacionadas