├── .gitignore
├── NativeFileDialogSharp
├── nfd.dll
├── nfd_x86.dll
├── runtimes
│ ├── win-x64
│ │ └── native
│ │ │ └── nfd.dll
│ ├── win-x86
│ │ └── native
│ │ │ └── nfd.dll
│ ├── linux-x64
│ │ └── native
│ │ │ └── libnfd.so
│ └── osx-x64
│ │ └── native
│ │ └── libnfd.dylib
├── NativeFileDialogSharp.csproj
├── Native
│ └── NativeFunctions.cs
└── NativeWrappers.cs
├── .gitmodules
├── NativeFileDialogSharpSandboxNetFramework
├── nfd.dll
├── nfd_x86.dll
├── packages.config
├── App.config
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── NativeFileDialogSharpSandboxNetFramework.csproj
├── README.md
├── NativeFileDialogSharpSandbox
├── NativeFileDialogSharpSandbox.csproj
└── Program.cs
├── LICENSE
└── NativeFileDialogSharp.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | obj/
3 | /packages/
4 | riderModule.iml
5 | /_ReSharper.Caches/
--------------------------------------------------------------------------------
/NativeFileDialogSharp/nfd.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharp/nfd.dll
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "nativefiledialog"]
2 | path = nativefiledialog
3 | url = https://github.com/milleniumbug/nativefiledialog
4 |
--------------------------------------------------------------------------------
/NativeFileDialogSharp/nfd_x86.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharp/nfd_x86.dll
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/nfd.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharpSandboxNetFramework/nfd.dll
--------------------------------------------------------------------------------
/NativeFileDialogSharp/runtimes/win-x64/native/nfd.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharp/runtimes/win-x64/native/nfd.dll
--------------------------------------------------------------------------------
/NativeFileDialogSharp/runtimes/win-x86/native/nfd.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharp/runtimes/win-x86/native/nfd.dll
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/nfd_x86.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharpSandboxNetFramework/nfd_x86.dll
--------------------------------------------------------------------------------
/NativeFileDialogSharp/runtimes/linux-x64/native/libnfd.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharp/runtimes/linux-x64/native/libnfd.so
--------------------------------------------------------------------------------
/NativeFileDialogSharp/runtimes/osx-x64/native/libnfd.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milleniumbug/NativeFileDialogSharp/HEAD/NativeFileDialogSharp/runtimes/osx-x64/native/libnfd.dylib
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NativeFileDialogSharp
2 |
3 | C# library bindings for [nativefiledialog](https://github.com/mlabbe/nativefiledialog).
4 |
5 | The library currently implements
6 |
7 | - Windows x86
8 | - Windows x86-64
9 | - Linux x86-64
10 | - macOS x86-64
11 |
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandbox/NativeFileDialogSharpSandbox.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This software is provided 'as-is', without any express or implied
2 | warranty. In no event will the authors be held liable for any damages
3 | arising from the use of this software.
4 |
5 | Permission is granted to anyone to use this software for any purpose,
6 | including commercial applications, and to alter it and redistribute it
7 | freely, subject to the following restrictions:
8 |
9 | 1. The origin of this software must not be misrepresented; you must not
10 | claim that you wrote the original software. If you use this software
11 | in a product, an acknowledgment in the product documentation would be
12 | appreciated but is not required.
13 | 2. Altered source versions must be plainly marked as such, and must not be
14 | misrepresented as being the original software.
15 | 3. This notice may not be removed or altered from any source distribution.
16 |
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandbox/Program.cs:
--------------------------------------------------------------------------------
1 | using NativeFileDialogSharp;
2 | using System;
3 |
4 | namespace NativeFileDialogSharpSandbox
5 | {
6 | internal class Program
7 | {
8 | static void Main(string[] args)
9 | {
10 | PrintResult(Dialog.FileOpenMultiple("pdf", null));
11 | PrintResult(Dialog.FileOpen(null));
12 | PrintResult(Dialog.FileSave(null));
13 | PrintResult(Dialog.FolderPicker(null));
14 | }
15 |
16 | static void PrintResult(DialogResult result)
17 | {
18 | Console.WriteLine($"Path: {result.Path}, IsError {result.IsError}, IsOk {result.IsOk}, IsCancelled {result.IsCancelled}, ErrorMessage {result.ErrorMessage}");
19 | if (result.Paths != null)
20 | {
21 | Console.WriteLine("Paths");
22 | Console.WriteLine(string.Join("\n", result.Paths));
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/Program.cs:
--------------------------------------------------------------------------------
1 | using NativeFileDialogSharp;
2 | using System;
3 |
4 | namespace NativeFileDialogSharpSandboxNetFramework
5 | {
6 | internal class Program
7 | {
8 | static void Main(string[] args)
9 | {
10 | PrintResult(Dialog.FileOpenMultiple("pdf", null));
11 | PrintResult(Dialog.FileOpen(null));
12 | PrintResult(Dialog.FileSave(null));
13 | PrintResult(Dialog.FolderPicker(null));
14 | }
15 |
16 | static void PrintResult(DialogResult result)
17 | {
18 | Console.WriteLine($"Path: {result.Path}, IsError {result.IsError}, IsOk {result.IsOk}, IsCancelled {result.IsCancelled}, ErrorMessage {result.ErrorMessage}");
19 | if (result.Paths != null)
20 | {
21 | Console.WriteLine("Paths");
22 | Console.WriteLine(string.Join("\n", result.Paths));
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/NativeFileDialogSharp/NativeFileDialogSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 7.3
5 | 0.5.0
6 | disable
7 | true
8 | Zlib
9 | milleniumbug
10 | https://github.com/milleniumbug/NativeFileDialogSharp
11 | https://github.com/milleniumbug/NativeFileDialogSharp
12 | Cross-platform native file dialog controls for Windows, Linux and macOS
13 | netstandard2.0
14 |
15 |
16 |
17 |
18 |
19 | PreserveNewest
20 |
21 |
22 | PreserveNewest
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("NativeFileDialogSharpSandboxNetFramework")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("NativeFileDialogSharpSandboxNetFramework")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("0fd91168-d8f5-4776-8d91-cb9b9c55aa1b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/NativeFileDialogSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31919.166
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeFileDialogSharp", "NativeFileDialogSharp\NativeFileDialogSharp.csproj", "{4127F279-9FD5-4C37-B904-242C124C1A07}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeFileDialogSharpSandbox", "NativeFileDialogSharpSandbox\NativeFileDialogSharpSandbox.csproj", "{427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeFileDialogSharpSandboxNetFramework", "NativeFileDialogSharpSandboxNetFramework\NativeFileDialogSharpSandboxNetFramework.csproj", "{0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Debug|x64 = Debug|x64
16 | Debug|x86 = Debug|x86
17 | Release|Any CPU = Release|Any CPU
18 | Release|x64 = Release|x64
19 | Release|x86 = Release|x86
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|x64.ActiveCfg = Debug|Any CPU
25 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|x64.Build.0 = Debug|Any CPU
26 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|x86.ActiveCfg = Debug|Any CPU
27 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|x86.Build.0 = Debug|Any CPU
28 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|x64.ActiveCfg = Release|Any CPU
31 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|x64.Build.0 = Release|Any CPU
32 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|x86.ActiveCfg = Release|Any CPU
33 | {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|x86.Build.0 = Release|Any CPU
34 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|x64.ActiveCfg = Debug|Any CPU
37 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|x64.Build.0 = Debug|Any CPU
38 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|x86.ActiveCfg = Debug|Any CPU
39 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|x86.Build.0 = Debug|Any CPU
40 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|x64.ActiveCfg = Release|Any CPU
43 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|x64.Build.0 = Release|Any CPU
44 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|x86.ActiveCfg = Release|Any CPU
45 | {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|x86.Build.0 = Release|Any CPU
46 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|x64.ActiveCfg = Debug|x64
49 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|x64.Build.0 = Debug|x64
50 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|x86.ActiveCfg = Debug|x86
51 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|x86.Build.0 = Debug|x86
52 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|x64.ActiveCfg = Release|x64
55 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|x64.Build.0 = Release|x64
56 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|x86.ActiveCfg = Release|x86
57 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|x86.Build.0 = Release|x86
58 | EndGlobalSection
59 | GlobalSection(SolutionProperties) = preSolution
60 | HideSolutionNode = FALSE
61 | EndGlobalSection
62 | GlobalSection(ExtensibilityGlobals) = postSolution
63 | SolutionGuid = {124CB415-A372-4268-9C13-330A0F1093C2}
64 | EndGlobalSection
65 | EndGlobal
66 |
--------------------------------------------------------------------------------
/NativeFileDialogSharpSandboxNetFramework/NativeFileDialogSharpSandboxNetFramework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}
8 | Exe
9 | NativeFileDialogSharpSandboxNetFramework
10 | NativeFileDialogSharpSandboxNetFramework
11 | v4.6.2
12 | 512
13 | true
14 | true
15 |
16 |
17 |
18 | x86
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\x64\Debug\
39 | DEBUG;TRACE
40 | full
41 | x64
42 | 7.3
43 | prompt
44 | true
45 |
46 |
47 | bin\x64\Release\
48 | TRACE
49 | true
50 | pdbonly
51 | x64
52 | 7.3
53 | prompt
54 | true
55 |
56 |
57 | true
58 | bin\x86\Debug\
59 | DEBUG;TRACE
60 | full
61 | x86
62 | 7.3
63 | prompt
64 | true
65 |
66 |
67 | bin\x86\Release\
68 | TRACE
69 | true
70 | pdbonly
71 | x86
72 | 7.3
73 | prompt
74 | true
75 |
76 |
77 |
78 | ..\packages\NativeFileDialogSharp.0.5.0\lib\netstandard2.0\NativeFileDialogSharp.dll
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/NativeFileDialogSharp/Native/NativeFunctions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace NativeFileDialogSharp.Native
5 | {
6 | public struct nfdpathset_t
7 | {
8 | public IntPtr buf;
9 | public IntPtr indices;
10 | public UIntPtr count;
11 | }
12 |
13 | public enum nfdresult_t
14 | {
15 | NFD_ERROR,
16 | NFD_OKAY,
17 | NFD_CANCEL
18 | }
19 |
20 | public static class NativeFunctions
21 | {
22 | public const string LibraryName = "nfd";
23 |
24 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
25 | public static extern unsafe nfdresult_t NFD_OpenDialog(byte* filterList, byte* defaultPath, out IntPtr outPath);
26 |
27 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
28 | public static extern unsafe nfdresult_t NFD_OpenDialogMultiple(byte* filterList, byte* defaultPath,
29 | nfdpathset_t* outPaths);
30 |
31 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
32 | public static extern unsafe nfdresult_t NFD_SaveDialog(byte* filterList, byte* defaultPath, out IntPtr outPath);
33 |
34 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
35 | public static extern unsafe nfdresult_t NFD_PickFolder(byte* defaultPath, out IntPtr outPath);
36 |
37 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
38 | public static extern unsafe byte* NFD_GetError();
39 |
40 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
41 | public static extern unsafe UIntPtr NFD_PathSet_GetCount(nfdpathset_t* pathSet);
42 |
43 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
44 | public static extern unsafe byte* NFD_PathSet_GetPath(nfdpathset_t* pathSet, UIntPtr index);
45 |
46 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
47 | public static extern unsafe void NFD_PathSet_Free(nfdpathset_t* pathSet);
48 |
49 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
50 | public static extern unsafe void NFD_Dummy();
51 |
52 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
53 | public static extern unsafe IntPtr NFD_Malloc(UIntPtr bytes);
54 |
55 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
56 | public static extern unsafe void NFD_Free(IntPtr ptr);
57 | }
58 |
59 | public static class NativeFunctions32
60 | {
61 | public const string LibraryName = "nfd_x86";
62 |
63 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
64 | public static extern unsafe nfdresult_t NFD_OpenDialog(byte* filterList, byte* defaultPath, out IntPtr outPath);
65 |
66 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
67 | public static extern unsafe nfdresult_t NFD_OpenDialogMultiple(byte* filterList, byte* defaultPath,
68 | nfdpathset_t* outPaths);
69 |
70 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
71 | public static extern unsafe nfdresult_t NFD_SaveDialog(byte* filterList, byte* defaultPath, out IntPtr outPath);
72 |
73 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
74 | public static extern unsafe nfdresult_t NFD_PickFolder(byte* defaultPath, out IntPtr outPath);
75 |
76 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
77 | public static extern unsafe byte* NFD_GetError();
78 |
79 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
80 | public static extern unsafe UIntPtr NFD_PathSet_GetCount(nfdpathset_t* pathSet);
81 |
82 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
83 | public static extern unsafe byte* NFD_PathSet_GetPath(nfdpathset_t* pathSet, UIntPtr index);
84 |
85 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
86 | public static extern unsafe void NFD_PathSet_Free(nfdpathset_t* pathSet);
87 |
88 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
89 | public static extern unsafe void NFD_Dummy();
90 |
91 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
92 | public static extern unsafe IntPtr NFD_Malloc(UIntPtr bytes);
93 |
94 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
95 | public static extern unsafe void NFD_Free(IntPtr ptr);
96 | }
97 | }
--------------------------------------------------------------------------------
/NativeFileDialogSharp/NativeWrappers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using NativeFileDialogSharp.Native;
7 |
8 | namespace NativeFileDialogSharp
9 | {
10 | public static class Dialog
11 | {
12 | private static readonly Encoder utf8encoder = Encoding.UTF8.GetEncoder();
13 |
14 | private static readonly bool need32bit = Is32BitWindowsOnNetFramework();
15 |
16 | private static bool Is32BitWindowsOnNetFramework()
17 | {
18 | try
19 | {
20 | // we call a function that does nothing just to test if we can load it properly
21 | NativeFileDialogSharp.Native.NativeFunctions.NFD_Dummy();
22 | return false;
23 | }
24 | catch
25 | {
26 | // a call to a default library failed, let's attempt the other one
27 | try
28 | {
29 | NativeFileDialogSharp.Native.NativeFunctions32.NFD_Dummy();
30 | return true;
31 | }
32 | catch
33 | {
34 | // both of them failed so we may as well default to the default one for predictability
35 | return false;
36 | }
37 | }
38 | }
39 |
40 | private static unsafe byte[] ToUtf8(string s)
41 | {
42 | var byteCount = Encoding.UTF8.GetByteCount(s);
43 | var bytes = new byte[byteCount + 1];
44 | fixed (byte* o = bytes)
45 | fixed (char* input = s)
46 | {
47 | utf8encoder.Convert(input, s.Length, o, bytes.Length, true, out _, out var _,
48 | out var completed);
49 | Debug.Assert(completed);
50 | }
51 |
52 | return bytes;
53 | }
54 |
55 | private static unsafe int GetNullTerminatedStringLength(byte* nullTerminatedString)
56 | {
57 | int count = 0;
58 | var ptr = nullTerminatedString;
59 | while (*ptr != 0)
60 | {
61 | ptr++;
62 | count++;
63 | }
64 |
65 | return count;
66 | }
67 |
68 | private static unsafe string FromUtf8(byte* nullTerminatedString)
69 | {
70 | return Encoding.UTF8.GetString(nullTerminatedString, GetNullTerminatedStringLength(nullTerminatedString));
71 | }
72 |
73 | public static unsafe DialogResult FileOpen(string filterList = null, string defaultPath = null)
74 | {
75 | fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null)
76 | fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null)
77 | {
78 | string path = null;
79 | string errorMessage = null;
80 | IntPtr outPathIntPtr;
81 | var result = need32bit
82 | ? NativeFunctions32.NFD_OpenDialog(filterListNts, defaultPathNts, out outPathIntPtr)
83 | : NativeFunctions.NFD_OpenDialog(filterListNts, defaultPathNts, out outPathIntPtr);
84 | if (result == nfdresult_t.NFD_ERROR)
85 | {
86 | errorMessage = FromUtf8(NativeFunctions.NFD_GetError());
87 | }
88 | else if (result == nfdresult_t.NFD_OKAY)
89 | {
90 | var outPathNts = (byte*)outPathIntPtr.ToPointer();
91 | path = FromUtf8(outPathNts);
92 | NativeFunctions.NFD_Free(outPathIntPtr);
93 | }
94 |
95 | return new DialogResult(result, path, null, errorMessage);
96 | }
97 | }
98 |
99 | public static unsafe DialogResult FileSave(string filterList = null, string defaultPath = null)
100 | {
101 | fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null)
102 | fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null)
103 | {
104 | string path = null;
105 | string errorMessage = null;
106 | IntPtr outPathIntPtr;
107 | var result = need32bit
108 | ? NativeFunctions32.NFD_SaveDialog(filterListNts, defaultPathNts, out outPathIntPtr)
109 | : NativeFunctions.NFD_SaveDialog(filterListNts, defaultPathNts, out outPathIntPtr);
110 | if (result == nfdresult_t.NFD_ERROR)
111 | {
112 | errorMessage = FromUtf8(NativeFunctions.NFD_GetError());
113 | }
114 | else if (result == nfdresult_t.NFD_OKAY)
115 | {
116 | var outPathNts = (byte*)outPathIntPtr.ToPointer();
117 | path = FromUtf8(outPathNts);
118 | NativeFunctions.NFD_Free(outPathIntPtr);
119 | }
120 |
121 | return new DialogResult(result, path, null, errorMessage);
122 | }
123 | }
124 |
125 | public static unsafe DialogResult FolderPicker(string defaultPath = null)
126 | {
127 | fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null)
128 | {
129 | string path = null;
130 | string errorMessage = null;
131 | IntPtr outPathIntPtr;
132 | var result = need32bit
133 | ? NativeFunctions32.NFD_PickFolder(defaultPathNts, out outPathIntPtr)
134 | : NativeFunctions.NFD_PickFolder(defaultPathNts, out outPathIntPtr);
135 | if (result == nfdresult_t.NFD_ERROR)
136 | {
137 | errorMessage = FromUtf8(NativeFunctions.NFD_GetError());
138 | }
139 | else if (result == nfdresult_t.NFD_OKAY)
140 | {
141 | var outPathNts = (byte*)outPathIntPtr.ToPointer();
142 | path = FromUtf8(outPathNts);
143 | NativeFunctions.NFD_Free(outPathIntPtr);
144 | }
145 |
146 | return new DialogResult(result, path, null, errorMessage);
147 | }
148 | }
149 |
150 | public static unsafe DialogResult FileOpenMultiple(string filterList = null, string defaultPath = null)
151 | {
152 | fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null)
153 | fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null)
154 | {
155 | List paths = null;
156 | string errorMessage = null;
157 | nfdpathset_t pathSet;
158 | var result = need32bit
159 | ? NativeFunctions32.NFD_OpenDialogMultiple(filterListNts, defaultPathNts, &pathSet)
160 | : NativeFunctions.NFD_OpenDialogMultiple(filterListNts, defaultPathNts, &pathSet);
161 | if (result == nfdresult_t.NFD_ERROR)
162 | {
163 | errorMessage = FromUtf8(NativeFunctions.NFD_GetError());
164 | }
165 | else if (result == nfdresult_t.NFD_OKAY)
166 | {
167 | var pathCount = (int)NativeFunctions.NFD_PathSet_GetCount(&pathSet).ToUInt32();
168 | paths = new List(pathCount);
169 | for (int i = 0; i < pathCount; i++)
170 | {
171 | paths.Add(FromUtf8(NativeFunctions.NFD_PathSet_GetPath(&pathSet, new UIntPtr((uint)i))));
172 | }
173 |
174 | NativeFunctions.NFD_PathSet_Free(&pathSet);
175 | }
176 |
177 | return new DialogResult(result, null, paths, errorMessage);
178 | }
179 | }
180 | }
181 |
182 | public class DialogResult
183 | {
184 | private readonly nfdresult_t result;
185 |
186 | public string Path { get; }
187 |
188 | public IReadOnlyList Paths { get; }
189 |
190 | public bool IsError => result == nfdresult_t.NFD_ERROR;
191 |
192 | public string ErrorMessage { get; }
193 |
194 | public bool IsCancelled => result == nfdresult_t.NFD_CANCEL;
195 |
196 | public bool IsOk => result == nfdresult_t.NFD_OKAY;
197 |
198 | internal DialogResult(nfdresult_t result, string path, IReadOnlyList paths, string errorMessage)
199 | {
200 | this.result = result;
201 | Path = path;
202 | Paths = paths;
203 | ErrorMessage = errorMessage;
204 | }
205 | }
206 | }
--------------------------------------------------------------------------------