当前位置:   article > 正文

【unity】unity打开Windows系统文件对话框_untiy 打开windows窗口

untiy 打开windows窗口

目录

前言

UnityEditor

Windows

引入外部动态库

声明GetOpenFileName函数

封装OPENFILENAME对象

调用GetOpenFileName函数

整合

最终效果


前言

        最近项目中遇到了需要调用系统对话框选择文件的问题,上网搜索时发现很多教程不够详细,费了不少功夫才解决。在项目开发时,程序运行在UnityEditor环境中,而打包后的程序须在Windows环境下运行,这两种环境调用系统文件对话框的方法不同,以下是我的思路

UnityEditor

        当项目在运行在UnityEditor时,可调用EditorUtility.OpenFilePanel()方法打开对话框。这个函数通常用于编辑器扩展(Editor Extensions)或自定义编辑器窗口中,以便让开发者在编辑器中选择文件。

        以下是EditorUtility.OpenFilePanel()的基本用法和一些参数说明:

  1. // 打开文件面板时显示的标题。
  2. string title = "Open File";
  3. // 打开文件面板时默认的目录。这应该是相对于项目文件夹的路径。
  4. string directory = "Assets";
  5. // 打开文件面板时默认选择的文件扩展名,可以是空字符串。
  6. string extension = "txt";
  7. // 函数返回一个字符串,表示用户选择的文件路径。如果用户取消选择或关闭文件面板,返回的路径将为空字符串。
  8. string path = EditorUtility.OpenFilePanel(title, directory, extension);

         注意,该方法只能在UnityEditor环境下使用,打包后的程序无法使用该方法。

Windows

        既然打包后无法使用EditorUtility.OpenFilePanel(),我们只能另寻他法。

引入外部动态库

        因此我们需要调用本机Windows系统所提供的动态链接库Comdlg32.dll,这个库是Windows操作系统中包含通用对话框函数(如文件对话框)的库。代码如下:

[DllImport("Comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]

               其中SetLastError = true表示将上一个错误代码设置为非零值。这对于调试和错误处理非常有用。如果调用失败,可以通过检查 Marshal.GetLastWin32Error() 获取错误代码。 
        而CharSet = CharSet.Auto表示字符集由运行时环境自动选择。

声明GetOpenFileName函数

        然后我们需要调用GetOpenFileName函数。这个函数是 Windows 操作系统提供的一个 API 函数,用于显示标准的文件打开对话框。该对话框允许用户选择一个或多个文件,并返回用户所选文件的路径信息。代码如下:

private static extern bool GetOpenFileName([In, Out] FileDialogWin.OPENFILENAME ofn);

        从关键字extern可以看出,该函数是一个本机方法,其实现并不在C#中,而是在本机代码中。

        [In, Out]是修饰符,用于指定参数是既输入又输出的(类似于引用传参)。

封装OPENFILENAME对象

        该函数接受一个FileDialogWin.OPENFILENAME类型的参数ofn,因此我们需要封装一个该类型的对象:

  1. public static class FileDialogWin
  2. {
  3. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  4. public class OPENFILENAME
  5. {
  6. public int structSize = 0;
  7. public IntPtr dlgOwner = IntPtr.Zero;
  8. public IntPtr instance = IntPtr.Zero;
  9. public string filter = null;
  10. public string customFilter = null;
  11. public int maxCustFilter = 0;
  12. public int filterIndex = 0;
  13. public string file = null;
  14. public int maxFile = 0;
  15. public string initialDir = null;
  16. public string title = null;
  17. public int flags = 0;
  18. public short fileOffset = 0;
  19. public short fileExtension = 0;
  20. public string defExt = null;
  21. public IntPtr custData = IntPtr.Zero;
  22. public IntPtr hook = IntPtr.Zero;
  23. public string templateName = null;
  24. public IntPtr reservedPtr = IntPtr.Zero;
  25. public int reservedInt = 0;
  26. public int flagsEx = 0;
  27. }
  28. }

        该结构体需要满足WindowsAPI所期望的格式,所以可以将它当作固定用法,这里就不作解释。 

调用GetOpenFileName函数

        上述准备工作做完后就可以调用函数了,代码如下:

  1. private string OpenWindowsFileDialog(string title, string defaultPath, string extension)
  2. {
  3. //Debug.Log("运行");
  4. FileDialogWin.OPENFILENAME ofn = new FileDialogWin.OPENFILENAME();
  5. ofn.structSize = System.Runtime.InteropServices.Marshal.SizeOf(ofn);
  6. ofn.filter =extension + "Files\0*.extension\0All Files\0*.*\0\0";
  7. ofn.file = new string(new char[256]);
  8. ofn.maxFile = ofn.file.Length;
  9. ofn.title = title;
  10. ofn.initialDir = defaultPath;
  11. //Debug.Log(GetOpenFileName(ofn));
  12. if (GetOpenFileName(ofn))
  13. {
  14. return ofn.file;
  15. }
  16. return null;
  17. }

        首先实例化一个 FileDialogWin.OPENFILENAME对象,并给其属性初始化,其中ofn.filter是通过正则表达式匹配文件扩展名。

        然后调用GetOpenFileName函数,该函数会返回一个bool值,通常用于表示用户是否成功选择了文件并点击了文件对话框的 "打开" 按钮。因此当返回值为true时,返回获取到的文件地址即可。

        注意,经过实际测试,想要正常打开文件对话框似乎需要确保以管理员权限运行

        

整合

        最后将上述两个方法整合一下,得到最终代码:

  1. public class FileDialog : MonoBehaviour
  2. {
  3. // 留出一个统一的调用接口
  4. public string OpenFilePanel()
  5. {
  6. //定义返回的文件路径
  7. string selectedFilePath = string.Empty;
  8. #if UNITY_EDITOR
  9. // 编辑器环境
  10. selectedFilePath = EditorUtility.OpenFilePanel("Select a file", "", "");
  11. #elif UNITY_STANDALONE_WIN
  12. // Windows环境
  13. selectedFilePath = OpenWindowsFileDialog("Select a file", "", "");
  14. #endif
  15. // 处理选中的文件路径
  16. if (!string.IsNullOrEmpty(selectedFilePath))
  17. {
  18. Debug.Log("Selected file: " + selectedFilePath);
  19. }
  20. else
  21. {
  22. Debug.Log("File selection canceled.");
  23. }
  24. return selectedFilePath;
  25. }
  26. #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
  27. // Windows平台的文件对话框
  28. [DllImport("Comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  29. private static extern bool GetOpenFileName([In, Out] FileDialogWin.OPENFILENAME ofn);
  30. private string OpenWindowsFileDialog(string title, string defaultPath, string extension)
  31. {
  32. //Debug.Log("运行");
  33. FileDialogWin.OPENFILENAME ofn = new FileDialogWin.OPENFILENAME();
  34. ofn.structSize = System.Runtime.InteropServices.Marshal.SizeOf(ofn);
  35. ofn.filter ="G-code Files\0*.gcode\0All Files\0*.*\0\0";
  36. ofn.file = new string(new char[256]);
  37. ofn.maxFile = ofn.file.Length;
  38. ofn.title = title;
  39. ofn.initialDir = defaultPath;
  40. //Debug.Log(GetOpenFileName(ofn));
  41. if (GetOpenFileName(ofn))
  42. {
  43. return ofn.file;
  44. }
  45. return null;
  46. }
  47. public static class FileDialogWin
  48. {
  49. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  50. public class OPENFILENAME
  51. {
  52. public int structSize = 0;
  53. public IntPtr dlgOwner = IntPtr.Zero;
  54. public IntPtr instance = IntPtr.Zero;
  55. public string filter = null;
  56. public string customFilter = null;
  57. public int maxCustFilter = 0;
  58. public int filterIndex = 0;
  59. public string file = null;
  60. public int maxFile = 0;
  61. public string initialDir = null;
  62. public string title = null;
  63. public int flags = 0;
  64. public short fileOffset = 0;
  65. public short fileExtension = 0;
  66. public string defExt = null;
  67. public IntPtr custData = IntPtr.Zero;
  68. public IntPtr hook = IntPtr.Zero;
  69. public string templateName = null;
  70. public IntPtr reservedPtr = IntPtr.Zero;
  71. public int reservedInt = 0;
  72. public int flagsEx = 0;
  73. }
  74. }
  75. #endif
  76. }

         只需在其他脚本调用OpenFilePanel()函数,将根据运行环境自动选择方案。

最终效果

UnityEditor

Windows

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/783228
推荐阅读
相关标签
  

闽ICP备14008679号