Compartilhar via


Estruturas de passagem

Muitas funções não gerenciadas esperam que você passe, sistema autônomo um parâmetro da função, sistema autônomo membros do estruturas (tipos definidos pelo usuário no Visual Basic) ou membros de classes definidas no código gerenciado.Ao passar estruturas ou classes para código não gerenciado usando invocação de plataforma, você deve fornecer informações adicionais para preservar o layout original e o alinhamento.Este tópico apresenta o StructLayoutAttribute atributo use para definir tipos formatados. Para gerenciado estruturas e classes, você pode selecionar vários comportamentos previsível layout fornecidos pelo LayoutKind enumeração.

Uma diferença importante entre tipos de estrutura e a classe é fundamental aos conceitos apresentados neste tópico.Estruturas são tipos de valor e as classes são tipos de referência — classes sempre fornecem pelo menos um nível de indireção memória (um ponteiro para um valor).Essa diferença é importante porque funções não gerenciadas com freqüência exigem indireção, sistema autônomo mostrados pelas assinaturas na primeira coluna da tabela a seguir.O gerenciado declarações de estrutura e a classe nas colunas restantes mostram o grau ao qual você pode ajustar o nível de indireção na sua declaração.

Assinatura não gerenciada

gerenciado declaração:

Nenhum caminho indireto

struct MyStruct(…);

gerenciado declaração:

um nível de engano

class MyStruct(…);

DoWork(MyStruct x);

As demandas de níveis de indireção de zero.

DoWork(ByVal x As MyStruct)

Adiciona zero níveis de indireção.

Não é possível porque já existe um nível de engano.

DoWork(MyStruct* x);

Exige um nível de engano.

DoWork(ByRef x As MyStruct)

Adiciona um nível de engano.

DoWork(ByVal x As MyStruct)

Adiciona zero níveis de indireção.

DoWork(MyStruct** x);

Exige dois níveis de indireção.

Not possible because ByRef ByRef cannot be used.

DoWork(ByRef x As MyStruct)

Adiciona um nível de engano.

A tabela descreve as diretrizes a seguir para declarações de invocação de plataforma:

  • Use uma estrutura passada por valor quando a função não gerenciada não exige nenhum indireção.

  • Use uma estrutura passado por referência ou uma classe passado por valor quando a função não gerenciada exige um nível de engano.

  • Use uma classe passada por referência quando a função não gerenciada exige dois níveis de indireção.

Declarando e estruturas de passagem

O exemplo a seguir mostra sistema autônomo definir o Point e Rect estruturas no código gerenciado e passar sistema autônomo tipos sistema autônomo parâmetro para o PtInRect função o User32 arquivo .dll.PtInRect tem a seguinte assinatura não gerenciada:

BOOL PtInRect(const RECT *lprc, POINT pt);

Observe que você deve passar a estrutura Rect por referência, desde que a função espera um ponteiro para um tipo RECT.

Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Sequential)> Public Structure Point
    Public x As Integer
    Public y As Integer
End Structure

Public Structure <StructLayout(LayoutKind.Explicit)> Rect
    <FieldOffset(0)> Public left As Integer
    <FieldOffset(4)> Public top As Integer
    <FieldOffset(8)> Public right As Integer
    <FieldOffset(12)> Public bottom As Integer
End Structure

Class Win32API    
    Declare Auto Function PtInRect Lib "user32.dll" _
    (ByRef r As Rect, p As Point) As Boolean
End Class
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct Point {
    public int x;
    public int y;
}   

[StructLayout(LayoutKind.Explicit)]
public struct Rect {
    [FieldOffset(0)] public int left;
    [FieldOffset(4)] public int top;
    [FieldOffset(8)] public int right;
    [FieldOffset(12)] public int bottom;
}   

class Win32API {
    [DllImport("User32.dll")]
    public static extern bool PtInRect(ref Rect r, Point p);
}

Classes de passagem e Delcaring

Você pode passar membros de uma classe para uma função DLL não gerenciada, desde que a classe tem um layout fixo do membro.O exemplo a seguir demonstra como passar os membros a MySystemTime classe, que são definidos em ordem seqüencial, como o GetSystemTime no arquivo User32.dll.GetSystemTime tem a seguinte assinatura não gerenciada:

void GetSystemTime(SYSTEMTIME* SystemTime);

Ao contrário de tipos de valor, classes sempre têm pelo menos um nível de indireção.

Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic

<StructLayout(LayoutKind.Sequential)> Public Class MySystemTime
    Public wYear As Short
    Public wMonth As Short
    Public wDayOfWeek As Short 
    Public wDay As Short
    Public wHour As Short
    Public wMinute As Short
    Public wSecond As Short
    Public wMiliseconds As Short
End Class

Public Class Win32
    Declare Auto Sub GetSystemTime Lib "Kernel32.dll"(sysTime _
        As MySystemTime)
    Declare Auto Function MessageBox Lib "User32.dll"(hWnd As Integer, _
        txt As String, caption As String, Typ As Integer) As Integer
End Class

Public Class TestPlatformInvoke    
    Public Shared Sub Main()
        Dim sysTime As New MySystemTime()
        Win32.GetSystemTime(sysTime)

        Dim dt As String
        dt = "System time is:" & ControlChars.CrLf & _
              "Year: " & sysTime.wYear & _
              ControlChars.CrLf & "Month: " & sysTime.wMonth & _
              ControlChars.CrLf & "DayOfWeek: " & sysTime.wDayOfWeek & _
              ControlChars.CrLf & "Day: " & sysTime.wDay
        Win32.MessageBox(0, dt, "Platform Invoke Sample", 0)      
    End Sub
End Class
[StructLayout(LayoutKind.Sequential)]
public class MySystemTime {
    public ushort wYear; 
    public ushort wMonth;
    public ushort wDayOfWeek; 
    public ushort wDay; 
    public ushort wHour; 
    public ushort wMinute; 
    public ushort wSecond; 
    public ushort wMilliseconds; 
}
class Win32API {
    [DllImport("Kernel32.dll")]
    public static extern void GetSystemTime(MySystemTime st);
}

Consulte também

Referência

Classe StructLayoutAttribute

Classe StructLayoutAttribute

Classe FieldOffsetAttribute

Outros recursos

Chamando uma função DLL