diff --git a/build.bat b/build.bat index 2e7a27c0..b055284c 100644 --- a/build.bat +++ b/build.bat @@ -6,7 +6,7 @@ cd src rmdir /s /q bin rmdir /s /q obj dotnet publish SourceGit_48.csproj --nologo -c Release -r win-x86 -o ..\publish\net48 -ilrepack /ndebug /out:..\publish\SourceGit.exe ..\publish\net48\SourceGit.exe ..\publish\net48\Newtonsoft.Json.dll ..\publish\net48\Ookii.Dialogs.Wpf.dll +ilrepack /ndebug /out:..\publish\SourceGit.exe ..\publish\net48\SourceGit.exe ..\publish\net48\Newtonsoft.Json.dll cd ..\publish ren SourceGit.exe SourceGit_48.exe rmdir /s /q net48 diff --git a/src/Resources/Locales/en_US.xaml b/src/Resources/Locales/en_US.xaml index a65fa255..c073e9b1 100644 --- a/src/Resources/Locales/en_US.xaml +++ b/src/Resources/Locales/en_US.xaml @@ -15,6 +15,7 @@ FILTER Optional. ‡Directory|*.this.directory + SELECT FOLDER URL : Git Repository URL diff --git a/src/Resources/Locales/zh_CN.xaml b/src/Resources/Locales/zh_CN.xaml index 239b8852..d826eefa 100644 --- a/src/Resources/Locales/zh_CN.xaml +++ b/src/Resources/Locales/zh_CN.xaml @@ -14,6 +14,7 @@ 过滤 选填 ‡路径|*.this.directory + 选择文件夹 仓库地址 : 远程仓库地址 diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj index 8334690d..07d315e7 100644 --- a/src/SourceGit.csproj +++ b/src/SourceGit.csproj @@ -17,7 +17,4 @@ true none - - - \ No newline at end of file diff --git a/src/SourceGit_48.csproj b/src/SourceGit_48.csproj index cee9d989..cdca829d 100644 --- a/src/SourceGit_48.csproj +++ b/src/SourceGit_48.csproj @@ -21,6 +21,5 @@ - \ No newline at end of file diff --git a/src/Views/Controls/FolderDialog.cs b/src/Views/Controls/FolderDialog.cs new file mode 100644 index 00000000..d5f9186a --- /dev/null +++ b/src/Views/Controls/FolderDialog.cs @@ -0,0 +1,124 @@ +using System; +using System.Runtime.InteropServices; +using System.Security; + +namespace SourceGit.Views.Controls { + + [SuppressUnmanagedCodeSecurity] + internal delegate Int32 BrowseCallbackProc(IntPtr hwnd, Int32 msg, IntPtr lParam, IntPtr lpData); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + [SuppressUnmanagedCodeSecurity] + internal class BrowseInfo { + public IntPtr hwndOwner; + public IntPtr pidlRoot; + public IntPtr pszDisplayName; + public String lpszTitle; + public Int32 ulFlags; + public BrowseCallbackProc lpfn; + public IntPtr lParam; + public Int32 iImage; + } + + /// + /// Win32 API封装(user32.dll) + /// + [SuppressUnmanagedCodeSecurity] + internal static class User32 { + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, String lParam); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam); + } + + /// + /// Win32 API封装(ole32.dll) + /// + [SuppressUnmanagedCodeSecurity] + internal static class Ole32 { + [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)] + internal static extern void CoTaskMemFree(IntPtr pv); + } + + /// + /// Win32 API封装(shell32.dll) + /// + [SuppressUnmanagedCodeSecurity] + internal static class Shell32 { + [DllImport("shell32.dll", CharSet = CharSet.Auto)] + public static extern Boolean SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath); + + [DllImport("shell32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr SHBrowseForFolder([In] BrowseInfo lpbi); + } + + /// + /// 调用WindowsAPI打开对话目录对话框 + /// + public class FolderDialog : Microsoft.Win32.CommonDialog { + /// + /// 选中的目录 + /// + public string SelectedPath { get; private set; } = string.Empty; + + public override void Reset() { + SelectedPath = string.Empty; + } + + protected override bool RunDialog(IntPtr hwndOwner) { + BrowseCallbackProc callback = new BrowseCallbackProc(BrowseCallbackHandler); + bool ok = false; + try { + var info = new BrowseInfo(); + info.pidlRoot = IntPtr.Zero; + info.hwndOwner = hwndOwner; + info.pszDisplayName = IntPtr.Zero; + info.lpszTitle = null; + info.ulFlags = 0x0153; + info.lpfn = callback; + info.lParam = IntPtr.Zero; + info.iImage = 0; + + IntPtr result = Shell32.SHBrowseForFolder(info); + if (result != IntPtr.Zero) { + IntPtr pathPtr = Marshal.AllocHGlobal(260 * Marshal.SystemDefaultCharSize); + Shell32.SHGetPathFromIDList(result, pathPtr); + + if (pathPtr != IntPtr.Zero) { + SelectedPath = Marshal.PtrToStringAuto(pathPtr); + ok = true; + Marshal.FreeHGlobal(pathPtr); + } + + Ole32.CoTaskMemFree(result); + } + } finally { + callback = null; + } + + return ok; + } + + private Int32 BrowseCallbackHandler(IntPtr hwnd, Int32 msg, IntPtr lParam, IntPtr lpData) { + switch (msg) { + case 1: + if (!string.IsNullOrEmpty(SelectedPath)) { + Int32 flag = Marshal.SystemDefaultCharSize == 1 ? 1126 : 1127; + User32.SendMessage(new HandleRef(null, hwnd), flag, 1, SelectedPath); + } + break; + case 2: + if (lParam != IntPtr.Zero) { + IntPtr pathPtr = Marshal.AllocHGlobal(260 * Marshal.SystemDefaultCharSize); + bool flag = Shell32.SHGetPathFromIDList(lParam, pathPtr); + Marshal.FreeHGlobal(pathPtr); + User32.SendMessage(new HandleRef(null, hwnd), 1125, 0, flag ? 1 : 0); + } + break; + } + + return 0; + } + } +} diff --git a/src/Views/Popups/Clone.xaml.cs b/src/Views/Popups/Clone.xaml.cs index db8becbc..6bd9d1d5 100644 --- a/src/Views/Popups/Clone.xaml.cs +++ b/src/Views/Popups/Clone.xaml.cs @@ -1,4 +1,3 @@ -using Ookii.Dialogs.Wpf; using System.Threading.Tasks; using System.Windows.Controls; @@ -55,7 +54,7 @@ namespace SourceGit.Views.Popups { } private void OnFolderSelectorClick(object sender, System.Windows.RoutedEventArgs e) { - var dialog = new VistaFolderBrowserDialog(); + var dialog = new Controls.FolderDialog(); if (dialog.ShowDialog() == true) { Folder = dialog.SelectedPath; txtFolder.GetBindingExpression(TextBox.TextProperty).UpdateTarget(); diff --git a/src/Views/Preference.xaml.cs b/src/Views/Preference.xaml.cs index ceeca412..7d44fc5d 100644 --- a/src/Views/Preference.xaml.cs +++ b/src/Views/Preference.xaml.cs @@ -1,5 +1,4 @@ using Microsoft.Win32; -using Ookii.Dialogs.Wpf; using System; using System.Windows; using System.Windows.Controls; @@ -62,7 +61,7 @@ namespace SourceGit.Views { } private void SelectGitCloneDir(object sender, RoutedEventArgs e) { - var dialog = new VistaFolderBrowserDialog(); + var dialog = new Controls.FolderDialog(); if (dialog.ShowDialog() == true) { Models.Preference.Instance.Git.DefaultCloneDir = dialog.SelectedPath; txtGitCloneDir?.GetBindingExpression(TextBox.TextProperty).UpdateTarget(); diff --git a/src/Views/Widgets/Histories.xaml.cs b/src/Views/Widgets/Histories.xaml.cs index a28eac78..fc8ac782 100644 --- a/src/Views/Widgets/Histories.xaml.cs +++ b/src/Views/Widgets/Histories.xaml.cs @@ -1,4 +1,3 @@ -using Ookii.Dialogs.Wpf; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -349,7 +348,7 @@ namespace SourceGit.Views.Widgets { var saveToPatch = new MenuItem(); saveToPatch.Header = App.Text("CommitCM.SaveAsPatch"); saveToPatch.Click += (o, e) => { - var dialog = new VistaFolderBrowserDialog(); + var dialog = new Controls.FolderDialog(); if (dialog.ShowDialog() == true) { new Commands.FormatPatch(repo.Path, commit.SHA, dialog.SelectedPath).Exec(); } diff --git a/src/Views/Widgets/RevisionFiles.xaml.cs b/src/Views/Widgets/RevisionFiles.xaml.cs index 9ac98301..7fd87309 100644 --- a/src/Views/Widgets/RevisionFiles.xaml.cs +++ b/src/Views/Widgets/RevisionFiles.xaml.cs @@ -1,4 +1,3 @@ -using Ookii.Dialogs.Wpf; using System; using System.Collections.Generic; using System.Diagnostics; @@ -296,7 +295,7 @@ namespace SourceGit.Views.Widgets { saveAs.Header = App.Text("SaveAs"); saveAs.IsEnabled = node.Type == Models.ObjectType.Blob; saveAs.Click += (obj, ev) => { - var dialog = new VistaFolderBrowserDialog(); + var dialog = new Controls.FolderDialog(); if (dialog.ShowDialog() == true) { var full = Path.Combine(dialog.SelectedPath, Path.GetFileName(node.Path)); new Commands.SaveRevisionFile(repo, node.Path, sha, full).Exec(); diff --git a/src/Views/Widgets/Welcome.xaml.cs b/src/Views/Widgets/Welcome.xaml.cs index 154afa0a..bd027cba 100644 --- a/src/Views/Widgets/Welcome.xaml.cs +++ b/src/Views/Widgets/Welcome.xaml.cs @@ -1,4 +1,3 @@ -using Ookii.Dialogs.Wpf; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -48,7 +47,7 @@ namespace SourceGit.Views.Widgets { #region FUNC_EVENTS private void OnOpenClicked(object sender, RoutedEventArgs e) { - var dialog = new VistaFolderBrowserDialog(); + var dialog = new Controls.FolderDialog(); if (dialog.ShowDialog() == true) CheckAndOpen(dialog.SelectedPath); }