- 題名: GetOpenFileNameで複数のファイル名を取得する方法
- 日時: 2007/05/01 17:56:11
- ID: 19644
- この記事の返信元:
- (なし)
- この記事への返信:
- [19645] Re[1]: GetOpenFileNameで複数のファイル名を取得する方法2007/05/01 18:35:06
- ツリーを表示
早速の回答ありがとうございます。
lpstrFile をIntPtr型に変更し、Char型配列(またはByte型配列)にセットしてから取り出してみたところ、
複数のファイル名を取得することができました。本当にありがとうございました。
変更したコードは以下の通りです。
Private Const FILENAMES_BYTES As Integer = 512
Public Function ShowDialog() As DialogResult
Dim ofn As OPENFILENAME = Nothing
Dim pFile As IntPtr = Marshal.StringToHGlobalUni(New String(vbNullChar, FILENAMES_BYTES))
Dim fList As New List(Of String)
ofn.lStructSize = Marshal.SizeOf(ofn)
ofn.lpstrFilter = "All Files(*.*)" & vbNullChar & "*.*" & vbNullChar & vbNullChar
ofn.nFilterIndex = 1
ofn.lpstrFile = pFile
ofn.nMaxFile = FILENAMES_BYTES
ofn.lpstrFileTitle = New String(vbNullChar, FILENAMES_BYTES)
ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length
ofn.hwndOwner = Form.ActiveForm.Handle
ofn.Flags = OFN_EXPLORER Or OFN_HIDEREADONLY Or OFN_ALLOWMULTISELECT
If GetOpenFileName(ofn) = 0 Then
Marshal.FreeHGlobal(pFile)
Return DialogResult.Cancel
End If
fList = GetFileList(pFile)
Marshal.FreeHGlobal(pFile)
If fList.Count >= 2 Then
Dim i As Integer
ReDim m_FileNames(fList.Count - 2)
For i = 0 To fList.Count - 2
m_FileNames(i) = Path.Combine(fList(0), fList(i + 1))
Next
Else
m_FileNames = New String() {fList(0)}
End If
Return DialogResult.OK
End Function
Private Function GetFileList(ByVal p As IntPtr) As List(Of String)
Dim cFileNames(FILENAMES_BYTES / 2 - 1) As Char
Dim tempFileName As String = ""
Dim files As New List(Of String)
Dim i As Integer
Marshal.Copy(p, cFileNames, 0, FILENAMES_BYTES / 2)
For i = 0 To FILENAMES_BYTES / 2 - 1
If cFileNames(i) = vbNullChar Then
'NULL文字を見つけたらリストに追加
files.Add(tempFileName)
'NULL文字が連続したら終了
If cFileNames(i + 1) = vbNullChar Then
Exit For
End If
tempFileName = ""
Else
tempFileName &= cFileNames(i).ToString()
End If
Next
Return files
End Function
一文字ずつToStringして&でくっつけていくよりも
Stringクラスのコンストラクタを使ったほうが効率よさそう。
Dim start As Integer = 0
Dim length As Integer = 0
For i As Integer = 0 To FILENAMES_BYTES / 2 - 1
If cFileNames(i) = vbNullChar Then
files.Add(New String(cFileNames, start, length))
start = i + 1
length = 0
If cFileNames(i + 1) = vbNullChar Then
Exit For
End If
Else
length = length + 1
End If
Next
分類:[.NET]
現在、文字エンコードの指定ができるOpenFileDialogを作っています。 そこで、OFN_ALLOWMULTISELECTを指定して、複数のファイル名を取得しようとしても、ディレクトリ名しか取得できません。 いくつかのサイトで調べてみたところ、本来は 「ディレクトリ名+NULL文字+ファイル名1+NULL文字 ... ファイル名N+NULL文字+NULL文字」 という形式で取得できるようです。 どこに問題があるか、ご教授願えませんでしょうか? 尚、1つのファイル名ならば問題なく取得できます。 以下は、必要だと思われる部分を取り出したコードです。 Imports System.IO Imports System.Windows.Forms Imports System.Runtime.InteropServices Public Class xOpenFileDialog <DllImport("Comdlg32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _ Private Shared Function GetOpenFileName( _ <MarshalAs(UnmanagedType.Struct)> ByRef lpofn As OPENFILENAME) As Boolean End Function Private Const OFN_ALLOWMULTISELECT As Integer = &H200 Private Const OFN_EXPLORER As Integer = &H80000 Private Const OFN_HIDEREADONLY As Integer = &H4 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _ Private Structure OPENFILENAME Public lStructSize As Integer Public hwndOwner As IntPtr Public hInstance As Integer <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrFilter As String <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrCustomFilter As String Public nMaxCustFilter As Integer Public nFilterIndex As Integer <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrFile As String Public nMaxFile As Integer <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrFileTitle As String Public nMaxFileTitle As Integer <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrInitialDir As String <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrTitle As String Public Flags As Integer Public nFileOffset As Short Public nFileExtension As Short <MarshalAs(UnmanagedType.LPTStr)> _ Public lpstrDefExt As String Public lCustData As Integer Public lpfnHook As Integer <MarshalAs(UnmanagedType.LPTStr)> _ Public lpTemplateName As String 'only if on nt 5.0 or higher Public pvReserved As Integer Public dwReserved As Integer Public FlagsEx As Integer End Structure Private m_FileNames() As String = Nothing Public Property FileName() As String Get If m_FileNames Is Nothing Then Return "" Else Return m_FileNames(0) End If End Get Set(ByVal value As String) m_FileNames = New String() {value} End Set End Property Public Property FileNames() As String() Get Return m_FileNames End Get Set(ByVal value As String()) m_FileNames = value End Set End Property Public Function ShowDialog() As DialogResult Dim ofn As OPENFILENAME = Nothing ofn.lStructSize = Marshal.SizeOf(ofn) ofn.lpstrFilter = "All Files(*.*)" & vbNullChar & "*.*" & vbNullChar & vbNullChar ofn.nFilterIndex = 1 ofn.lpstrFile = New String(vbNullChar, 512) ofn.nMaxFile = ofn.lpstrFile.Length ofn.lpstrFileTitle = New String(vbNullChar, 512) ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length ofn.hwndOwner = Form.ActiveForm.Handle ofn.Flags = OFN_EXPLORER Or OFN_HIDEREADONLY Or OFN_ALLOWMULTISELECT If GetOpenFileName(ofn) = 0 Then Return DialogResult.Cancel End If Console.WriteLine(ofn.lpstrFile.Length) Dim doubleNullIndex As Integer = ofn.lpstrFile.IndexOf(vbNullChar & vbNullChar) If doubleNullIndex < 0 Then m_FileNames = New String() {ofn.lpstrFile} Else '複数選択の場合 ofn.lpstrFile = ofn.lpstrFile.Substring(0, ofn.lpstrFile.IndexOf(vbNullChar & vbNullChar)) Dim fName() As String = ofn.lpstrFile.Split(vbNullChar) ReDim m_FileNames(fName.Length - 2) Dim i As Integer For i = 0 To m_FileNames.Length - 2 m_FileNames(i) = Path.Combine(fName(0), fName(i + 1)) Next End If Return DialogResult.OK End Function End Class