From c11828a7d5ee0cec233064e87b78e5d4356af05b Mon Sep 17 00:00:00 2001 From: milleniumbug Date: Mon, 27 Dec 2021 22:17:54 +0100 Subject: [PATCH] Port to .NET Standard 2.0 - so far works only on .NET Core derived runtimes and .NET Framework, but in the later case the user has to manually copy the dll --- NativeFileDialogSharp.sln | 73 +++-- .../Native/NativeFunctions.cs | 137 +++++---- .../NativeFileDialogSharp.csproj | 6 +- NativeFileDialogSharp/NativeWrappers.cs | 264 +++++++++--------- .../NativeFileDialogSharpSandbox.csproj | 2 +- NativeFileDialogSharpSandbox/Program.cs | 40 ++- .../App.config | 6 + ...eFileDialogSharpSandboxNetFramework.csproj | 78 ++++++ .../Program.cs | 26 ++ .../Properties/AssemblyInfo.cs | 36 +++ .../packages.config | 5 + 11 files changed, 459 insertions(+), 214 deletions(-) create mode 100644 NativeFileDialogSharpSandboxNetFramework/App.config create mode 100644 NativeFileDialogSharpSandboxNetFramework/NativeFileDialogSharpSandboxNetFramework.csproj create mode 100644 NativeFileDialogSharpSandboxNetFramework/Program.cs create mode 100644 NativeFileDialogSharpSandboxNetFramework/Properties/AssemblyInfo.cs create mode 100644 NativeFileDialogSharpSandboxNetFramework/packages.config diff --git a/NativeFileDialogSharp.sln b/NativeFileDialogSharp.sln index 89a69db..c95c259 100644 --- a/NativeFileDialogSharp.sln +++ b/NativeFileDialogSharp.sln @@ -1,22 +1,51 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeFileDialogSharp", "NativeFileDialogSharp\NativeFileDialogSharp.csproj", "{4127F279-9FD5-4C37-B904-242C124C1A07}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeFileDialogSharpSandbox", "NativeFileDialogSharpSandbox\NativeFileDialogSharpSandbox.csproj", "{427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|Any CPU.Build.0 = Release|Any CPU - {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31919.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeFileDialogSharp", "NativeFileDialogSharp\NativeFileDialogSharp.csproj", "{4127F279-9FD5-4C37-B904-242C124C1A07}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeFileDialogSharpSandbox", "NativeFileDialogSharpSandbox\NativeFileDialogSharpSandbox.csproj", "{427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeFileDialogSharpSandboxNetFramework", "NativeFileDialogSharpSandboxNetFramework\NativeFileDialogSharpSandboxNetFramework.csproj", "{0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|x64.ActiveCfg = Debug|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Debug|x64.Build.0 = Debug|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|Any CPU.Build.0 = Release|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|x64.ActiveCfg = Release|Any CPU + {4127F279-9FD5-4C37-B904-242C124C1A07}.Release|x64.Build.0 = Release|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|x64.ActiveCfg = Debug|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Debug|x64.Build.0 = Debug|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|Any CPU.Build.0 = Release|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|x64.ActiveCfg = Release|Any CPU + {427E5F76-8418-4EA3-9AA3-C1DBFDE0478F}.Release|x64.Build.0 = Release|Any CPU + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|x64.ActiveCfg = Debug|x64 + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Debug|x64.Build.0 = Debug|x64 + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|Any CPU.Build.0 = Release|Any CPU + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|x64.ActiveCfg = Release|x64 + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {124CB415-A372-4268-9C13-330A0F1093C2} + EndGlobalSection +EndGlobal diff --git a/NativeFileDialogSharp/Native/NativeFunctions.cs b/NativeFileDialogSharp/Native/NativeFunctions.cs index e332cdc..9b702ea 100644 --- a/NativeFileDialogSharp/Native/NativeFunctions.cs +++ b/NativeFileDialogSharp/Native/NativeFunctions.cs @@ -1,56 +1,97 @@ using System; using System.Runtime.InteropServices; -namespace NativeFileDialogSharp.Native; - -public struct nfdpathset_t +namespace NativeFileDialogSharp.Native { - public IntPtr buf; - public IntPtr indices; - public UIntPtr count; -} + public struct nfdpathset_t + { + public IntPtr buf; + public IntPtr indices; + public UIntPtr count; + } -public enum nfdresult_t -{ - NFD_ERROR, - NFD_OKAY, - NFD_CANCEL -} + public enum nfdresult_t + { + NFD_ERROR, + NFD_OKAY, + NFD_CANCEL + } -public static class NativeFunctions -{ - public const string LibraryName = "nfd"; + public static class NativeFunctions + { + public const string LibraryName = "nfd"; + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_OpenDialog(byte* filterList, byte* defaultPath, out IntPtr outPath); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_OpenDialogMultiple(byte* filterList, byte* defaultPath, + nfdpathset_t* outPaths); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_SaveDialog(byte* filterList, byte* defaultPath, out IntPtr outPath); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_PickFolder(byte* defaultPath, out IntPtr outPath); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe byte* NFD_GetError(); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe UIntPtr NFD_PathSet_GetCount(nfdpathset_t* pathSet); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe byte* NFD_PathSet_GetPath(nfdpathset_t* pathSet, UIntPtr index); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe void NFD_PathSet_Free(nfdpathset_t* pathSet); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe void NFD_Dummy(); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe IntPtr NFD_Malloc(UIntPtr bytes); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe void NFD_Free(IntPtr ptr); + } - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe nfdresult_t NFD_OpenDialog(byte* filterList, byte* defaultPath, out IntPtr outPath); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe nfdresult_t NFD_OpenDialogMultiple(byte* filterList, byte* defaultPath, nfdpathset_t* outPaths); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe nfdresult_t NFD_SaveDialog(byte* filterList, byte* defaultPath, out IntPtr outPath); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe nfdresult_t NFD_PickFolder(byte* defaultPath, out IntPtr outPath); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe byte* NFD_GetError(); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe UIntPtr NFD_PathSet_GetCount(nfdpathset_t* pathSet); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe byte* NFD_PathSet_GetPath(nfdpathset_t* pathSet, UIntPtr index); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe void NFD_PathSet_Free(nfdpathset_t* pathSet); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe void NFD_Dummy(); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe IntPtr NFD_Malloc(UIntPtr bytes); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern unsafe void NFD_Free(IntPtr ptr); + public static class NativeFunctions32 + { + public const string LibraryName = "nfd_x86"; + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_OpenDialog(byte* filterList, byte* defaultPath, out IntPtr outPath); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_OpenDialogMultiple(byte* filterList, byte* defaultPath, + nfdpathset_t* outPaths); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_SaveDialog(byte* filterList, byte* defaultPath, out IntPtr outPath); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe nfdresult_t NFD_PickFolder(byte* defaultPath, out IntPtr outPath); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe byte* NFD_GetError(); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe UIntPtr NFD_PathSet_GetCount(nfdpathset_t* pathSet); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe byte* NFD_PathSet_GetPath(nfdpathset_t* pathSet, UIntPtr index); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe void NFD_PathSet_Free(nfdpathset_t* pathSet); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe void NFD_Dummy(); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe IntPtr NFD_Malloc(UIntPtr bytes); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern unsafe void NFD_Free(IntPtr ptr); + } } \ No newline at end of file diff --git a/NativeFileDialogSharp/NativeFileDialogSharp.csproj b/NativeFileDialogSharp/NativeFileDialogSharp.csproj index 1628e6a..87a0602 100644 --- a/NativeFileDialogSharp/NativeFileDialogSharp.csproj +++ b/NativeFileDialogSharp/NativeFileDialogSharp.csproj @@ -1,9 +1,8 @@ - 10 - 0.2.5 - net6.0 + 7.3 + 0.5.0 disable true Zlib @@ -11,6 +10,7 @@ https://github.com/milleniumbug/NativeFileDialogSharp https://github.com/milleniumbug/NativeFileDialogSharp Cross-platform native file dialog controls for Windows, Linux and macOS + netstandard2.0 diff --git a/NativeFileDialogSharp/NativeWrappers.cs b/NativeFileDialogSharp/NativeWrappers.cs index a6ee17e..42e02f0 100644 --- a/NativeFileDialogSharp/NativeWrappers.cs +++ b/NativeFileDialogSharp/NativeWrappers.cs @@ -1,156 +1,168 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; using NativeFileDialogSharp.Native; -namespace NativeFileDialogSharp; - -public static class Dialog +namespace NativeFileDialogSharp { - private static byte[] ToUtf8(string s) + public static class Dialog { - var byteCount = Encoding.UTF8.GetByteCount(s); - var bytes = new byte[byteCount + 1]; - Encoding.UTF8.GetBytes(s.AsSpan(), bytes.AsSpan()); - return bytes; - } + private static readonly Encoder utf8encoder = Encoding.UTF8.GetEncoder(); - private static unsafe Span MakeSpanFromNullTerminatedString(byte* nullTerminatedString) - { - int count = 0; - var ptr = nullTerminatedString; - while (*ptr != 0) + private static unsafe byte[] ToUtf8(string s) { - ptr++; - count++; + var byteCount = Encoding.UTF8.GetByteCount(s); + var bytes = new byte[byteCount + 1]; + fixed (byte* o = bytes) + fixed (char* input = s) + { + utf8encoder.Convert(input, s.Length, o, bytes.Length, true, out _, out var _, + out var completed); + Debug.Assert(completed); + } + + return bytes; } - return new Span(nullTerminatedString, count); - } - - private static string FromUtf8(ReadOnlySpan input) - { - return Encoding.UTF8.GetString(input); - } - - public static unsafe DialogResult FileOpen(string filterList = null, string defaultPath = null) - { - fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null) - fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) + private static unsafe int GetNullTerminatedStringLength(byte* nullTerminatedString) { - string path = null; - string errorMessage = null; - var result = NativeFunctions.NFD_OpenDialog(filterListNts, defaultPathNts, out IntPtr outPathIntPtr); - if (result == nfdresult_t.NFD_ERROR) + int count = 0; + var ptr = nullTerminatedString; + while (*ptr != 0) { - errorMessage = FromUtf8(MakeSpanFromNullTerminatedString(NativeFunctions.NFD_GetError())); - } - else if (result == nfdresult_t.NFD_OKAY) - { - var outPathNts = (byte*)outPathIntPtr.ToPointer(); - path = FromUtf8(MakeSpanFromNullTerminatedString(outPathNts)); - NativeFunctions.NFD_Free(outPathIntPtr); + ptr++; + count++; } - return new DialogResult(result, path, null, errorMessage); + return count; } - } - - public static unsafe DialogResult FileSave(string filterList = null, string defaultPath = null) - { - fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null) - fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) - { - string path = null; - string errorMessage = null; - var result = NativeFunctions.NFD_SaveDialog(filterListNts, defaultPathNts, out IntPtr outPathIntPtr); - if (result == nfdresult_t.NFD_ERROR) - { - errorMessage = FromUtf8(MakeSpanFromNullTerminatedString(NativeFunctions.NFD_GetError())); - } - else if (result == nfdresult_t.NFD_OKAY) - { - var outPathNts = (byte*)outPathIntPtr.ToPointer(); - path = FromUtf8(MakeSpanFromNullTerminatedString(outPathNts)); - NativeFunctions.NFD_Free(outPathIntPtr); - } - return new DialogResult(result, path, null, errorMessage); - } - } - - public static unsafe DialogResult FolderPicker(string defaultPath = null) - { - fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) + private static unsafe string FromUtf8(byte* nullTerminatedString) { - string path = null; - string errorMessage = null; - var result = NativeFunctions.NFD_PickFolder(defaultPathNts, out IntPtr outPathIntPtr); - if (result == nfdresult_t.NFD_ERROR) - { - errorMessage = FromUtf8(MakeSpanFromNullTerminatedString(NativeFunctions.NFD_GetError())); - } - else if (result == nfdresult_t.NFD_OKAY) - { - var outPathNts = (byte*)outPathIntPtr.ToPointer(); - path = FromUtf8(MakeSpanFromNullTerminatedString(outPathNts)); - NativeFunctions.NFD_Free(outPathIntPtr); - } + return Encoding.UTF8.GetString(nullTerminatedString, GetNullTerminatedStringLength(nullTerminatedString)); + } - return new DialogResult(result, path, null, errorMessage); - } - } - - public static unsafe DialogResult FileOpenMultiple(string filterList = null, string defaultPath = null) - { - fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null) - fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) + public static unsafe DialogResult FileOpen(string filterList = null, string defaultPath = null) { - List paths = null; - string errorMessage = null; - nfdpathset_t pathSet; - var result = NativeFunctions.NFD_OpenDialogMultiple(filterListNts, defaultPathNts, &pathSet); - if (result == nfdresult_t.NFD_ERROR) + fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null) + fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) { - errorMessage = FromUtf8(MakeSpanFromNullTerminatedString(NativeFunctions.NFD_GetError())); - } - else if (result == nfdresult_t.NFD_OKAY) - { - var pathCount = (int)NativeFunctions.NFD_PathSet_GetCount(&pathSet).ToUInt32(); - paths = new List(pathCount); - for (int i = 0; i < pathCount; i++) + string path = null; + string errorMessage = null; + var result = NativeFunctions.NFD_OpenDialog(filterListNts, defaultPathNts, out IntPtr outPathIntPtr); + if (result == nfdresult_t.NFD_ERROR) { - paths.Add(FromUtf8(MakeSpanFromNullTerminatedString(NativeFunctions.NFD_PathSet_GetPath(&pathSet, new UIntPtr((uint)i))))); + errorMessage = FromUtf8(NativeFunctions.NFD_GetError()); + } + else if (result == nfdresult_t.NFD_OKAY) + { + var outPathNts = (byte*)outPathIntPtr.ToPointer(); + path = FromUtf8(outPathNts); + NativeFunctions.NFD_Free(outPathIntPtr); } - NativeFunctions.NFD_PathSet_Free(&pathSet); - } - return new DialogResult(result, null, paths, errorMessage); + return new DialogResult(result, path, null, errorMessage); + } + } + + public static unsafe DialogResult FileSave(string filterList = null, string defaultPath = null) + { + fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null) + fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) + { + string path = null; + string errorMessage = null; + var result = NativeFunctions.NFD_SaveDialog(filterListNts, defaultPathNts, out IntPtr outPathIntPtr); + if (result == nfdresult_t.NFD_ERROR) + { + errorMessage = FromUtf8(NativeFunctions.NFD_GetError()); + } + else if (result == nfdresult_t.NFD_OKAY) + { + var outPathNts = (byte*)outPathIntPtr.ToPointer(); + path = FromUtf8(outPathNts); + NativeFunctions.NFD_Free(outPathIntPtr); + } + + return new DialogResult(result, path, null, errorMessage); + } + } + + public static unsafe DialogResult FolderPicker(string defaultPath = null) + { + fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) + { + string path = null; + string errorMessage = null; + var result = NativeFunctions.NFD_PickFolder(defaultPathNts, out IntPtr outPathIntPtr); + if (result == nfdresult_t.NFD_ERROR) + { + errorMessage = FromUtf8(NativeFunctions.NFD_GetError()); + } + else if (result == nfdresult_t.NFD_OKAY) + { + var outPathNts = (byte*)outPathIntPtr.ToPointer(); + path = FromUtf8(outPathNts); + NativeFunctions.NFD_Free(outPathIntPtr); + } + + return new DialogResult(result, path, null, errorMessage); + } + } + + public static unsafe DialogResult FileOpenMultiple(string filterList = null, string defaultPath = null) + { + fixed (byte* filterListNts = filterList != null ? ToUtf8(filterList) : null) + fixed (byte* defaultPathNts = defaultPath != null ? ToUtf8(defaultPath) : null) + { + List paths = null; + string errorMessage = null; + nfdpathset_t pathSet; + var result = NativeFunctions.NFD_OpenDialogMultiple(filterListNts, defaultPathNts, &pathSet); + if (result == nfdresult_t.NFD_ERROR) + { + errorMessage = FromUtf8(NativeFunctions.NFD_GetError()); + } + else if (result == nfdresult_t.NFD_OKAY) + { + var pathCount = (int)NativeFunctions.NFD_PathSet_GetCount(&pathSet).ToUInt32(); + paths = new List(pathCount); + for (int i = 0; i < pathCount; i++) + { + paths.Add(FromUtf8(NativeFunctions.NFD_PathSet_GetPath(&pathSet, new UIntPtr((uint)i)))); + } + + NativeFunctions.NFD_PathSet_Free(&pathSet); + } + + return new DialogResult(result, null, paths, errorMessage); + } } } -} -public class DialogResult -{ - private readonly nfdresult_t result; - - public string Path { get; } - - public IReadOnlyList Paths { get; } - - public bool IsError => result == nfdresult_t.NFD_ERROR; - - public string ErrorMessage { get; } - - public bool IsCancelled => result == nfdresult_t.NFD_CANCEL; - - public bool IsOk => result == nfdresult_t.NFD_OKAY; - - internal DialogResult(nfdresult_t result, string path, IReadOnlyList paths, string errorMessage) + public class DialogResult { - this.result = result; - Path = path; - Paths = paths; - ErrorMessage = errorMessage; + private readonly nfdresult_t result; + + public string Path { get; } + + public IReadOnlyList Paths { get; } + + public bool IsError => result == nfdresult_t.NFD_ERROR; + + public string ErrorMessage { get; } + + public bool IsCancelled => result == nfdresult_t.NFD_CANCEL; + + public bool IsOk => result == nfdresult_t.NFD_OKAY; + + internal DialogResult(nfdresult_t result, string path, IReadOnlyList paths, string errorMessage) + { + this.result = result; + Path = path; + Paths = paths; + ErrorMessage = errorMessage; + } } } \ No newline at end of file diff --git a/NativeFileDialogSharpSandbox/NativeFileDialogSharpSandbox.csproj b/NativeFileDialogSharpSandbox/NativeFileDialogSharpSandbox.csproj index e9f7684..5f3b95e 100644 --- a/NativeFileDialogSharpSandbox/NativeFileDialogSharpSandbox.csproj +++ b/NativeFileDialogSharpSandbox/NativeFileDialogSharpSandbox.csproj @@ -8,7 +8,7 @@ - + diff --git a/NativeFileDialogSharpSandbox/Program.cs b/NativeFileDialogSharpSandbox/Program.cs index abd3bed..f0a57a1 100644 --- a/NativeFileDialogSharpSandbox/Program.cs +++ b/NativeFileDialogSharpSandbox/Program.cs @@ -1,14 +1,26 @@ -// See https://aka.ms/new-console-template for more information - -using System; -using NativeFileDialogSharp; -using NativeFileDialogSharp.Native; - -var result = Dialog.FileOpenMultiple(); - -Console.WriteLine($"Path: {result.Path}, IsError {result.IsError}, IsOk {result.IsOk}, IsCancelled {result.IsCancelled}, ErrorMessage {result.ErrorMessage}"); -if (result.Paths != null) -{ - Console.WriteLine("Paths"); - Console.WriteLine(string.Join("\n", result.Paths)); -} \ No newline at end of file +using NativeFileDialogSharp; +using System; + +namespace NativeFileDialogSharpSandbox +{ + internal class Program + { + static void Main(string[] args) + { + PrintResult(Dialog.FileOpenMultiple("pdf", null)); + PrintResult(Dialog.FileOpen(null)); + PrintResult(Dialog.FileSave(null)); + PrintResult(Dialog.FolderPicker(null)); + } + + static void PrintResult(DialogResult result) + { + Console.WriteLine($"Path: {result.Path}, IsError {result.IsError}, IsOk {result.IsOk}, IsCancelled {result.IsCancelled}, ErrorMessage {result.ErrorMessage}"); + if (result.Paths != null) + { + Console.WriteLine("Paths"); + Console.WriteLine(string.Join("\n", result.Paths)); + } + } + } +} diff --git a/NativeFileDialogSharpSandboxNetFramework/App.config b/NativeFileDialogSharpSandboxNetFramework/App.config new file mode 100644 index 0000000..e89424b --- /dev/null +++ b/NativeFileDialogSharpSandboxNetFramework/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/NativeFileDialogSharpSandboxNetFramework/NativeFileDialogSharpSandboxNetFramework.csproj b/NativeFileDialogSharpSandboxNetFramework/NativeFileDialogSharpSandboxNetFramework.csproj new file mode 100644 index 0000000..9629bee --- /dev/null +++ b/NativeFileDialogSharpSandboxNetFramework/NativeFileDialogSharpSandboxNetFramework.csproj @@ -0,0 +1,78 @@ + + + + + Debug + AnyCPU + {0FD91168-D8F5-4776-8D91-CB9B9C55AA1B} + Exe + NativeFileDialogSharpSandboxNetFramework + NativeFileDialogSharpSandboxNetFramework + v4.6.2 + 512 + true + true + + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + ..\packages\NativeFileDialogSharp.0.4.4\lib\net461\NativeFileDialogSharp.dll + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NativeFileDialogSharpSandboxNetFramework/Program.cs b/NativeFileDialogSharpSandboxNetFramework/Program.cs new file mode 100644 index 0000000..485a57f --- /dev/null +++ b/NativeFileDialogSharpSandboxNetFramework/Program.cs @@ -0,0 +1,26 @@ +using NativeFileDialogSharp; +using System; + +namespace NativeFileDialogSharpSandboxNetFramework +{ + internal class Program + { + static void Main(string[] args) + { + PrintResult(Dialog.FileOpenMultiple("pdf", null)); + PrintResult(Dialog.FileOpen(null)); + PrintResult(Dialog.FileSave(null)); + PrintResult(Dialog.FolderPicker(null)); + } + + static void PrintResult(DialogResult result) + { + Console.WriteLine($"Path: {result.Path}, IsError {result.IsError}, IsOk {result.IsOk}, IsCancelled {result.IsCancelled}, ErrorMessage {result.ErrorMessage}"); + if (result.Paths != null) + { + Console.WriteLine("Paths"); + Console.WriteLine(string.Join("\n", result.Paths)); + } + } + } +} diff --git a/NativeFileDialogSharpSandboxNetFramework/Properties/AssemblyInfo.cs b/NativeFileDialogSharpSandboxNetFramework/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ffd8a87 --- /dev/null +++ b/NativeFileDialogSharpSandboxNetFramework/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NativeFileDialogSharpSandboxNetFramework")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NativeFileDialogSharpSandboxNetFramework")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0fd91168-d8f5-4776-8d91-cb9b9c55aa1b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NativeFileDialogSharpSandboxNetFramework/packages.config b/NativeFileDialogSharpSandboxNetFramework/packages.config new file mode 100644 index 0000000..7826378 --- /dev/null +++ b/NativeFileDialogSharpSandboxNetFramework/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file