Partilhar via


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 HRESULTarquivo . 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.

Consulte também