Передача структур

Обновлен: Ноябрь 2007

Для многих неуправляемых функций в качестве параметра должны быть переданы члены структур (в Visual Basic это определяемые пользователем типы) или члены классов, определяемые в управляемом коде программы. Для сохранения исходного размещения и выравнивания при передаче структур или классов в неуправляемый код необходимо предоставить дополнительные сведения при вызове неуправляемого кода. В этом разделе описывается атрибут StructLayoutAttribute, который можно использовать для определения форматированных типов. Для управляемых структур и классов можно выбрать одно из стандартных размещений, предоставленных перечислением LayoutKind.

Важнейшим из понятий, описанных в этом разделе, является существенное различие между структурами и классами как типами. Структуры представляют собой типы значений, а классы —ссылочные типы, которые всегда обеспечивают, по крайней мере, один уровень косвенного обращения к памяти (указатель на значение). Это различие очень важно, так как неуправляемые функции часто требуют косвенного обращения, что видно из примеров подписей в первом столбце следующей таблицы. Объявления управляемых структур и классов в остальных столбцах показывают, насколько возможна настройка уровня косвенного обращения в объявлении.

Неуправляемая подпись

Управляемое объявление:

без косвенного обращения

struct MyStruct(…);

Управляемое объявление:

один уровень косвенного обращения

class MyStruct(…);

DoWork(MyStruct x);

Требует отсутствия уровней косвенного обращения.

DoWork(ByVal x As MyStruct)

Добавляет ноль уровней косвенного обращения.

Невозможно, так как уже существует один уровень косвенного обращения.

DoWork(MyStruct* x);

Требует одного уровня косвенного обращения.

DoWork(ByRef x As MyStruct)

Добавляет один уровень косвенного обращения.

DoWork(ByVal x As MyStruct)

Добавляет ноль уровней косвенного обращения.

DoWork(MyStruct** x);

Требует двух уровней косвенного обращения.

Невозможно, так как объявление ByRef ByRef использовать нельзя.

DoWork(ByRef x As MyStruct)

Добавляет один уровень косвенного обращения.

Эта таблица содержит следующие указания для объявлений вызовов неуправляемого кода:

  • Если неуправляемая функция не требует косвенного обращения, структуру следует передавать по значению.

  • Если для неуправляемой функции требуется один уровень косвенного обращения, используется либо структура, передаваемая по ссылке, либо класс, передаваемый по значению.

  • Если для неуправляемой функции требуется два уровня косвенного обращения, используется класс, передаваемый по ссылке.

Объявление и передача структур

В следующем примере показано определение структур Point и Rect в управляемом коде и передача типов в качестве параметра функции PtInRect в файле библиотеки User32.dll. Для функции PtInRect используется следующая неуправляемая подпись:

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

Обратите внимание, что структуру Rect следует передавать по ссылке, так как функция должна получить указатель на тип 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);
}

Объявление и передача классов

Если для класса используется фиксированное размещение членов, их можно передавать в неуправляемую функцию DLL,. В следующем примере демонстрируется передача последовательно упорядоченных в определении членов класса MySystemTime в функцию GetSystemTime в файле User32.dll. Для функции GetSystemTime используется следующая неуправляемая подпись:

void GetSystemTime(SYSTEMTIME* SystemTime);

В отличие от типов значений для классов всегда используется, по крайней мере, один уровень косвенного обращения.

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);
}

См. также

Ссылки

Класс StructLayoutAttribute

Класс StructLayoutAttribute

Класс FieldOffsetAttribute

Другие ресурсы

Вызов функции DLL