There is no .NET method for creating a network drive yet (as of .NET 4.0) so here is how you can do it using good old Windows APIs 🙂 As well as the API definitions, I’ve included a managed method that wraps up the functionality of the API so that it is easier to use from .NET code.
Here are the API definitions:
Public Const RESOURCETYPE_DISK As UInteger = 1
”’ <summary>
”’ Contains information about a network resource. Used by the WNetAddConnection2 method
”’ </summary>
<StructLayoutAttribute(LayoutKind.Sequential)> _
Public Structure NETRESOURCE
Public dwScope As UInteger
Public dwType As UInteger
Public dwDisplayType As UInteger
Public dwUsage As UInteger
<MarshalAsAttribute(UnmanagedType.LPWStr)> _
Public lpLocalName As String
<MarshalAsAttribute(UnmanagedType.LPWStr)> _
Public lpRemoteName As String
<MarshalAsAttribute(UnmanagedType.LPWStr)> _
Public lpComment As String
<MarshalAsAttribute(UnmanagedType.LPWStr)> _
Public lpProvider As String
End Structure
”’ <summary>
”’ Creates a connection to a network resource
”’ </summary>
”’ <param name=”lpNetResource”>A NETRESOURCE structure that specifies information about the network resource connection</param>
”’ <param name=”lpPassword”>The password to use for the connection – leave blank to use current user credentials</param>
”’ <param name=”lpUserName”>The username to use for the connection – leave blank to use current user credentials</param>
”’ <param name=”dwFlags”>Bitmask that specifies connection options. For example, whether or not to make the connection persistent</param>
<DllImportAttribute(“mpr.dll”, EntryPoint:=“WNetAddConnection2W”)> _
Public Shared Function WNetAddConnection2(ByRef lpNetResource As NETRESOURCE, <InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpPassword As String, <InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpUserName As String, ByVal dwFlags As UInteger) As UInteger
End Function
and here is my .NET method that makes the API easier to use – the idea is that you call this .NET method and just pass in basic information instead of having to call the API directly and mess around building structures etc each time:
”’ Creates a network drive (aka mapped drive) using the specified drive letter, UNC path and optional credentials
”’ </summary>
”’ <param name=”UncPath”>The UNC path (\\servername\share) to map the drive letter to</param>
”’ <param name=”DriveLetter”>The drive letter to use</param>
”’ <param name=”Persistent”>False to have this drive removed when the user logs off. True to have the drive remembered.
”’ This option is the equivelant of the Reconnect At Logon checkbox shown when mapping a drive in Windows Exporer</param>
”’ <param name=”ConnectionUsername”>The username to use for the connection – optional</param>
”’ <param name=”ConnectionPassword”>The password to use for the connection – optional</param>
Public Shared Sub MapNetworkDrive(ByVal UncPath As String, ByVal DriveLetter As Char, ByVal Persistent As Boolean, Optional ByVal ConnectionUsername As String = Nothing, Optional ByVal ConnectionPassword As String = Nothing)
If String.IsNullOrEmpty(UncPath) Then
Throw New ArgumentException(“No UNC path specified”, “UncPath”)
End If
Dim DriveInfo As New NETRESOURCE
With DriveInfo
.dwType = RESOURCETYPE_DISK
.lpLocalName = DriveLetter & “:”
.lpRemoteName = UncPath
End With
Dim flags As UInteger = 0
If Persistent Then
flags = &H1
End If
Dim Result As UInteger = WNetAddConnection2(DriveInfo, ConnectionPassword, ConnectionUsername, flags)
If Not Result = NO_ERROR Then
Throw New System.ComponentModel.Win32Exception(CInt(Result))
End If
End Sub
So now you can just call my MapNetworkDrive method like so whenever you want to map a drive:
‘make it persistent (reconnect at logon)
MapNetworkDrive(“\\MyServer\SomeShareName”, “F”c, True)
‘Of course you should add some error handling too
I’ll make another blog post soon on how to delete existing mapped drives as well.
Wow, I have been trying to get other peoples code for this to work for days. Yours works like a charm.
Thanks a bunch.
No worries 🙂 glad it helped you out
Chris
Works like a charm. WooHoo. okay, now how do I disconnect the mapping? I need to be able to enter different servers and retrieve data from some text files. Thanks.
This is the source code from the RemoveNetworkDrive method in my Windows API class library (which you can download from this blog), hope it helps:
”’
”’
”’ The drive letter to delete, must be a network drive
”’ Force the drive to be deleted even if files are still open on this drive
Public Shared Sub RemoveNetworkDrive(ByVal DriveLetter As Char, ByVal Force As Boolean)
Dim Result As UInteger = ApiDefinitions.WNetCancelConnection(DriveLetter & “:”, ApiDefinitions.CONNECT_UPDATE_PROFILE, Force)
If Not Result = ApiDefinitions.NO_ERROR Then
Throw New System.ComponentModel.Win32Exception(CInt(Result))
End If
End Sub
I cannot find your source code for disconnecting a mapped network drive. Do I need to login?
Its in the comments on this same post, just look up 🙂
EDIT: Actually you even replied to the comment that contained it…
Oh and if you are just programmatically accessing shares on servers to get at some files and thats it then you should just access the files via the UNC path (the path that you map the network drive to) rather than bothering with mapping and unmapping a network drive
Actually, while trying to figure out the disconnect I came across this. Seems cleaner.
Public Declare Function WNetAddConnection2 Lib “mpr.dll” Alias “WNetAddConnection2A” _
( ByRef lpNetResource As NETRESOURCE, ByVal lpPassword As String, _
ByVal lpUserName As String, ByVal dwFlags As Integer) As Integer
Public Declare Function WNetCancelConnection2 Lib “mpr” Alias “WNetCancelConnection2A” _
(ByVal lpName As String, ByVal dwFlags As Integer, ByVal fForce As Integer) As Integer
_
Public Structure NETRESOURCE
Public dwScope As Integer
Public dwType As Integer
Public dwDisplayType As Integer
Public dwUsage As Integer
Public lpLocalName As String
Public lpRemoteName As String
Public lpComment As String
Public lpProvider As String
End Structure
Public Const ForceDisconnect As Integer = 1
Public Const RESOURCETYPE_DISK As Long = &H1
Public Function MapDrive(ByVal DriveLetter As String, ByVal UNCPath As String) As Boolean
Dim nr As NETRESOURCE
Dim strUsername As String
Dim strPassword As String
nr = New NETRESOURCE
nr.lpRemoteName = UNCPath
nr.lpLocalName = DriveLetter & “:”
strUsername = Nothing ‘(add parameters to pass this if necessary)
strPassword = Nothing ‘(add parameters to pass this if necessary)
nr.dwType = RESOURCETYPE_DISK
Dim result As Integer
result = WNetAddConnection2(nr, strPassword, strUsername, 0)
If result = 0 Then
Return True
Else
Return False
End If
End Function
Public Function UnMapDrive(ByVal DriveLetter As String) As Boolean
Dim rc As Integer
rc = WNetCancelConnection2(DriveLetter & “:”, 0, ForceDisconnect)
If rc = 0 Then
Return True
Else
Return False
End If
End Function
How is that any ‘cleaner’ than my code?
i have an application that loads as a service. can/will your code function in that scenario? i know there are a lot of issues around the credentials especially when crossing domain and server to server.
You added a comment above regarding just using UNC versus mapping a drive letter… how would that be done (is the variable value optional)?
I’m not sure I’m afraid – you would have to test it
I am running Windows 7. The code you have documented here runs without a error. However, the network share does not appear in ‘My Computer’ nor is it visible via the CMD prompt using ‘net use’
Any ideas?
BTW, Many thanks for publishing this code.
Do you get the same issue if you tell it to be persistent (pass in True for the last parameter) or does it appear when you do that?
Same here, it is weird because in my IDE (VS2010) it works fine in testing, but the moment I deploy the code it doesn’t work as expected (also, I am integrating this in an aspx page on a webserver in my company’s domain) Any ideas?
Sorry I have no idea about web development. If it was a desktop app and running on Vista/Windows 7 then I would say its probably a UAC issue (mapped drives don’t seem to carry over into your normal logon session if mapped from an app running “As Administrator”) but no idea how this works in a web environment I’m afraid
The app I am using your code in is run with ‘admin’ rights. Afthough the function passes back true, I do not see the drives mapped in my computer OR using net use from the cmmand prompt.
However, when I run as a normal user (not ‘run as admin’) the shares appear as expected. Wierd.
When you do Run As Admin do you have to enter an admin user’s credentials or do you just have to click Yes on the UAC prompt?
Program A is an app used to change the IP address of the ethernet adapter. So it needs to be run as admin just click yes at UAC prompt. I want to add the ability to map shares from this app too. However when run as admin the shares do not appear in ‘my computer’. After doing some reading it is because of the LUID. I am not aware of a way to start a 2nd process with lower priviledges in order to work around this problem.
Try running you app and admin and then mapping a share. It doesn’t work.
Hi,
Does this check to see if there is already a mapping in place and if not any idea’s how we check?
Kind regards
Mike
Just call IO.DriveInfo.GetDrives and loop through the results checking to see if the DriveType property is Network. If you want to see the UNC path that any of those existing network drives map to, you can use the NativeFileSystem.GetUncPathFromNetworkDrive method from my Windows API library (which you can download here: https://cjwdev.wordpress.com/2011/06/12/net-windows-api-library-cjwdev-windowsapi-vesion-2-2-released/)
Thanks for the awesome code!
For the vista/win7/win8 issue of different shares for the standard vs elevated user you can add this registry key to make any shares added apply to both. After adding the key you’ll need to disconnect and reconnect the drive to see an effect.
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
“EnableLinkedConnections”=dword:00000001