Amostra de OpenFileDlg
Este exemplo demonstra como chamar uma função não gerenciada que espera um ponteiro para uma estrutura que contém uma seqüência de caracteres. Além disso, ele demonstra como usar uma classe gerenciada para representar uma estrutura não gerenciada, como aplicar o InAttribute e OutAttribute atributos para empacotar a classe de volta para o chamador e como declarar e inicializar diferentes campos da classe para produzir a representação correta não gerenciado.
O exemplo de OpenFileDlg usa a seguinte função não gerenciada, mostrada com sua declaração de função original:
GetOpenFileName exportada de Comdlg32. dll.
BOOL GetOpenFileName(LPOPENFILENAME lpofn);
O LPOPENFILENAME estrutura da API Win32, que é passado para a função anterior, contém os seguintes elementos:
typedef struct tagOFN {
DWORD lStructSize;
//…
LPCTSTR lpstrFilter;
//…
LPTSTR lpstrFile;
DWORD nMaxFile;
LPTSTR lpstrFileTitle;
DWORD nMaxFileTitle;
LPCTSTR lpstrInitialDir;
LPCTSTR lpstrTitle;
//…
LPCTSTR lpstrDefExt;
//…
} OPENFILENAME, *LPOPENFILENAME;
Neste exemplo, o OpenFileName classe contém os elementos da estrutura original como membros de classe. A estrutura não gerenciada é declarada como uma classe em vez de como uma estrutura gerenciada, para mostrar como uma classe pode ser usada quando a função não gerenciada espera um ponteiro para uma estrutura. Como uma classe gerenciada é um tipo de referência, quando ele é passado por valor, um ponteiro para a classe é passado para o código não gerenciado. Isso é exatamente o que espera a função não gerenciada.
O StructLayoutAttribute atributo é aplicado à classe para garantir que os membros são dispostos em memória seqüencialmente, na ordem em que aparecem. O CharSet campo será definido para essa plataforma chamar pode escolher entre ANSI e Unicode formatos em tempo de execução, com base na plataforma de destino.
O LibWrap classe contém o protótipo gerenciado da GetOpenFileName método, que passa a OpenFileName classe como um parâmetro In/Out. Aplicando InAttribute e OutAttribute explicitamente, o exemplo garante que OpenFileName é empacotado como um parâmetro In/Out e o chamador podem ver as alterações empacotadas de volta. (Para desempenho, o padrão atributo direcional de uma classe é no, o que impede que o chamador vendo as alterações empacotado back.) O App classe cria uma nova instância da OpenFileName classe e usa o Marshal.SizeOf método para determinar o tamanho, em bytes, da estrutura não gerenciada.
A declaração de protótipos
' Declare a class member for each structure element.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class OpenFileName
Public structSize As Integer = 0
Public hwnd As IntPtr = IntPtr.Zero
Public hinst As IntPtr = IntPtr.Zero
Public filter As String = Nothing
Public custFilter As String = Nothing
Public custFilterMax As Integer = 0
Public filterIndex As Integer = 0
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 flags As Integer = 0
Public fileOffset As Short = 0
Public fileExtMax As Short = 0
Public defExt as String = Nothing
Public custData As Integer = 0
Public pHook As IntPtr = IntPtr.Zero
Public template As String = Nothing
End Class
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
// Declare a class member for each structure element.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class OpenFileName
{
public int structSize = 0;
public IntPtr hwnd = IntPtr.Zero;
public IntPtr hinst = IntPtr.Zero;
public string filter = null;
public string custFilter = null;
public int custFilterMax = 0;
public int filterIndex = 0;
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 int flags = 0;
public short fileOffset = 0;
public short fileExtMax = 0;
public string defExt = null;
public int custData = 0;
public IntPtr pHook = IntPtr.Zero;
public string template = 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);
}
// Declare a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Auto)]
public ref class OpenFileName
{
public:
int structSize;
IntPtr hwnd;
IntPtr hinst;
String^ filter;
String^ custFilter;
int custFilterMax;
int filterIndex;
String^ file;
int maxFile;
String^ fileTitle;
int maxFileTitle;
String^ initialDir;
String^ title;
int flags;
short fileOffset;
short fileExtMax;
String^ defExt;
int custData;
IntPtr pHook;
String^ tmplate;
OpenFileName()
{
// Initialize the fields.
for each (FieldInfo^ fi in this->GetType()->GetFields())
{
fi->SetValue(this, nullptr);
}
}
};
public ref class LibWrap
{
public:
// Declare a managed prototype for the unmanaged function.
[DllImport("Comdlg32.dll", CharSet=CharSet::Auto)]
static bool GetOpenFileName([In, Out] OpenFileName^ ofn);
};
Chamando funções
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
End Class
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);
}
}
}
public ref class App
{
public:
static void Main()
{
OpenFileName^ ofn = gcnew OpenFileName();
ofn->structSize = Marshal::SizeOf(ofn);
ofn->filter = "Log files\0*.log\0Batch files\0*.bat\0";
ofn->file = gcnew String(gcnew array<Char>(256));
ofn->maxFile = ofn->file->Length;
ofn->fileTitle = gcnew String(gcnew array<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);
}
}
};
Consulte também
Conceitos
Tipos de dados de invocação de plataforma
Padrão de empacotamento de Strings
Outros recursos
Creating Prototypes in Managed Code