[Unity] Unity öffnet das Windows-Systemdateidialogfeld

Inhaltsverzeichnis

Vorwort

UnityEditor

Windows

Einführung externer dynamischer Bibliotheken

Deklarieren Sie die GetOpenFileName-Funktion

Kapseln Sie das OPENFILENAME-Objekt

Rufen Sie die GetOpenFileName-Funktion auf

Integrieren

endgültige Wirkung


Vorwort

        Kürzlich bin ich auf ein Problem gestoßen, bei dem die Systemdialogfeld-Auswahldatei aufgerufen werden muss. Bei der Suche nach einer Online-Suche stellte ich fest, dass viele Tutorials nicht detailliert genug waren und es viel Aufwand erforderte, das Problem zu lösen. Während der Projektentwicklung wird das Programm in der UnityEditor-Umgebung ausgeführt, und das gepackte Programm muss in der Windows-Umgebung ausgeführt werden. Die beiden Umgebungen haben unterschiedliche Methoden zum Aufrufen des Systemdateidialogfelds. Das Folgende ist meine Idee.

UnityEditor

        Wenn das Projekt in UnityEditor ausgeführt wird, kann die Methode EditorUtility.OpenFilePanel() aufgerufen werden, um das Dialogfeld zu öffnen. Diese Funktion wird normalerweise in Editor-Erweiterungen oder benutzerdefinierten Editorfenstern verwendet, um Entwicklern die Auswahl von Dateien im Editor zu ermöglichen.

        Im Folgenden finden Sie die grundlegende Verwendung und einige Parameterbeschreibungen von EditorUtility.OpenFilePanel():

// 打开文件面板时显示的标题。
string title = "Open File"; 

// 打开文件面板时默认的目录。这应该是相对于项目文件夹的路径。
string directory = "Assets"; 

// 打开文件面板时默认选择的文件扩展名,可以是空字符串。
string extension = "txt"; 

 // 函数返回一个字符串,表示用户选择的文件路径。如果用户取消选择或关闭文件面板,返回的路径将为空字符串。
string path = EditorUtility.OpenFilePanel(title, directory, extension);

         Beachten Sie, dass diese Methode nur in der UnityEditor-Umgebung und nicht in gepackten Programmen verwendet werden kann.

Windows

        Da EditorUtility.OpenFilePanel() nach dem Packen nicht mehr verwendet werden kann, können wir nur einen anderen Weg finden.

Einführung externer dynamischer Bibliotheken

        Daher müssen wir die Dynamic Link Library Comdlg32.dll aufrufen, die vom nativen Windows-System bereitgestellt wird. Diese Bibliothek ist eine universelle Bibliothek, die in enthalten ist das Windows-Betriebssystem. Bibliothek für Dialogfunktionen wie Dateidialoge. Der Code lautet wie folgt:

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

               to ’ s ’ ’ s ’ s to t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t a t i t s Dies ist nützlich zum Debuggen und zur Fehlerbehandlung. Wenn der Aufruf fehlschlägt, kann der Fehlercode durch Überprüfen von Marshal.GetLastWin32Error() ermittelt werden.         CharSet = CharSet.Auto bedeutet, dass der Zeichensatz automatisch von der Laufzeitumgebung ausgewählt wird.

Deklarieren Sie die GetOpenFileName-Funktion

        Dann müssen wir die Funktion GetOpenFileName aufrufen. Diese Funktion ist eine API-Funktion, die vom Windows-Betriebssystem bereitgestellt wird und dazu verwendet wird,ein Standarddialogfeld zum Öffnen von Dateien anzuzeigen. In diesem Dialogfeld kann der Benutzer eine oder mehrere Dateien auswählen und die Pfadinformationen der vom Benutzer ausgewählten Dateien zurückgeben. Der Code lautet wie folgt:

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

        Aus dem Schlüsselwort extern geht hervor, dass es sich bei dieser Funktion um einenative Methode handelt und ihre Implementierung nicht in C#, sondern in this erfolgt im Maschinencode.

        [In, Out] ist ein Modifikator, der verwendet wird, um anzugeben, dass Parameter sowohl Eingabe als auch Ausgabe sind (ähnlich der Übergabe von Parametern per Referenz).

Kapseln Sie das OPENFILENAME-Objekt

        Diese Funktion akzeptiert einen Parameter ofn vom Typ FileDialogWin.OPENFILENAME, daher müssen wir a kapseln Parameter ofn Objekt vom Typ:

public static class FileDialogWin
    {
        [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 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;
        }
    }

        Diese Struktur muss dem von der Windows-API erwarteten Format entsprechen, daher kann sie als feste Verwendung betrachtet werden und wird hier nicht erläutert. 

Optimierung GetOpenFileName-Funktion

        Nachdem die oben genannten Vorbereitungen abgeschlossen sind, kann die Funktion aufgerufen werden. Der Code lautet wie folgt:

private string OpenWindowsFileDialog(string title, string defaultPath, string extension)
    {
        //Debug.Log("运行");
        FileDialogWin.OPENFILENAME ofn = new FileDialogWin.OPENFILENAME();
        ofn.structSize = System.Runtime.InteropServices.Marshal.SizeOf(ofn);
        ofn.filter =extension + "Files\0*.extension\0All Files\0*.*\0\0"; 
        ofn.file = new string(new char[256]);
        ofn.maxFile = ofn.file.Length;
        ofn.title = title;
        ofn.initialDir = defaultPath;

        //Debug.Log(GetOpenFileName(ofn));
        
        if (GetOpenFileName(ofn))
        {
            return ofn.file;
        }

        return null;
    }

        Instanziieren Sie zunächst ein FileDialogWin.OPENFILENAME-Objekt und initialisieren Sie seine Eigenschaften, wobei ofn.filter die Dateierweiterung über einen regulären Ausdruck abgleicht.

        Rufen Sie dann die Funktion „GetOpenFileName“ auf, die einen Bool-Wert zurückgibt, der normalerweise verwendet wird, um anzuzeigen, ob der Benutzer die Datei erfolgreich ausgewählt und im Dateidialogfeld auf die Schaltfläche „Öffnen“ geklickt hat. Wenn der Rückgabewert wahr ist, geben Sie daher einfach die erhaltene Dateiadresse zurück.

        Beachten Sie, dass es nach tatsächlichen Tests so aussieht, als ob Sie das Dateidialogfeld normal öffnen möchten und sicherstellen müssen, dass Sie es mit Administratorrechten ausführen.

        

Integrieren

        ​​​​Integrieren Sie abschließend die beiden oben genannten Methoden, um den endgültigen Code zu erhalten:

public class FileDialog : MonoBehaviour
{

    // 留出一个统一的调用接口
    public string OpenFilePanel()
    {
        //定义返回的文件路径
        string selectedFilePath = string.Empty;
#if UNITY_EDITOR
        // 编辑器环境
        selectedFilePath = EditorUtility.OpenFilePanel("Select a file", "", "");
#elif UNITY_STANDALONE_WIN
        // Windows环境
        selectedFilePath = OpenWindowsFileDialog("Select a file", "", "");
#endif

        // 处理选中的文件路径
        if (!string.IsNullOrEmpty(selectedFilePath))
        {
            Debug.Log("Selected file: " + selectedFilePath);
        }
        else
        {
            Debug.Log("File selection canceled.");
        }

        return selectedFilePath;
    }


#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
    // Windows平台的文件对话框
    [DllImport("Comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool GetOpenFileName([In, Out] FileDialogWin.OPENFILENAME ofn);

    private string OpenWindowsFileDialog(string title, string defaultPath, string extension)
    {
        //Debug.Log("运行");
        FileDialogWin.OPENFILENAME ofn = new FileDialogWin.OPENFILENAME();
        ofn.structSize = System.Runtime.InteropServices.Marshal.SizeOf(ofn);
        ofn.filter ="G-code Files\0*.gcode\0All Files\0*.*\0\0"; 
        ofn.file = new string(new char[256]);
        ofn.maxFile = ofn.file.Length;
        ofn.title = title;
        ofn.initialDir = defaultPath;

        //Debug.Log(GetOpenFileName(ofn));
        
        if (GetOpenFileName(ofn))
        {
            return ofn.file;
        }

        return null;
    }

    public static class FileDialogWin
    {
        [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 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;
        }
    }
#endif
}

         ​ ​ ​ Rufen Sie einfach die Funktion OpenFilePanel() in anderen Skripten auf und die Lösung wird automatisch basierend auf der laufenden Umgebung ausgewählt.

endgültige Wirkung

UnityEditor

Windows

Supongo que te gusta

Origin blog.csdn.net/m0_67636792/article/details/134996606
Recomendado
Clasificación