Пример объединений
В этом примере показан способ передачи в неуправляемую функцию, ожидающей объединение, в качестве параметров структур, содержащих только типы значений, а также структур, содержащих тип значения и строку. Объединение представляет собой ячейку памяти, которая может совместно использоваться двумя и более переменными.
В примере объединений используются следующие неуправляемые функции, показанные вместе со своим исходным объявлением).
Функция TestUnion, экспортированная из PinvokeLib.dll.
void TestUnion(MYUNION u, int type);
PinvokeLib.dll — это специализированная неуправляемая библиотека, содержащая реализацию ранее описанной функции и два объединения, MYUNION and MYUNION2. Объединение содержит следующие элементы:
union MYUNION
{
int number;
double d;
}
union MYUNION2
{
int i;
char str[128];
};
В управляемом коде объединения определяются как структуры. Структура MyUnion в качестве своих членов содержит два типа значений: целочисленные и с двойной точностью. Для управления точным положением каждого члена данных задается атрибут StructLayoutAttribute. Атрибут FieldOffsetAttribute предоставляет физическое положение полей внутри неуправляемого представления объединения. Обратите внимание, что значения смещения у обоих членов одинаковы, что позволяет членам определять один и тот же участок памяти.
Объединения MyUnion2_1 и MyUnion2_2 содержат тип значения (целое число) и строку, соответственно. В управляемом коде типы значения и ссылочные типы не перекрываются. Чтобы при вызове той же самой неуправляемой функции вызывающий объект мог использовать оба типа, в данном примере применяется перегрузка метода. Структура MyUnion2_1 задана явным образом и использует точное значение смещения. Напротив, MyUnion2_2 использует последовательную структуру, поскольку структуры, заданные явным образом, нельзя использовать вместе со ссылочными типами. Атрибут MarshalAsAttribute задает для перечисления UnmanagedType значение ByValTStr, используемое для идентификации встроенных массивов знаков фиксированной длины, появляющихся в неуправляемом представлении объединения.
Класс LibWrap содержит прототипы для методов TestUnion и TestUnion2. TestUnion2 перегружается для объявления MyUnion2_1 или MyUnion2_2 как параметров.
Объявление прототипов
' Declares managed structures instead of unions.
<StructLayout(LayoutKind.Explicit)> _
Public Structure MyUnion
<FieldOffset(0)> Public i As Integer
<FieldOffset(0)> Public d As Double
End Structure 'MyUnion
<StructLayout(LayoutKind.Explicit, Size := 128)> _
Public Structure MyUnion2_1
<FieldOffset(0)> Public i As Integer
End Structure 'MyUnion2_1
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyUnion2_2
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := 128)> _
Public str As String
End Structure 'MyUnion2_2
Public Class LibWrap
' Declares managed prototypes for unmanaged function.
Declare Sub TestUnion Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion, ByVal type As Integer)
Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion2_1, ByVal type As Integer)
Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion2_2, ByVal type As Integer)
End Class 'LibWrap
// Declares managed structures instead of unions.
[StructLayout(LayoutKind.Explicit)]
public struct MyUnion
{
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public double d;
}
[StructLayout(LayoutKind.Explicit, Size=128)]
public struct MyUnion2_1
{
[FieldOffset(0)]
public int i;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyUnion2_2
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public string str;
}
public class LibWrap
{
// Declares managed prototypes for unmanaged function.
[DllImport( "..\\LIB\\PInvokeLib.dll")]
public static extern void TestUnion(MyUnion u, int type);
[DllImport( "..\\LIB\\PInvokeLib.dll")]
public static extern void TestUnion2(MyUnion2_1 u, int type);
[DllImport( "..\\LIB\\PInvokeLib.dll")]
public static extern void TestUnion2(MyUnion2_2 u, int type);
}
// Declares managed structures instead of unions.
[StructLayout(LayoutKind::Explicit)]
public value struct MyUnion
{
public:
[FieldOffset(0)]
int i;
[FieldOffset(0)]
double d;
};
[StructLayout(LayoutKind::Explicit, Size=128)]
public value struct MyUnion2_1
{
public:
[FieldOffset(0)]
int i;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyUnion2_2
{
public:
[MarshalAs(UnmanagedType::ByValTStr, SizeConst=128)]
String^ str;
};
public ref class LibWrap
{
public:
// Declares managed prototypes for unmanaged function.
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestUnion(MyUnion u, int type);
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestUnion2(MyUnion2_1 u, int type);
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestUnion2(MyUnion2_2 u, int type);
};
Вызов функций
Public Class App
Public Shared Sub Main()
Dim mu As New MyUnion()
mu.i = 99
LibWrap.TestUnion(mu, 1)
mu.d = 99.99
LibWrap.TestUnion(mu, 2)
Dim mu2_1 As New MyUnion2_1()
mu2_1.i = 99
LibWrap.TestUnion2(mu2_1, 1)
Dim mu2_2 As New MyUnion2_2()
mu2_2.str = "*** string ***"
LibWrap.TestUnion2(mu2_2, 2)
End Sub 'Main
End Class 'App
public class App
{
public static void Main()
{
MyUnion mu = new MyUnion();
mu.i = 99;
LibWrap.TestUnion(mu, 1);
mu.d = 99.99;
LibWrap.TestUnion(mu, 2);
MyUnion2_1 mu2_1 = new MyUnion2_1();
mu2_1.i = 99;
LibWrap.TestUnion2(mu2_1, 1);
MyUnion2_2 mu2_2 = new MyUnion2_2();
mu2_2.str = "*** string ***";
LibWrap.TestUnion2(mu2_2, 2);
}
}
public ref class App
{
public:
static void Main()
{
MyUnion mu;// = new MyUnion();
mu.i = 99;
LibWrap::TestUnion(mu, 1);
mu.d = 99.99;
LibWrap::TestUnion(mu, 2);
MyUnion2_1 mu2_1;// = new MyUnion2_1();
mu2_1.i = 99;
LibWrap::TestUnion2(mu2_1, 1);
MyUnion2_2 mu2_2;// = new MyUnion2_2();
mu2_2.str = "*** string ***";
LibWrap::TestUnion2(mu2_2, 2);
}
};
См. также
Основные понятия
Маршалинг классов, структур и объединений