unity调用操作系统的dialog

时间:2022-10-25 22:43:12

有个需求,就是在扩展编辑器功能时,有一些配置文件需要读取,现在希望能选取这个东西,而不是每次手填地址。
找了半天unity提供的组件,发现没有提供这个功能呀,这可怎么办???
突然想到unity用的是c#呀,那能不能直接使用c#的系统弹窗,想到就查,结果竟然还真的可以,下面我们来看看要怎么搞。

参考的这个博客的内容:
https://www.jianshu.com/p/e3ef2f45bda0

代码如下:

[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;
    }
/// <summary>
    /// 从dll加载对话框
    /// </summary>
    public class DllLoadDialog
    {
        [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);  

        [DllImport("shell32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]  
        public static extern IntPtr SHBrowseForFolder([In, Out] OpenFileDir ofn);  

        [DllImport("shell32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]  
        public static extern bool SHGetPathFromIDList([In] IntPtr pidl, [In, Out] char[] fileName);
    }
public class OpenDialog
    {
        /// <summary>
        /// 打开文件对话框
        /// </summary>
        /// <returns></returns>
        public static string OpenFileName()
        {
            OpenFileName openFileName = new OpenFileName();
            openFileName.structSize = Marshal.SizeOf(openFileName);
            openFileName.filter = "配置文件(*.txt)\0*.txt\0All Files\0*.*\0\0";
            openFileName.file = new string(new char[256]);
            openFileName.maxFile = openFileName.file.Length;
            openFileName.fileTitle = new string(new char[64]);
            openFileName.maxFileTitle = openFileName.fileTitle.Length;
            openFileName.initialDir = Application.dataPath; // 默认路径
            openFileName.title = "窗口标题";
            // 注意 一下项目不一定要全选 但是0x00000008项不要缺少
            // OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_NOCHANGEDIR
            openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;  

            if (DllLoadDialog.GetOpenFileName(openFileName))
            {
// Debug.LogFormat("OpenFileName file = {0} fileTitle = {1}", openFileName.file, openFileName.fileTitle);
                return openFileName.file;
            }

            return null;
        }

        /// <summary>
        /// 另存为对话框
        /// </summary>
        /// <returns></returns>
        public static string SaveFileName()
        {
            OpenFileName openFileName = new OpenFileName();
            openFileName.structSize = Marshal.SizeOf(openFileName);
            openFileName.filter = "配置文件(*.txt)\0*.txt\0All Files\0*.*\0\0";
            openFileName.file = new string(new char[256]);
            openFileName.maxFile = openFileName.file.Length;
            openFileName.fileTitle = new string(new char[64]);
            openFileName.maxFileTitle = openFileName.fileTitle.Length;
            openFileName.initialDir = Application.dataPath;//默认路径
            openFileName.title = "窗口标题";
            // 注意 一下项目不一定要全选 但是0x00000008项不要缺少
            // OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_NOCHANGEDIR
            openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;  

            if (DllLoadDialog.GetSaveFileName(openFileName))
            {
// Debug.LogFormat("SaveFileName file = {0} fileTitle = {1}", openFileName.file, openFileName.fileTitle);
                return openFileName.file;
            }

            return null;
        }

        public static string OpenFileDir()
        {
            OpenFileDir openFileDir = new OpenFileDir();
            openFileDir.pszDisplayName = new string(new char[2000]); // 存放目录路径缓冲区 
            openFileDir.lpszTitle = "Open Project"; // 标题 
            //openFileDir.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX; // 新的样式,带编辑框 
            IntPtr pidlPtr = DllLoadDialog.SHBrowseForFolder(openFileDir);

            char[] charArray = new char[2000];
            for (int i = 0; i < 2000; i++)
            {
                charArray[i] = '\0';
            }

            DllLoadDialog.SHGetPathFromIDList(pidlPtr, charArray);
            string fullDirPath = new String(charArray);
            fullDirPath = fullDirPath.Substring(0, fullDirPath.IndexOf('\0'));

// Debug.LogFormat("OpenFileDir = {0}", fullDirPath);
            return fullDirPath;
        }

    }

弹出窗的配置参数是通过我们声明的那个 OPENFILENAME 结构体来控制的,结构体的具体定义可以查看微软的网站
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646839(v=vs.85).aspx

最终效果:
unity调用操作系统的dialog

PS: initialDir 这个属性没有效果,每次打开的目录都是上次关闭的,第一次打开的目录也不是我设的地方,不知道是什么原因,不过不打算研究了,能用就行了