Skip to content

Commit 7b1e066

Browse files
authored
Improved support for network locations (#3295)
1 parent 574024c commit 7b1e066

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1938
-350
lines changed

Files.Launcher/Files.Launcher.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<Compile Include="DragDropForm.cs">
130130
<SubType>Form</SubType>
131131
</Compile>
132+
<Compile Include="NetworkDrivesAPI.cs" />
132133
<Compile Include="Program.cs" />
133134
<Compile Include="Properties\AssemblyInfo.cs" />
134135
<Compile Include="QuickLook.cs" />
@@ -157,6 +158,9 @@
157158
<PackageReference Include="System.Runtime.WindowsRuntime.UI.Xaml">
158159
<Version>4.7.0</Version>
159160
</PackageReference>
161+
<PackageReference Include="Vanara.PInvoke.Mpr">
162+
<Version>3.3.4</Version>
163+
</PackageReference>
160164
<PackageReference Include="Vanara.Windows.Shell">
161165
<Version>3.3.4</Version>
162166
</PackageReference>

Files.Launcher/NetworkDrivesAPI.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Runtime.InteropServices;
4+
using System.Windows.Forms;
5+
using Vanara.Extensions;
6+
using Vanara.InteropServices;
7+
using static Vanara.PInvoke.Mpr;
8+
9+
namespace FilesFullTrust
10+
{
11+
public class NetworkDrivesAPI
12+
{
13+
/// <summary>
14+
/// A dialog box that allows the user to browse and connect to network resources.
15+
/// </summary>
16+
public class NetworkConnectionDialog : CommonDialog
17+
{
18+
private NETRESOURCE nres = new NETRESOURCE();
19+
private CONNECTDLGSTRUCT opts;
20+
21+
/// <summary>Initializes a new instance of the <see cref="NetworkConnectionDialog"/> class.</summary>
22+
public NetworkConnectionDialog()
23+
{
24+
opts.cbStructure = (uint)Marshal.SizeOf(typeof(CONNECTDLGSTRUCT));
25+
nres.dwType = NETRESOURCEType.RESOURCETYPE_DISK;
26+
}
27+
28+
/// <summary>Gets the connected device number. This value is only valid after successfully running the dialog.</summary>
29+
/// <value>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.</value>
30+
[Browsable(false)]
31+
public int ConnectedDeviceNumber => opts.dwDevNum;
32+
33+
/// <summary>Gets or sets a value indicating whether to hide the check box allowing the user to restore the connection at logon.</summary>
34+
/// <value><c>true</c> if hiding restore connection check box; otherwise, <c>false</c>.</value>
35+
[DefaultValue(false), Category("Appearance"), Description("Hide the check box allowing the user to restore the connection at logon.")]
36+
public bool HideRestoreConnectionCheckBox
37+
{
38+
get => opts.dwFlags.IsFlagSet(CONN_DLG.CONNDLG_HIDE_BOX);
39+
set => opts.dwFlags = opts.dwFlags.SetFlags(CONN_DLG.CONNDLG_HIDE_BOX, value);
40+
}
41+
42+
/// <summary>Gets or sets a value indicating whether restore the connection at logon.</summary>
43+
/// <value><c>true</c> to restore connection at logon; otherwise, <c>false</c>.</value>
44+
[DefaultValue(false), Category("Behavior"), Description("Restore the connection at logon.")]
45+
public bool PersistConnectionAtLogon
46+
{
47+
get => opts.dwFlags.IsFlagSet(CONN_DLG.CONNDLG_PERSIST);
48+
set
49+
{
50+
opts.dwFlags = opts.dwFlags.SetFlags(CONN_DLG.CONNDLG_PERSIST, value);
51+
opts.dwFlags = opts.dwFlags.SetFlags(CONN_DLG.CONNDLG_NOT_PERSIST, !value);
52+
}
53+
}
54+
55+
/// <summary>
56+
/// Gets or sets a value indicating whether to display a read-only path instead of allowing the user to type in a path. This is only
57+
/// valid if <see cref="RemoteNetworkName"/> is not <see langword="null"/>.
58+
/// </summary>
59+
/// <value><c>true</c> to display a read only path; otherwise, <c>false</c>.</value>
60+
[DefaultValue(false), Category("Appearance"), Description("Display a read-only path instead of allowing the user to type in a path.")]
61+
public bool ReadOnlyPath { get; set; }
62+
63+
/// <summary>Gets or sets the name of the remote network.</summary>
64+
/// <value>The name of the remote network.</value>
65+
[DefaultValue(null), Category("Behavior"), Description("The value displayed in the path field.")]
66+
public string RemoteNetworkName { get => nres.lpRemoteName; set => nres.lpRemoteName = value; }
67+
68+
/// <summary>Gets or sets a value indicating whether to enter the most recently used paths into the combination box.</summary>
69+
/// <value><c>true</c> to use MRU path; otherwise, <c>false</c>.</value>
70+
/// <exception cref="InvalidOperationException">UseMostRecentPath</exception>
71+
[DefaultValue(false), Category("Behavior"), Description("Enter the most recently used paths into the combination box.")]
72+
public bool UseMostRecentPath
73+
{
74+
get => opts.dwFlags.IsFlagSet(CONN_DLG.CONNDLG_USE_MRU);
75+
set
76+
{
77+
if (value && !string.IsNullOrEmpty(RemoteNetworkName))
78+
throw new InvalidOperationException($"{nameof(UseMostRecentPath)} cannot be set to true if {nameof(RemoteNetworkName)} has a value.");
79+
opts.dwFlags = opts.dwFlags.SetFlags(CONN_DLG.CONNDLG_USE_MRU, value);
80+
}
81+
}
82+
83+
/// <inheritdoc/>
84+
public override void Reset()
85+
{
86+
opts.dwDevNum = -1;
87+
opts.dwFlags = 0;
88+
opts.lpConnRes = IntPtr.Zero;
89+
ReadOnlyPath = false;
90+
}
91+
92+
/// <inheritdoc/>
93+
protected override bool RunDialog(IntPtr hwndOwner)
94+
{
95+
using (var lpnres = SafeCoTaskMemHandle.CreateFromStructure(nres))
96+
{
97+
opts.hwndOwner = hwndOwner;
98+
opts.lpConnRes = lpnres.DangerousGetHandle();
99+
if (ReadOnlyPath && !string.IsNullOrEmpty(nres.lpRemoteName))
100+
opts.dwFlags |= CONN_DLG.CONNDLG_RO_PATH;
101+
var ret = WNetConnectionDialog1(opts);
102+
opts.lpConnRes = IntPtr.Zero;
103+
if (ret == unchecked((uint)-1)) return false;
104+
ret.ThrowIfFailed();
105+
return true;
106+
}
107+
}
108+
}
109+
110+
public static bool OpenMapNetworkDriveDialog()
111+
{
112+
using var ncd = new NetworkConnectionDialog { UseMostRecentPath = true };
113+
ncd.HideRestoreConnectionCheckBox = false;
114+
return ncd.ShowDialog() == DialogResult.OK;
115+
}
116+
117+
public static bool DisconnectNetworkDrive(string drive)
118+
{
119+
return !WNetCancelConnection2(drive.TrimEnd('\\'), CONNECT.CONNECT_UPDATE_PROFILE, true).Failed;
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)