diff --git a/src/Files.App/Files.App.csproj b/src/Files.App/Files.App.csproj index 33cdbc317433..03908729c6a7 100644 --- a/src/Files.App/Files.App.csproj +++ b/src/Files.App/Files.App.csproj @@ -93,10 +93,8 @@ - - - + diff --git a/src/Files.App/NativeMethods.txt b/src/Files.App/NativeMethods.txt index d7956acc3785..07401d489bd7 100644 --- a/src/Files.App/NativeMethods.txt +++ b/src/Files.App/NativeMethods.txt @@ -46,6 +46,16 @@ DeleteFileFromApp RemoveDirectoryFromApp GetKeyState CreateDirectoryFromApp +WNetCancelConnection2 +NET_USE_CONNECT_FLAGS +NETRESOURCEW +WNetAddConnection3 +CREDENTIALW +CredWrite +WNetConnectionDialog1 +CONNECTDLGSTRUCTW +DwmSetWindowAttribute +WIN32_ERROR CoCreateInstance FileOpenDialog IFileOpenDialog diff --git a/src/Files.App/Services/CommonDialogService.cs b/src/Files.App/Services/CommonDialogService.cs index 3b7d19d868ea..c06de3b04cc1 100644 --- a/src/Files.App/Services/CommonDialogService.cs +++ b/src/Files.App/Services/CommonDialogService.cs @@ -7,6 +7,7 @@ using Vanara.Extensions; using Windows.Win32; using Windows.Win32.Foundation; +using Windows.Win32.NetworkManagement.WNet; using Windows.Win32.System.Com; using Windows.Win32.UI.Shell; using Windows.Win32.UI.Shell.Common; @@ -179,31 +180,34 @@ public bool Open_NetworkConnectionDialog(nint hWind, bool hideRestoreConnectionC private sealed class NetworkConnectionDialog : CommonDialog { - private readonly Vanara.PInvoke.Mpr.NETRESOURCE netRes = new(); - private Vanara.PInvoke.Mpr.CONNECTDLGSTRUCT dialogOptions; + private NETRESOURCEW netRes = new(); + private CONNECTDLGSTRUCTW dialogOptions; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. public NetworkConnectionDialog() { - dialogOptions.cbStructure = (uint)Marshal.SizeOf(typeof(Vanara.PInvoke.Mpr.CONNECTDLGSTRUCT)); - netRes.dwType = Vanara.PInvoke.Mpr.NETRESOURCEType.RESOURCETYPE_DISK; + dialogOptions.cbStructure = (uint)Marshal.SizeOf(typeof(CONNECTDLGSTRUCTW)); + netRes.dwType = NET_RESOURCE_TYPE.RESOURCETYPE_DISK; } /// Gets the connected device number. This value is only valid after successfully running the dialog. /// The connected device number. The value is 1 for A:, 2 for B:, 3 for C:, and so on. If the user made a deviceless connection, the value is –1. [Browsable(false)] - public int ConnectedDeviceNumber - => dialogOptions.dwDevNum; + public int ConnectedDeviceNumber => (int)dialogOptions.dwDevNum; /// Gets or sets a value indicating whether to hide the check box allowing the user to restore the connection at logon. /// true if hiding restore connection check box; otherwise, false. [DefaultValue(false), Category("Appearance"), Description("Hide the check box allowing the user to restore the connection at logon.")] public bool HideRestoreConnectionCheckBox { - get => dialogOptions.dwFlags.IsFlagSet(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_HIDE_BOX); - set => dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_HIDE_BOX, value); + get => dialogOptions.dwFlags.HasFlag(CONNECTDLGSTRUCT_FLAGS.CONNDLG_HIDE_BOX); + set + { + if (value) + dialogOptions.dwFlags |= CONNECTDLGSTRUCT_FLAGS.CONNDLG_HIDE_BOX; + else + dialogOptions.dwFlags &= ~CONNECTDLGSTRUCT_FLAGS.CONNDLG_HIDE_BOX; + } } /// Gets or sets a value indicating whether restore the connection at logon. @@ -211,11 +215,11 @@ public bool HideRestoreConnectionCheckBox [DefaultValue(false), Category("Behavior"), Description("Restore the connection at logon.")] public bool PersistConnectionAtLogon { - get => dialogOptions.dwFlags.IsFlagSet(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_PERSIST); + get => dialogOptions.dwFlags.IsFlagSet(CONNECTDLGSTRUCT_FLAGS.CONNDLG_PERSIST); set { - dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_PERSIST, value); - dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_NOT_PERSIST, !value); + dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(CONNECTDLGSTRUCT_FLAGS.CONNDLG_PERSIST, value); + dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(CONNECTDLGSTRUCT_FLAGS.CONNDLG_NOT_PERSIST, !value); } } @@ -230,7 +234,18 @@ public bool PersistConnectionAtLogon /// Gets or sets the name of the remote network. /// The name of the remote network. [DefaultValue(null), Category("Behavior"), Description("The value displayed in the path field.")] - public string RemoteNetworkName { get => netRes.lpRemoteName; set => netRes.lpRemoteName = value; } + public string RemoteNetworkName + { + get => netRes.lpRemoteName.ToString(); + set + { + unsafe + { + fixed (char* lpcRemoteName = value) + netRes.lpRemoteName = lpcRemoteName; + } + } + } /// Gets or sets a value indicating whether to enter the most recently used paths into the combination box. /// true to use MRU path; otherwise, false. @@ -238,44 +253,45 @@ public bool PersistConnectionAtLogon [DefaultValue(false), Category("Behavior"), Description("Enter the most recently used paths into the combination box.")] public bool UseMostRecentPath { - get => dialogOptions.dwFlags.IsFlagSet(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_USE_MRU); + get => dialogOptions.dwFlags.IsFlagSet(CONNECTDLGSTRUCT_FLAGS.CONNDLG_USE_MRU); set { if (value && !string.IsNullOrEmpty(RemoteNetworkName)) throw new InvalidOperationException($"{nameof(UseMostRecentPath)} cannot be set to true if {nameof(RemoteNetworkName)} has a value."); - dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_USE_MRU, value); + dialogOptions.dwFlags = dialogOptions.dwFlags.SetFlags(CONNECTDLGSTRUCT_FLAGS.CONNDLG_USE_MRU, value); } } /// - public override void Reset() + public unsafe override void Reset() { - dialogOptions.dwDevNum = -1; + dialogOptions.dwDevNum = unchecked((uint)-1); dialogOptions.dwFlags = 0; - dialogOptions.lpConnRes = IntPtr.Zero; + dialogOptions.lpConnRes = null; ReadOnlyPath = false; } /// - protected override bool RunDialog(IntPtr hwndOwner) + protected unsafe override bool RunDialog(IntPtr hwndOwner) { - using var lpNetResource = Vanara.InteropServices.SafeCoTaskMemHandle.CreateFromStructure(netRes); + dialogOptions.hwndOwner = new(hwndOwner); - dialogOptions.hwndOwner = hwndOwner; - dialogOptions.lpConnRes = lpNetResource.DangerousGetHandle(); + fixed (NETRESOURCEW* lpConnRes = &netRes) + dialogOptions.lpConnRes = lpConnRes; - if (ReadOnlyPath && !string.IsNullOrEmpty(netRes.lpRemoteName)) - dialogOptions.dwFlags |= Vanara.PInvoke.Mpr.CONN_DLG.CONNDLG_RO_PATH; + if (ReadOnlyPath && !string.IsNullOrEmpty(netRes.lpRemoteName.ToString())) + dialogOptions.dwFlags |= CONNECTDLGSTRUCT_FLAGS.CONNDLG_RO_PATH; - var result = Vanara.PInvoke.Mpr.WNetConnectionDialog1(dialogOptions); + var result = PInvoke.WNetConnectionDialog1W(ref dialogOptions); - dialogOptions.lpConnRes = IntPtr.Zero; + dialogOptions.lpConnRes = null; - if (result == unchecked((uint)-1)) + if ((uint)result == unchecked((uint)-1)) return false; - result.ThrowIfFailed(); + if (result == 0) + throw new Win32Exception("Cannot display dialog"); return true; } diff --git a/src/Files.App/Services/NetworkService.cs b/src/Files.App/Services/NetworkService.cs index d7a172e0abbc..e0249c33b7c8 100644 --- a/src/Files.App/Services/NetworkService.cs +++ b/src/Files.App/Services/NetworkService.cs @@ -3,11 +3,12 @@ using System.Runtime.InteropServices; using System.Text; -using Vanara.InteropServices; using Vanara.PInvoke; using Vanara.Windows.Shell; -using static Vanara.PInvoke.AdvApi32; -using static Vanara.PInvoke.Mpr; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.NetworkManagement.WNet; +using Windows.Win32.Security.Credentials; namespace Files.App.Services { @@ -180,7 +181,12 @@ public async Task UpdateShortcutsAsync() /// public bool DisconnectNetworkDrive(ILocatableFolder drive) { - return WNetCancelConnection2(drive.Path.TrimEnd('\\'), CONNECT.CONNECT_UPDATE_PROFILE, true).Succeeded; + return + PInvoke.WNetCancelConnection2W( + drive.Path.TrimEnd('\\'), + (uint)NET_USE_CONNECT_FLAGS.CONNECT_UPDATE_PROFILE, + true) + is WIN32_ERROR.NO_ERROR; } /// @@ -198,16 +204,18 @@ public Task OpenMapNetworkDriveDialogAsync() /// public async Task AuthenticateNetworkShare(string path) { - var netRes = new NETRESOURCE() + var netRes = new NETRESOURCEW() { dwType = NET_RESOURCE_TYPE.RESOURCETYPE_DISK }; + + unsafe { - dwType = NETRESOURCEType.RESOURCETYPE_DISK, - lpRemoteName = path - }; + fixed (char* lpcPath = path) + netRes.lpRemoteName = new PWSTR(lpcPath); + } // If credentials are saved, this will return NO_ERROR - Win32Error connectionError = WNetAddConnection3(HWND.NULL, netRes, null, null, 0); + var res = (WIN32_ERROR)PInvoke.WNetAddConnection3W(new(nint.Zero), netRes, null, null, 0); - if (connectionError == Win32Error.ERROR_LOGON_FAILURE || connectionError == Win32Error.ERROR_ACCESS_DENIED) + if (res == WIN32_ERROR.ERROR_LOGON_FAILURE || res == WIN32_ERROR.ERROR_ACCESS_DENIED) { var dialog = DynamicDialogFactory.GetFor_CredentialEntryDialog(path); await dialog.ShowAsync(); @@ -215,22 +223,32 @@ public async Task AuthenticateNetworkShare(string path) if (credentialsReturned is not null && credentialsReturned[1] != null) { - connectionError = WNetAddConnection3(HWND.NULL, netRes, credentialsReturned[1], credentialsReturned[0], 0); - if (credentialsReturned[2] == "y" && connectionError == Win32Error.NO_ERROR) + res = (WIN32_ERROR)PInvoke.WNetAddConnection3W(new(nint.Zero), netRes, credentialsReturned[1], credentialsReturned[0], 0); + if (credentialsReturned[2] == "y" && res == WIN32_ERROR.NO_ERROR) { - var creds = new CREDENTIAL + var creds = new CREDENTIALW() { - TargetName = new StrPtrAuto(path.Substring(2)), - UserName = new StrPtrAuto(credentialsReturned[0]), Type = CRED_TYPE.CRED_TYPE_DOMAIN_PASSWORD, AttributeCount = 0, Persist = CRED_PERSIST.CRED_PERSIST_ENTERPRISE }; - byte[] bPassword = Encoding.Unicode.GetBytes(credentialsReturned[1]); - creds.CredentialBlobSize = (uint)bPassword.Length; - creds.CredentialBlob = Marshal.StringToCoTaskMemUni(credentialsReturned[1]); - CredWrite(creds, 0); + unsafe + { + fixed (char* lpcTargetName = path.Substring(2)) + creds.TargetName = new(lpcTargetName); + + fixed (char* lpcUserName = credentialsReturned[0]) + creds.UserName = new(lpcUserName); + + byte[] bPassword = Encoding.Unicode.GetBytes(credentialsReturned[1]); + fixed (byte* lpCredentialBlob = bPassword) + creds.CredentialBlob = lpCredentialBlob; + + creds.CredentialBlobSize = (uint)bPassword.Length; + } + + PInvoke.CredWrite(creds, 0); } } else @@ -239,13 +257,13 @@ public async Task AuthenticateNetworkShare(string path) } } - if (connectionError == Win32Error.NO_ERROR) + if (res == WIN32_ERROR.NO_ERROR) { return true; } else { - await DialogDisplayHelper.ShowDialogAsync("NetworkFolderErrorDialogTitle".GetLocalizedResource(), connectionError.ToString().Split(":")[1].Trim()); + await DialogDisplayHelper.ShowDialogAsync("NetworkFolderErrorDialogTitle".GetLocalizedResource(), res.ToString()); return false; } diff --git a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs index 17f96846185f..4a932c1de4df 100644 --- a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs @@ -11,6 +11,8 @@ using Windows.Win32.Graphics.Dxgi; using Windows.Win32.Graphics.DirectComposition; using WinRT; +using Windows.Win32; +using Windows.Win32.Graphics.Dwm; using static Vanara.PInvoke.ShlwApi; using static Vanara.PInvoke.User32; @@ -178,7 +180,18 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter) Marshal.ReleaseComObject(d3d11Device); Marshal.ReleaseComObject(d3d11DeviceContext); - return DwmApi.DwmSetWindowAttribute(hwnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_CLOAK, true).Succeeded; + unsafe + { + var dwAttrib = Convert.ToUInt32(true); + + return + PInvoke.DwmSetWindowAttribute( + new((nint)hwnd), + DWMWINDOWATTRIBUTE.DWMWA_CLOAK, + &dwAttrib, + (uint)Marshal.SizeOf(dwAttrib)) + .Succeeded; + } } public void UnloadPreview() @@ -195,7 +208,17 @@ public void PointerEntered(bool onPreview) { if (onPreview) { - DwmApi.DwmSetWindowAttribute(hwnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_CLOAK, false); + unsafe + { + var dwAttrib = Convert.ToUInt32(false); + + PInvoke.DwmSetWindowAttribute( + new((nint)hwnd), + DWMWINDOWATTRIBUTE.DWMWA_CLOAK, + &dwAttrib, + (uint)Marshal.SizeOf(dwAttrib)); + } + if (isOfficePreview) Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE, 0); } @@ -203,7 +226,17 @@ public void PointerEntered(bool onPreview) { Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE, (nint)(WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_COMPOSITED)); - DwmApi.DwmSetWindowAttribute(hwnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_CLOAK, true); + + unsafe + { + var dwAttrib = Convert.ToUInt32(true); + + PInvoke.DwmSetWindowAttribute( + new((nint)hwnd), + DWMWINDOWATTRIBUTE.DWMWA_CLOAK, + &dwAttrib, + (uint)Marshal.SizeOf(dwAttrib)); + } } } }