1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

OpenFileDialog in Runtime

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

  1. Astiolo

    Astiolo

    Joined:
    Dec 18, 2014
    Posts:
    17
    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;
    3.  
    4. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    5.  
    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. }
    31.  
    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.     }
    31.  
    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

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    1,277
    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

    Astiolo

    Joined:
    Dec 18, 2014
    Posts:
    17
    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

    N3uRo

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

    Tautvydas-Zilys

    Unity Technologies

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

    N3uRo

    Joined:
    Dec 10, 2011
    Posts:
    268
    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

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    3,871
    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

    N3uRo

    Joined:
    Dec 10, 2011
    Posts:
    268
    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

    Astiolo

    Joined:
    Dec 18, 2014
    Posts:
    17
    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

    gkngkc

    Joined:
    Feb 4, 2013
    Posts:
    6
    Astiolo likes this.