1. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    Dismiss Notice
  2. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  3. We’re giving 2017.1 beta testers a chance to win t-shirts and a Nintendo Switch. Read more on the blog.
    Dismiss Notice
  4. We want to know how you learned Unity! Help us by taking this quick survey and have a chance at a $25 gift card
    Dismiss Notice
  5. Unity 5.6 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice

OpenFileDialog in Runtime

Discussion in 'Windows' started by Astiolo, Mar 5, 2017.

  1. Astiolo


    Dec 18, 2014
    I spent quite a while searching for a way to open the Windows native open file dialog and eventually stumbled on some code that worked in a Chinese forum (I can't speak or read Chinese).

    First you will need this DllTest code:

    Code (CSharp):
    1. using System;
    2. using System.Runtime.InteropServices;
    4. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    6. public class OpenFileName {
    7.     public int      structSize = 0;
    8.     public IntPtr   dlgOwner = IntPtr.Zero;
    9.     public IntPtr   instance = IntPtr.Zero;
    10.     public String   filter = null;
    11.     public String   customFilter = null;
    12.     public int      maxCustFilter = 0;
    13.     public int      filterIndex = 0;
    14.     public String   file = null;
    15.     public int      maxFile = 0;
    16.     public String   fileTitle = null;
    17.     public int      maxFileTitle = 0;
    18.     public String   initialDir = null;
    19.     public String   title = null;
    20.     public int      flags = 0;
    21.     public short    fileOffset = 0;
    22.     public short    fileExtension = 0;
    23.     public String   defExt = null;
    24.     public IntPtr   custData = IntPtr.Zero;
    25.     public IntPtr   hook = IntPtr.Zero;
    26.     public String   templateName = null;
    27.     public IntPtr   reservedPtr = IntPtr.Zero;
    28.     public int      reservedInt = 0;
    29.     public int      flagsEx = 0;
    30. }
    32. public class DllTest {
    33.     [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    34.     public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
    35.     public static bool GetOpenFileName1([In, Out] OpenFileName ofn) {
    36.         return GetOpenFileName(ofn);
    37.     }
    38. }
    Then you can open the dialog with the following code (using System.Runtime.InteropServices):

    Code (CSharp):
    1. OpenFileName ofn = new OpenFileName();
    2.         ofn.structSize = Marshal.SizeOf(ofn);
    3.         ofn.filter = "All Files\0*.*\0\0";
    4.         ofn.file = new string(new char[256]);
    5.         ofn.maxFile = ofn.file.Length;
    6.         ofn.fileTitle = new string(new char[64]);
    7.         ofn.maxFileTitle = ofn.fileTitle.Length;
    8.         ofn.initialDir = UnityEngine.Application.dataPath;
    9.         ofn.title = "Upload Image";
    10.         ofn.defExt = "PNG";
    11.         ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;//OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR
    12.         if(DllTest.GetOpenFileName(ofn)) {
    13.             FileDialogResult("file:///" + ofn.file);
    14.         }
    Where "FileDialogResult" is just a function created to act on the returned file path. Depending on your application, you will probably want to adjust some of the parameters like the file extension and title. I don't really understand this code though, it's just something I found that worked for me so I probably won't be able to help if you run into problems.

    Here is the original forum and the following the their test code for opening the dialog and applying the loaded image as a texture. Just put it on an object in the scene and assign the 'plane' object (I thought I should include it just to make it a little easier for you to make sure it works).

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Text;
    4. using System.Runtime.InteropServices;
    5. using System;
    6. public class Test : MonoBehaviour {
    7.     public GameObject plane;
    8.     void OnGUI()
    9.     {
    10.         if(GUI.Button(new Rect(0,0,100,35),"OpenDialog"))
    11.         {
    12.             OpenFileName ofn = new OpenFileName();
    13.             ofn.structSize = Marshal.SizeOf(ofn);
    14.             ofn.filter = "All Files\0*.*\0\0";
    15.             ofn.file = new string(new char[256]);
    16.             ofn.maxFile = ofn.file.Length;
    17.             ofn.fileTitle = new string(new char[64]);
    18.             ofn.maxFileTitle = ofn.fileTitle.Length;
    19.             ofn.initialDir =UnityEngine.Application.dataPath;//默认路径
    20.             ofn.title = "Open Project";
    21.             ofn.defExt = "JPG";//显示文件的类型
    22.            //注意 一下项目不一定要全选 但是0x00000008项不要缺少
    23.             ofn.flags=0x00080000|0x00001000|0x00000800|0x00000200|0x00000008;//OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR
    24.             if(DllTest.GetOpenFileName( ofn ))
    25.             {
    26.                 StartCoroutine(WaitLoad(ofn.file));//加载图片到panle
    27.                 Debug.Log( "Selected file with full path: {0}"+ofn.file );
    28.             }
    29.         }
    30.     }
    32.     IEnumerator WaitLoad(string fileName)
    33.     {
    34.         WWW wwwTexture=new WWW("file://"+fileName);
    35.         Debug.Log(wwwTexture.url);
    36.         yield return wwwTexture;
    37.         plane.renderer.material.mainTexture=wwwTexture.texture;
    38.     }
    39. }
    Please share any improvements and it would be fantastic to add some multi platform support but I'll be looking into that later on.
  2. Aurimas-Cernius


    Unity Technologies

    Jul 31, 2013
    GetOpenFileName() is Windows function for opening that dialog. What you do here is define a C# struct with marshaling so that when you call this Windows function it gets transformed into C struct that function takes as an argument. You can find full documentation about that function in Microsofts website.
    As for multi platform it is much more complicated. Other OSes have their own native APIs for such dialog and those APIs are very different, so making a generic platform independent API for this is quite a challenge.
  3. Astiolo


    Dec 18, 2014
    To be honest I think this should be something built into Unity. It's in the Editor as a simple function, why not include that as an option in runtime?
    RealMTG likes this.
  4. N3uRo


    Dec 10, 2011
    I agree, If there is an editor API for this why would not expose it for runtime?
  5. Tautvydas-Zilys


    Unity Technologies

    Jul 25, 2013
    Implementing it on 3 platforms is easier than implementing it on 20+. Plus, hardly any games need this functionality.
  6. N3uRo


    Dec 10, 2011
    I mean in desktop platforms (windows, osx, Linux) because on other platforms like mobiles platforms is not always possible or have sense (consoles...). In Android 4.4+ was added that features and on iOS you can only select images or videos you can't browse freely any file.

    For simple features like this would be easier if Unity was open source and people would develop and pull request this things that are not a priority for Unity.
  7. Tautvydas-Zilys


    Unity Technologies

    Jul 25, 2013
    You don't need Unity's source code to implement anything like this. People can and have extended the engine through using our plugin model. There are loads of plugins on the asset store...

    If you think this is important, you can always make a plugin yourself and put it out there :).
  8. N3uRo


    Dec 10, 2011
    You haven't understand it. I know I can do it myself without source code. I have developed many Plugins on different platforms.

    I meant that having source code and making pull-requests we could make it to core and Unity staff focus on other more important things.
  9. Astiolo


    Dec 18, 2014
    Sure, but why not have that option for those three platforms?

    That's a terrible philosophy for creating good software and it frustrates me a lot when I find simple things that Unity should have but instead I have to pay someone else to get their fix. I understand you can't provide everything that gets requested but some things should just be part of the engine. For some examples there's this functionality, a decent control mapping system (like rewired), the ability to instantiate prefabs with lightmap data, etc.

    Just to be clear I'm not saying the asset store is a bad idea. Just that you shouldn't go telling your customers to do the work for you, to overcome simple limitations of your software. When those features should have just been implemented in the engine in the first place.
    Last edited: Mar 14, 2017
  10. gkngkc


    Feb 4, 2013
    Astiolo likes this.