最近使用Unity时遇到了一个从外界加载文件的需求,这里陈述了两种解决方案。
方案一 利用WindowsForm对话框
- Unity本身并不支持 System.Windows.Forms,需要手动导入。在Unity工程文件中建立一个Plugins文件夹,将System.Windows.Forms.dll文件复制到该文件夹中。
- System.Windows.Forms.dll免费下载路径:链接,也可以在本机的Unity安装目录下进行查找,以下路径可供参考。
Unity\2019\Editor\Data\MonoBleedingEdge\lib\mono\gac\System.Windows.Forms\4.0.0.0__b77a5c561934e089
- 一些文章中要求将API Compatibility Level*修改为
.net 2.0
,经unity2019版本测试,.net 4.x
正常使用。 - 引入命名空间:
using System.Windows.Forms;
- 简单用法如下所示,更多用法参看微软c#官方资料
private void Start()
{
string filePath;
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.InitialDirectory = "c:\\";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
filePath = openFileDialog.FileName;
Debug.Log(filePath);
}
}
}
- 运行结果:
方案二 引用Comdlg32.dll(非托管的DLL)
方案一实现了对话框调用并获取路径,但是对话框版本较为陈旧,下面的方式更简单美观。
参考资料:
资料一:StructLayout特&性
资料二:C#直接使用DllImport外部Dll的方法
资料三:OpenFileName结构体介绍
资料四:百度资料
- 自定义OpenFileName数据接收类
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 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 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;
public OpenFileName(int FileLenth = 256, int FileTitleLenth=64)
{
structSize=Marshal.SizeOf(this);
file = new string(new char[FileLenth]);
maxFile = file.Length;
fileTitle = new string(new char[FileTitleLenth]);
maxFileTitle = fileTitle.Length;
title = String.Empty;
flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;
title = "窗口标题";
initialDir = Application.streamingAssetsPath.Replace('/', '\\');
}
}
- 导入非托管方法:
public class LocalDialog
{
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
}
- 调用过程:
private void Start()
{
OpenFileName openFileName = new OpenFileName();
if (LocalDialog.GetOpenFileName(openFileName))
{
Debug.Log(openFileName.file);
Debug.Log(openFileName.fileTitle);
} ;
}
-
运行结果:
-
OpenFileName参数介绍
【structSize】:结构的长度(单位bytes)。
【dlgOwner 】:对话框窗口的拥有者。该成员可以是任何有效的窗口句柄,如果对话框没有拥有者,则可以为NULL。
【instance】:对话框模板设置,可以为NULL。
【filter 】:文件过滤器,根据设定来进行初步筛选
【customFilter 】:静态缓冲区,其中包含一对以空值结尾的过滤器字符串,用于保留用户选择的过滤器模式。
【maxCustFilter 】:customFilter 缓冲区的大小,该缓冲区的长度至少应为40个字符。如果customFilter 为NULL或指向NULL字符串,则忽略此成员。
【filterIndex 】:当前所选过滤器的索引,filter 指向的缓冲区包含定义过滤器的字符串对。第一对字符串的索引值为1,第二对字符串的索引值为2,依此类推。索引为零表示lpstrCustomFilter指定的自定义过滤器 。
【file 】:可用于初始化文件名。如果不需要初始化,则必须为NULL。当GetOpenFileName或GetSaveFileName函数成功返回时,该字符串为选择文件的路径(包含驱动器标识符,路径,文件名以及所选文件的扩展名)。
【maxFile 】:file 字符串的长度,至少应为256个字符,太小则无法包含文件路径信息。
【fileTitle 】:所选文件的文件名和扩展名(不包含路径信息)。
【maxFileTitle】:fileTitle 字符串的长度。
【initialDir】:打开的初始目录。
【title 】:放置在对话框标题栏中的字符串。
【flags 】:用于初始化对话框的标志位,OFN(OpenFileName),具体编码含义查看 参考资料三
【fileOffset 】:从路径开头到File指向的字符串中的文件名的从零开始的偏移量,以字符为单位。
【fileExtension 】:从路径的开头到lpstrFile指向的字符串中的文件扩展名的从零开始的偏移量,以字符为单位。
【defExt 】:默认扩展名。
【custData 】:系统传递给由lpfnHook成员标识的挂钩过程的应用程序定义的数据。
【hook 】:指向Hook的指针
【templateName 】:hInstance成员标识的模块中对话框模板资源的名称。
【reservedPtr 】:保留指针,未使用
【reservedInt 】:保留int参数,未使用
【flagsEx 】:一组位标志可用于初始化对话框。当前,该成员可以为零或以下标志。