Traduções de assinatura de método implícito na interoperabilidade .NET
Para manter a linguagem de programação agnóstica, o sistema Windows COM e muitas APIs do Windows retornam um tipo inteiro de 4 bytes chamado an HRESULT
para indicar se uma API foi bem-sucedida ou falhou, juntamente com algumas informações sobre a falha. Outros valores que precisam ser passados para o chamador são "retornados" por meio de parâmetros de ponteiro que atuam como parâmetros "out" e normalmente são o último parâmetro na assinatura. Linguagens como C# e Visual Basic tradicionalmente traduzem um código de falha para uma exceção para corresponder a como as falhas geralmente são propagadas na linguagem e esperam que as assinaturas do método de interoperabilidade não incluam o HRESULT
. Para traduzir a assinatura do método para uma assinatura nativa, o tempo de execução move o valor de retorno do método para um parâmetro "out" adicional com mais um nível de indirection (em outras palavras, torna-o um ponteiro para o tipo de retorno da assinatura gerenciada) e assume um HRESULT
valor de retorno. Se o método gerenciado retornar void
, nenhum parâmetro adicional será adicionado e o valor de retorno se tornará um HRESULT
arquivo . Por exemplo, consulte os dois métodos COM C# a seguir que se traduzem para a mesma assinatura nativa:
int Add(int a, int b);
void Add(int a, int b, out int sum);
HRESULT Add(int a, int b, /* out */ int* sum);
PreserveSig em COM
Espera-se que todos os métodos COM em C# usem a assinatura traduzida por padrão. Para usar e exportar métodos sem a conversão de assinatura e manipulação de valores, adicione o PreserveSigAttribute a um método de HRESULT
interface COM. Quando o atributo é aplicado a um método, nenhuma tradução é feita para a assinatura e exceções não são lançadas para valores com falha HRESULT
. Isso se aplica tanto ao COM interno quanto ao COM gerado pelo código-fonte. Por exemplo, consulte a seguinte assinatura de método C# com um PreserveSig
atributo e sua assinatura nativa correspondente.
[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);
Isso pode ser útil se o método pode retornar valores diferentes HRESULT
que não são falhas, mas devem ser tratados de forma diferente. Por exemplo, alguns métodos podem retornar o valor S_FALSE
quando um método não falha, mas retorna apenas resultados parciais e S_OK
quando retorna todos os resultados.
PreserveSig
com P/Invoca
O DllImportAttribute atributo também tem o bool PreserveSig
campo que funciona de forma semelhante ao PreserveSigAttribute
, mas o padrão é .true
Para indicar que o tempo de execução deve traduzir a assinatura gerenciada e manipular o HRESULT
que é retornado, defina o PreserveSig
campo como false
no DllImportAttribute
. Por exemplo, consulte as seguintes assinaturas de dois P/Invokes para o mesmo método nativo, um com PreserveSig
set como false
, e outro com ele deixado para o valor padrão true
.
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true, PreserveSig = false)]
public static extern void SHAutoComplete(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true)]
public static extern int SHAutoCompleteHRESULT(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);
Nota
P/Invokes gerados pela fonte, que usam o LibraryImportAttribute, não PreserveSig
têm campo. O código gerado sempre pressupõe que a assinatura nativa e gerenciada são idênticas. Para obter mais informações, consulte P/Invokes gerados pela fonte.
Manipular HRESULT
valores manualmente
Ao chamar um PreserveSig
método que retorna um HRESULT
, você pode usar o ThrowExceptionForHR método para lançar a exceção correspondente se o HRESULT
indicar uma falha. Da mesma forma, ao implementar um PreserveSig
método, você pode usar o GetHRForException método para retornar o HRESULT
que indica um valor correspondente para a exceção.
Marechal HRESULTs como estruturas
Ao usar um PreserveSig
método, int
espera-se que seja o tipo gerenciado para HRESULT
. No entanto, usar uma estrutura personalizada de 4 bytes como o tipo de retorno permite que você defina métodos auxiliares e propriedades que podem simplificar o trabalho com o HRESULT
. No empacotamento integrado, isso funciona automaticamente. Para usar um struct no lugar de int
como a representação gerenciada do HRESULT
empacotamento gerado na fonte, adicione o MarshalAsAttribute atributo com Error como argumento. A presença deste atributo reinterpreta os bits do HRESULT
como o struct.