Пример OpenFileDlg
Обновлен: Ноябрь 2007
В этом примере показан способ вызова неуправляемой функции, ожидающей указатель на структуру, содержащую строку. Далее показывается, как использовать управляемый класс для представления неуправляемой структуры, как применять атрибуты InAttribute и OutAttribute для маршалинга класса обратно в вызывающий объект, а также как объявить и инициализировать различные поля класса для создания правильного неуправляемого представления.
В примере OpenFileDlg используется следующая неуправляемая функция, показанная со своим исходным объявлением.
Функция GetOpenFileName, экспортированная из Comdlg32.dll.
BOOL GetOpenFileName(LPOPENFILENAME lpofn);
Структура LPOPENFILENAME из интерфейса Win32 API, передаваемая предыдущей функции, содержит следующие элементы:
typedef struct tagOFN {
DWORD lStructSize;
//…
LPCTSTR lpstrFilter;
//…
LPTSTR lpstrFile;
DWORD nMaxFile;
LPTSTR lpstrFileTitle;
DWORD nMaxFileTitle;
LPCTSTR lpstrInitialDir;
LPCTSTR lpstrTitle;
//…
LPCTSTR lpstrDefExt;
//…
} OPENFILENAME, *LPOPENFILENAME;
В этом примере класс OpenFileName содержит элементы исходной структуры в качестве членов класса. Неуправляемая структура объявляется как класс, а не как управляемая структура, чтобы показать способ использования класса, когда неуправляемая функция ожидает указатель на структуру. Поскольку при передаче по значению управляемый класс является ссылочным типом, в неуправляемый код передается указатель на класс. Именно этот аргумент и ожидается функцией.
Атрибут StructLayoutAttribute применяется к классу, чтобы гарантировать размещение членов в памяти последовательно, в порядке их появления. Значение поля CharSet при вызове неуправляемого кода во время выполнения определяет выбор одного из двух форматов (ANSI или Юникод), в зависимости от целевой платформы.
Класс LibWrap содержит управляемый прототип метода GetOpenFileName, передающий класс OpenFileName в качестве параметра In/Out. Применение InAttribute и OutAttribute, позволяет гарантировать маршалинг класса OpenFileName как параметра In или Out, при этом вызывающий объект отслеживает маршалинг изменений в обратном направлении. (Для повышения производительности атрибутом направления по умолчанию является In, что не позволяет вызывающему объекту отслеживать изменения, упаковываемые и передаваемые обратно.) Класс App создает новый экземпляр класса OpenFileName и использует метод Marshal.SizeOf, чтобы определить размер неуправляемой структуры в байтах.
Исходный код для следующих примеров кода см. в разделе Пример технологии вызова неуправляемого кода для .NET Framework.
Объявление прототипов
' Declare a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Auto )> _
Public Class OpenFileName
Public structSize As Integer = 0
'…
Public filter As String = Nothing
'…
Public file As String = Nothing
Public maxFile As Integer = 0
Public fileTitle As String = Nothing
Public maxFileTitle As Integer = 0
Public initialDir As String = Nothing
Public title As String = Nothing
'…
Public defExt As String = Nothing
'…
End Class 'OpenFileName
Public Class LibWrap
' Declare managed prototype for the unmanaged function.
Declare Auto Function GetOpenFileName Lib "Comdlg32.dll" ( _
<[In], Out> ByVal ofn As OpenFileName ) As Boolean
End Class 'LibWrap
// Declare a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Auto )]
public class OpenFileName
{
public int structSize = 0;
//…
public String filter = null;
//…
public String file = null;
public int maxFile = 0;
public String fileTitle = null;
public int maxFileTitle = 0;
public String initialDir = null;
public String title = null;
//…
public String defExt = null;
//…
}
public class LibWrap
{
// Declare a managed prototype for the unmanaged function.
[ DllImport( "Comdlg32.dll", CharSet=CharSet.Auto )]
public static extern bool GetOpenFileName([ In, Out ]
OpenFileName ofn );
}
Вызов функций
Public Class App
Public Shared Sub Main()
Dim ofn As New OpenFileName()
ofn.structSize = Marshal.SizeOf( ofn )
ofn.filter = "Log files" & ChrW(0) & "*.log" & ChrW(0) & _
"Batch files" & ChrW(0) & "*.bat" & ChrW(0)
ofn.file = New String( New Char( 256 ) {})
ofn.maxFile = ofn.file.Length
ofn.fileTitle = New String( New Char( 64 ) {})
ofn.maxFileTitle = ofn.fileTitle.Length
ofn.initialDir = "C:\"
ofn.title = "Open file called using platform invoke..."
ofn.defExt = "txt"
If LibWrap.GetOpenFileName( ofn ) Then
Console.WriteLine( "Selected file with full path: {0}", _
ofn.file )
End If
End Sub 'Main
End Class 'OpenFileDlgSample
public class App
{
public static void Main()
{
OpenFileName ofn = new OpenFileName();
ofn.structSize = Marshal.SizeOf( ofn );
ofn.filter = "Log files\0*.log\0Batch files\0*.bat\0";
ofn.file = new String( new char[ 256 ]);
ofn.maxFile = ofn.file.Length;
ofn.fileTitle = new String( new char[ 64 ]);
ofn.maxFileTitle = ofn.fileTitle.Length;
ofn.initialDir = "C:\\";
ofn.title = "Open file called using platform invoke...";
ofn.defExt = "txt";
if( LibWrap.GetOpenFileName( ofn ))
{
Console.WriteLine( "Selected file with full path: {0}",
ofn.file );
}
}
}
См. также
Задачи
Пример технологии вызова неуправляемого кода
Основные понятия
Типы данных вызовов неуправляемого кода