|
-
May 29th, 2010, 01:58 PM
#1
Mapping a network drive
Unfortunately in the .NET Framework there is currently no way to create a network drive (aka mapped drive) so we have to use a Windows API to accomplish this, the WNetAddConnection2 API to be precise. So I thought I would provide the VB.NET definitions for the API function and the relevant structures/constants, along with a .NET method that you can use to wrap this API functionality to make it easier to use 
EDIT: The .NET wrapper for this function and loads of others are all in my .NET Windows API Library which you can download here to save copying and pasting API definitions etc into your projects: http://cjwdev.wordpress.com/2011/06/...-2-2-released/
First of all make sure you use this at the very top of your code:
vb Code:
Imports System.Runtime.InteropServices
then you can copy and paste these API definitions, which I've added comments to just in case you do want to use these directly instead of using the .NET method I will provide later in this post.
vb Code:
'Constants Public Const NO_ERROR As UInteger = 0 Public Const RESOURCETYPE_DISK As UInteger = 1 ''' <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 ''' <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
and here is the .NET method I wrote that makes using the API much simpler:
vb Code:
''' <summary> ''' 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 then when you want to map a network drive you can simply do this:
vb Code:
'This example maps the R drive to \\SomeServer\SomeShare Try MapNetworkDrive("\\SomeServer\SomeShare", "R"c, False) Catch ex As Exception MessageBox.Show("The network drive could not be mapped for the following reason: " & ex.Message) End Try
Last edited by chris128; Sep 11th, 2013 at 12:55 PM.
-
May 29th, 2010, 03:53 PM
#2
Re: Mapping a network drive
Oh and here's a bonus - how to delete an existing mapped drive 
API Definitions:
vb Code:
Public Const CONNECT_UPDATE_PROFILE As UInteger = 1
Public Const NO_ERROR As UInteger = 0
''' <summary>
''' Deletes a connection to a network resource
''' </summary>
''' <param name="lpName">The name of the connection to delete (e.g drive letter)</param>
''' <param name="dwFlags">If this is a persistent connection set to CONNECT_UPDATE_PROFILE to prevent from being mapped again at next logon</param>
''' <param name="fForce">Delete connection even if files from this resource are still open</param>
<DllImportAttribute("mpr.dll", EntryPoint:="WNetCancelConnectionW")> _
Public Shared Function WNetCancelConnection(<InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpName As String, ByVal dwFlags As UInteger, <MarshalAsAttribute(UnmanagedType.Bool)> ByVal fForce As Boolean) As UInteger
End Function
and my .NET method that wraps up the API functionality:
vb Code:
''' <summary>
''' Deletes an existing mapped network drive
''' </summary>
''' <param name="DriveLetter">The drive letter to delete, must be a network drive</param>
''' <param name="Force">Force the drive to be deleted even if files are still open on this drive</param>
Public Shared Sub RemoveNetworkDrive(ByVal DriveLetter As Char, ByVal Force As Boolean)
Dim Result As UInteger = WNetCancelConnection(DriveLetter & ":", CONNECT_UPDATE_PROFILE, Force)
If Not Result = NO_ERROR Then
Throw New System.ComponentModel.Win32Exception(CInt(Result))
End If
End Sub
So once you have copied and pasted all that into your project you can do this to delete a mapped drive:
vb Code:
'Deletes the F drive
'Throws an exception if F is not a network drive
RemoveNetworkDrive("F"c, True)
-
Jun 21st, 2010, 07:52 AM
#3
Lively Member
Re: Mapping a network drive
this has been very useful to me, thx ! =)
-
Jun 21st, 2010, 08:57 AM
#4
Re: Mapping a network drive
No worries, glad it was helpful
-
Jun 5th, 2013, 03:45 PM
#5
Junior Member
Re: Mapping a network drive
Sorry to revive... but I tried this out. The mapping works great so far but the delete is having issues.
First this line: Public Const NO_ERROR as UInteger = 0 is coming up as a problem saying its already declared in this class.
So I commented that out.
Then when I try to delete a mapped drive it will cause issues and lock up.
This is what I get.
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'blahblah::WNetCancelConnection' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Any help with this would be nice. If we can't figure it out im sure i can delete mapped drives some other way.
-
Jun 5th, 2013, 04:12 PM
#6
Re: Mapping a network drive
Well yeah the constant NO_ERROR is already declared in the first bit of code I posted on how to map a drive, so if you had already copied that and then copied the second part on removing a mapped drive as well then you'll obviously need to delete one of the NO_ERROR declarations.
As for the stack imbalance error, I looked in the latest version of my Windows API library and this is how I've got it declared now (notice the entry point is WNetCancelConnection2W not WNetCancelConnectionW like in my original post):
Code:
''' <summary>
''' Deletes a connection to a network resource
''' </summary>
''' <param name="lpName">The name of the connection to delete (e.g drive letter)</param>
''' <param name="dwFlags">If this is a persistent connection set to CONNECT_UPDATE_PROFILE to prevent from being mapped again at next logon</param>
''' <param name="fForce">Delete connection even if files from this resource are still open</param>
<DllImport("mpr.dll", EntryPoint:="WNetCancelConnection2W", SetLastError:=True)> _
Public Shared Function WNetCancelConnection(<InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpName As String, ByVal dwFlags As UInteger, <MarshalAsAttribute(UnmanagedType.Bool)> ByVal fForce As Boolean) As UInteger
End Function
and then to use it:
Code:
''' <summary>
''' Deletes an existing mapped network drive
''' </summary>
''' <param name="DriveLetter">The drive letter to delete, must be a network drive</param>
''' <param name="Force">Force the drive to be deleted even if files are still open on this drive</param>
Public Shared Sub RemoveNetworkDrive(ByVal DriveLetter As Char, ByVal Force As Boolean)
Dim Result As UInteger = WNetCancelConnection(DriveLetter & ":", CONNECT_UPDATE_PROFILE, Force)
If Not Result = NO_ERROR Then
Throw New System.ComponentModel.Win32Exception(CInt(Result))
End If
End Sub
If you want to skip having to define these things yourself etc you can just download the DLL I wrote that has all of these API definitions and .NET wrapper methods in it from my blog: http://blog.cjwdev.co.uk/2011/06/12/...-2-2-released/
Last edited by chris128; Jun 5th, 2013 at 04:26 PM.
-
Jun 6th, 2013, 07:58 AM
#7
Junior Member
Re: Mapping a network drive
Thank you, I took the old code out and put these both in.
Now i get another error but its only when the drive it expects to be mapped is not mapped.
I am guessing it has something to do with that no_error thing i commented out before.
It happens in the second chunk of code at the "throw new system.componentmode1.win32exception(CInt(result)) line.
The error says, A first chance exception of type 'system.componentmodel.win32exception' occurred.
It also says, This network connection does not exist.
-
Jun 6th, 2013, 10:02 AM
#8
Re: Mapping a network drive
No that's nothing to do with the NO_ERROR constant, that's an error that is being thrown for exactly the reason it says - you're trying to delete something that doesn't exist. You should loop through the current list of network drives and see if the drive exists before you try and delete it. See example below on how to loop through network drives:
Code:
For Each Drive As IO.DriveInfo In IO.DriveInfo.GetDrives()
If Drive.DriveType = IO.DriveType.Network Then
MessageBox.Show("Drive " & Drive.Name & " is a network drive")
End If
Next
If you wanted to check to see the actual UNC path that a network drive is mapped to you can use another function from my API library DLL that I linked to in the previous post like so:
Code:
MessageBox.Show(Cjwdev.WindowsApi.NativeFileSystem.GetUncPathFromNetworkDrive("H"c))
That example would show you the UNC path that the H drive is mapped to - obviously if you wanted to work with a different drive letter you'd replace H with whatever letter you wanted. The lower case "c" after the letter H is just converting it from a String to a Char as I made that function only accept a single letter as the parameter, so that there was no confusion over how the drive letter should be specified (as it people could think it should be "H" or "H:" or "H:\")
Last edited by chris128; Jun 6th, 2013 at 11:24 AM.
-
Jun 6th, 2013, 10:22 AM
#9
Junior Member
Re: Mapping a network drive
Ok so i just have to do a check it sounds like to make sure the drives i will be using are mapped before trying to delete.
I didnt know if your code already would counter that or not. Sounds good.
-
Sep 11th, 2013, 09:10 AM
#10
New Member
Re: Mapping a network drive
I am using your .NET Windows API library, and I am loving it. I ran into a problem, though, when I recently upgraded to Windows 7 64-bit. I get no errors when the MapNetworkDrive function runs, then my "If Drive Exists Then Start Explorer" statement fires and Explorer states the drive doesn't exist.
Is there a 64-bit version of your API library?
Thanks,
Carthax
-
Sep 11th, 2013, 12:24 PM
#11
Re: Mapping a network drive
 Originally Posted by Carthax
I am using your .NET Windows API library, and I am loving it. I ran into a problem, though, when I recently upgraded to Windows 7 64-bit. I get no errors when the MapNetworkDrive function runs, then my "If Drive Exists Then Start Explorer" statement fires and Explorer states the drive doesn't exist.
Is there a 64-bit version of your API library?
Thanks,
Carthax
Is your program running "As Administrator" (aka with elevated permissions) ? If so then any drives you map will not be visible to explorer because explorer is running with different permissions. There's a registry entry you can set to change this behaviour but that's how it works by default. Its nothing to do with 64/32 bit and every program has the same issue (try using the Net Use command from an elevated command prompt and you'll have the same issue)
-
Sep 11th, 2013, 12:40 PM
#12
New Member
Re: Mapping a network drive
 Originally Posted by chris128
Is your program running "As Administrator" (aka with elevated permissions) ? If so then any drives you map will not be visible to explorer because explorer is running with different permissions. There's a registry entry you can set to change this behaviour but that's how it works by default. Its nothing to do with 64/32 bit and every program has the same issue (try using the Net Use command from an elevated command prompt and you'll have the same issue)
Interesting. You're absolutely right. My code requires that the app run as administrator, and it does appear to map the drive as administrator (as expected), but it is running Explorer as a non-elevated user (completely unexpected). Let me see what I can do about that. ...and I wonder how many of the other folks asking about that on Google are having the same problem...? Thanks for the help!
-
Sep 11th, 2013, 12:47 PM
#13
Re: Mapping a network drive
It runs explorer non-elevated because you're not actually launching a new instance of explorer.exe (as that's a single instance application) - if you try to start explorer.exe when one instance of it is already running in your session then it just opens an explorer window from that existing explorer.exe process.
Oh and yes you'll find plenty of results on google about the mapped drives not persisting from elevated apps to non elevated apps
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|