I have a class that is a simple wrapper for WNetUseConnection
Here is the implementation (for reference only):
internal class RemoteFileSystemContext : IDisposable
{
private readonly string _remoteUnc;
private bool _isConnected;
public RemoteFileSystemContext(string remoteUnc, string username, string password, bool promptUser)
{
if (WindowsNetworking.TryConnectToRemote(remoteUnc, username, password, promptUser))
{
_isConnected = true;
_remoteUnc = remoteUnc;
}
else
{
GC.SuppressFinalize(this);
}
}
public void Dispose()
{
Dispose(true);
}
~RemoteFileSystemContext()
{
Dispose(false);
}
private void Dispose(bool isDisposing)
{
if (!_isConnected)
return;
_isConnected = false;
if (isDisposing)
{
GC.SuppressFinalize(this);
}
WindowsNetworking.DisconnectRemote(_remoteUnc);
}
}
and here is used:
using (var context = WindowsNetworking.CreateRemoteContext(storagePath, login, pass))
{
GC.KeepAlive(context);
}
The question is whether to write GC.KeepAlive(context)or not? I mean that I did not write such code until I read the article (about AsyncLock, but now I can not find the link), and now I'm not sure that the GC can call the finalizer before this method completes. Theoretically, it should use Disposein the section finally using, but this article is written by a smart guy, so I'm not sure right now.
Just in case, I provide the code for the reference class:
public static class WindowsNetworking
{
public static bool TryConnectToRemote(string remoteUnc, string username, string password, bool promptUser = false)
{
bool isUnc = remoteUnc != null && remoteUnc.Length >= 2 && remoteUnc[0] == '\\' && remoteUnc[1] == '\\';
if (!isUnc)
{
return false;
}
ConnectToRemote(remoteUnc, username, password, promptUser);
return true;
}
public static IDisposable CreateRemoteContext(string remoteUnc, string username, string password, bool promptUser = false)
{
return new RemoteFileSystemContext(remoteUnc, username, password, promptUser);
}
public static void DisconnectRemote(string remoteUNC)
{
var ret = (NetworkError) WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
if (ret != NetworkError.NO_ERROR)
{
throw new Win32Exception((int) ret, ret.ToString());
}
}
[DllImport("Mpr.dll")]
private static extern int WNetUseConnection(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
int dwFlags,
string lpAccessName,
string lpBufferSize,
string lpResult
);
[DllImport("Mpr.dll")]
private static extern int WNetCancelConnection2(
string lpName,
int dwFlags,
bool fForce
);
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
}
private static void ConnectToRemote(string remoteUNC, string username, string password, bool promptUser)
{
NETRESOURCE nr = new NETRESOURCE
{
dwType = RESOURCETYPE_DISK,
lpRemoteName = remoteUNC
};
NetworkError ret;
if (promptUser)
ret = (NetworkError) WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
else
ret = (NetworkError) WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);
if (ret != NetworkError.NO_ERROR)
{
throw new Win32Exception((int) ret, ret.ToString());
}
}
}