Partilhar via


Criando protótipos em código gerenciado

Este tópico descreve como acessar funções não gerenciadas e apresenta vários campos de atributo que anotam a definição de método no código gerenciado. Para exemplos que demonstram como construir . Declarações baseadas em NET a serem usadas com invocação de plataforma, consulte Marshalling Data with Platform Invoke.

Antes de poder acessar uma função DLL não gerenciada a partir do código gerenciado, você precisa saber o nome da função e o nome da DLL que a exporta. Com essas informações, você pode começar a escrever a definição gerenciada para uma função não gerenciada que é implementada em uma DLL. Além disso, você pode ajustar a maneira como a plataforma invoca cria a função e controla os dados de e para a função.

Nota

As funções da API do Windows que alocam uma cadeia de caracteres permitem que você libere a cadeia de caracteres usando um método como LocalFree. A invocação de plataforma lida com esses parâmetros de forma diferente. Para chamadas de invocação de plataforma, torne o parâmetro um IntPtr tipo em vez de um String tipo. Use métodos fornecidos pela System.Runtime.InteropServices.Marshal classe para converter o tipo em uma cadeia de caracteres manualmente e liberá-la manualmente.

Noções básicas da declaração

As definições gerenciadas para funções não gerenciadas dependem do idioma, como você pode ver nos exemplos a seguir. Para obter exemplos de código mais completos, consulte Exemplos de invocação de plataforma.

Friend Class NativeMethods
    Friend Declare Auto Function MessageBox Lib "user32.dll" (
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
End Class

Para aplicar os DllImportAttribute.BestFitMappingcampos , DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError, ou DllImportAttribute.ThrowOnUnmappableChar a uma declaração do Visual Basic, você deve usar o DllImportAttribute atributo em vez da Declare instrução.

Imports System.Runtime.InteropServices

Friend Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Friend Shared Function MessageBox(
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
    End Function
End Class
using System;
using System.Runtime.InteropServices;

internal static class NativeMethods
{
    [DllImport("user32.dll")]
    internal static extern int MessageBox(
        IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
using namespace System;
using namespace System::Runtime::InteropServices;

[DllImport("user32.dll")]
extern "C" int MessageBox(
    IntPtr hWnd, String* lpText, String* lpCaption, unsigned int uType);

Ajustando a definição

Quer você os defina explicitamente ou não, os campos de atributo estão em ação definindo o comportamento do código gerenciado. A invocação de plataforma opera de acordo com os valores padrão definidos em vários campos que existem como metadados em um assembly. Você pode alterar esse comportamento padrão ajustando os valores de um ou mais campos. Em muitos casos, você usa o DllImportAttribute para definir um valor.

A tabela a seguir lista o conjunto completo de campos de atributo que pertencem à invocação de plataforma. Para cada campo, a tabela inclui o valor padrão e um link para informações sobre como usar esses campos para definir funções DLL não gerenciadas.

Campo Descrição
BestFitMapping Habilita ou desabilita o mapeamento de melhor ajuste.
CallingConvention Especifica a convenção de chamada a ser usada na passagem de argumentos de método. O padrão é WinAPI, que corresponde para __stdcall as plataformas baseadas em Intel de 32 bits.
CharSet Controla o mangling de nome e a maneira como os argumentos de cadeia de caracteres devem ser empacotados para a função. A predefinição é CharSet.Ansi.
EntryPoint Especifica o ponto de entrada DLL a ser chamado.
ExactSpelling Controla se um ponto de entrada deve ser modificado para corresponder ao conjunto de caracteres. O valor padrão varia de acordo com a linguagem de programação.
PreserveSig Controla se a assinatura do método gerenciado deve ser transformada em uma assinatura não gerenciada que retorna um HRESULT e tem um argumento adicional [out, retval] para o valor de retorno.

O padrão é true (a assinatura não deve ser transformada).
SetLastError Permite que o chamador use a Marshal.GetLastWin32Error função API para determinar se ocorreu um erro durante a execução do método. No Visual Basic, o padrão é true; em C# e C++, o padrão é false.
ThrowOnUnmappableChar Controla o lançamento de uma exceção em um caractere Unicode não mapeável que é convertido em um caractere ANSI "?"

Para obter informações de referência detalhadas, consulte DllImportAttribute.

A plataforma invoca considerações de segurança

O Assert, Denye os PermitOnly membros da enumeração são referidos como modificadores de caminhada de SecurityAction pilha. Esses membros serão ignorados se forem usados como atributos declarativos em declarações de invocação de plataforma e instruções IDL (COM Interface Definition Language).

Exemplos de invocação de plataforma

Os exemplos de invocação de plataforma nesta seção ilustram o RegistryPermission uso do atributo com os modificadores de caminhada de pilha.

No exemplo a seguir, os SecurityActionAssertmodificadores , Denye PermitOnly são ignorados.

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionAssert();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

No entanto, o Demand modificador no exemplo a seguir é aceito.

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

SecurityAction Os modificadores funcionam corretamente se forem colocados em uma classe que contém (encapsula) a chamada de invocação de plataforma.

      [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
public ref class PInvokeWrapper  
{  
public:  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
};  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
class PInvokeWrapper  
{  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
}  

SecurityAction Os modificadores também funcionam corretamente em um cenário aninhado onde são colocados no chamador da chamada de invocação da plataforma:

      {  
public ref class PInvokeWrapper  
public:  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
  
    [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
};  
class PInvokeScenario  
{  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionInternal();  
  
    [RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
}  

Exemplos de interoperabilidade COM

Os exemplos de interoperabilidade COM nesta seção ilustram o RegistryPermission uso do atributo com os modificadores de caminhada de pilha.

As seguintes declarações de interface de interoperabilidade COM ignoram os Assertmodificadores , Denye PermitOnly de forma semelhante aos exemplos de invocação de plataforma na seção anterior.

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDenyStubsItf  
{  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

Além disso, o Demand modificador não é aceito em cenários de declaração de interface de interoperabilidade COM, conforme mostrado no exemplo a seguir.

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDemandStubsItf  
{  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

Consulte também