OpenFileDlg 샘플
이 샘플에서는 문자열을 포함하는 구조체에 대한 포인터를 필요로 하는 관리되지 않는 함수의 호출 방법을 보여 줍니다. 또한 관리되는 클래스를 사용하여 관리되지 않는 구조체를 나타내는 방법과 InAttribute 및 OutAttribute 특성을 적용하여 클래스를 호출자로 다시 마샬링하는 방법, 그리고 클래스의 여러 가지 필드를 선언하고 초기화하여 관리되지 않는 표현을 올바르게 생성하는 방법을 보여 줍니다.
OpenFileDlg 샘플에서는 다음의 관리되지 않는 함수를 사용합니다. 이 함수는 원래의 함수 선언과 함께 표시되어 있습니다.
Comdlg32.dll에서 내보낸 GetOpenFileName
BOOL GetOpenFileName(LPOPENFILENAME lpofn);
위의 함수로 전달되는 Win32 API의 LPOPENFILENAME 구조체에는 다음 요소가 포함되어 있습니다.
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 클래스에는 OpenFileName 클래스를 In/Out 매개 변수를 통해 전달하는 GetOpenFileName 메서드의 관리되는 프로토타입이 포함되어 있습니다. 이 샘플에서는 OpenFileName이 In/Out 매개 변수를 통해 마샬링되고 호출자가 다시 마샬링된 변경 내용을 볼 수 있도록 InAttribute 및 OutAttribute를 명시적으로 적용합니다. 성능상의 이유로 클래스에 대한 기본 방향 특성은 호출자가 다시 마샬링된 변경 내용을 볼 수 없도록 하는 In입니다. App클래스에서는 OpenFileName 클래스의 새 인스턴스를 만들고 Marshal.SizeOf 메서드를 사용하여 관리되지 않는 구조체의 크기를 바이트 단위로 결정합니다.
프로토타입 선언
' 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);
};
함수 호출
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);
}
}
};
참고 항목
개념
기타 리소스
Creating Prototypes in Managed Code