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 para 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 a função e transmite os dados de e para a função.

Observação

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, faça o parâmetro ser do tipo IntPtr em vez do tipo String. 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 campos DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError ou DllImportAttribute.ThrowOnUnmappableChar a uma declaração do Visual Basic, deve-se usar o atributo DllImportAttribute em vez da instrução Declare.

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 conforme os valores padrão definidos em vários campos que existem como metadados em uma 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 mais adequado.
CallingConvention Especifica a convenção de chamada a ser usada na passagem de argumentos de método. O padrão é WinAPI, que corresponde a __stdcall nas plataformas Intel de 32 bits.
CharSet Controla a obfuscação de nomes e a maneira como os argumentos de cadeia de caracteres devem ser transformados para a função. A predefinição é CharSet.Ansi.
EntryPoint Especifica o ponto de entrada da 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 gerido deve ser transformada numa assinatura não-gerida que retorna um HRESULT e tem um argumento adicional [out, retval] para o valor retornado.

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

Os membros Assert, Deny e PermitOnly da enumeração SecurityAction são referidos como modificadores de percurso na 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 uso do atributo RegistryPermission com os modificadores de percurso de pilha.

As seguintes declarações de interface de interoperabilidade COM ignoram os modificadores Assert, Deny, e PermitOnly 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();  
}  

Ver também