C#中使用windows檔案選擇器選擇多個檔案
阿新 • • 發佈:2021-06-16
C#中使用windows檔案選擇器選擇多個檔案
- 呼叫windows的檔案選擇視窗需要使用Comdlg32.h的方法,詳見GetOpenFileNameA,這個方法需要傳遞一個包含檔案選擇所需所有資訊的類,詳見OPENFILENAMEA,以下是這個類的定義:
using System; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class OpenFileName { public int structSize = 0; public IntPtr dlgOwner = IntPtr.Zero; public IntPtr instance = IntPtr.Zero; public String filter = null; public String customFilter = null; public int maxCustFilter = 0; public int filterIndex = 0; public IntPtr file; 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 fileExtension = 0; public String defExt = null; public IntPtr custData = IntPtr.Zero; public IntPtr hook = IntPtr.Zero; public String templateName = null; public IntPtr reservedPtr = IntPtr.Zero; public int reservedInt = 0; public int flagsEx = 0; }
需要注意的是,file欄位並不是用String型別儲存,這個欄位用於儲存使用者選擇的檔名,當只選擇一個檔案時,這個欄位返回選擇檔案的全路徑,當選擇多個檔案時,會返回資料夾路徑以及選擇的多個檔名組成的字串,如果是使用的資源管理器風格,會以 NULL 分割,如果使用的是舊式對話方塊風格時,會以 空格 分割。
一般而言,會使用資源管理器風格。(舊式風格我嘗試過,介面和操作較為反人類)
使用IntPtr儲存file欄位的原因就在於此,因為String型別以 NULL 結尾,選中多個檔案時,String型別的file欄位只能獲取到資料夾路徑。
- 使用 DllImport 屬性呼叫系統函式
using System.Runtime.InteropServices; public class LocalDialog { //連結指定系統函式 開啟檔案對話方塊 [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] public static extern bool GetOpenFileName([In, Out] OpenFileName ofn); }
- 使用方法
public List<string> FileSelector() { List<string> fileFullNames = new List<string>(); OpenFileName openFileName = new OpenFileName(); openFileName.structSize = Marshal.SizeOf(openFileName); openFileName.filter = "模型檔案(*.fbx,*.obj)\0*.fbx;*.obj\0"; openFileName.fileTitle = new string(new char[64]); openFileName.maxFileTitle = openFileName.fileTitle.Length; openFileName.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//預設路徑 openFileName.title = "選擇fbx檔案"; openFileName.flags = 0x00000004 | 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008 | 0x00000200; // Create buffer for file names string fileNames = new String(new char[2048]); openFileName.file = Marshal.StringToBSTR(fileNames); openFileName.maxFile = fileNames.Length; if (LocalDialog.GetOpenFileName(openFileName)) { List<string> selectedFilesList = new List<string>(); long pointer = (long)openFileName.file; string file = Marshal.PtrToStringAuto(openFileName.file); while (file.Length > 0) { selectedFilesList.Add(file); pointer += file.Length * 2 + 2; openFileName.file = (IntPtr)pointer; file = Marshal.PtrToStringAuto(openFileName.file); } if (selectedFilesList.Count == 1) { fileFullNames = selectedFilesList; } else { string[] selectedFiles = new string[selectedFilesList.Count - 1]; for (int i = 0; i < selectedFiles.Length; i++) { selectedFiles[i] = selectedFilesList[0] + "\\" + selectedFilesList[i + 1]; } fileFullNames = new List<string>(selectedFiles); } } if (fileFullNames.Count > 0) { return fileFullNames; } else { return null; } }
在flag的設定中關鍵的幾個為:
- 0x00000200:允許多選
- 0x00080000:使用資源管理器風格
其餘選項詳見OPENFILENAMEA中關於flag欄位的列舉介紹
參考資料:
Unity中呼叫Windows視窗選擇檔案
GetOpenFileNameA function (commdlg.h)