다음을 통해 공유


OpenFileDlg 샘플

이 샘플에서는 문자열을 포함하는 구조체에 대한 포인터를 필요로 하는 관리되지 않는 함수의 호출 방법을 보여 줍니다. 또한 관리되는 클래스를 사용하여 관리되지 않는 구조체를 나타내는 방법과 InAttributeOutAttribute 특성을 적용하여 클래스를 호출자로 다시 마샬링하는 방법, 그리고 클래스의 여러 가지 필드를 선언하고 초기화하여 관리되지 않는 표현을 올바르게 생성하는 방법을 보여 줍니다.

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 매개 변수를 통해 마샬링되고 호출자가 다시 마샬링된 변경 내용을 볼 수 있도록 InAttributeOutAttribute를 명시적으로 적용합니다. 성능상의 이유로 클래스에 대한 기본 방향 특성은 호출자가 다시 마샬링된 변경 내용을 볼 수 없도록 하는 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