Good afternoon,
I am using the code below to map a network drive in a .net application.. well more precisely, try to do it. Whenever I do make the call to WNetAddConnection2W, I get a win32exception with the error code 67... which basically translates into 'The network name cannot be found'.. but I really do now know why... any ideas where this error might come from?
Here's the NetworkMapper class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Libraries.Utilities
{
/// <summary>
///
/// </summary>
public class NetworkDriveMapper
{
#region Public variables and propertys
private string _localDrive = null;
private string _shareName = "";
/// <summary>
/// Initializes a new instance of the <see cref="NetworkDriveMapper"/> class.
/// </summary>
public NetworkDriveMapper()
{
FindNextFreeDrive = false;
PromptForCredentials = false;
Force = false;
Persistent = false;
SaveCredentials = false;
}
/// <summary>
/// Option to save credentials on reconnection...
/// </summary>
public bool SaveCredentials { get; set; }
/// <summary>
/// Option to reconnect drive after log off / reboot...
/// </summary>
public bool Persistent { get; set; }
/// <summary>
/// Option to force connection if drive is already mapped...
/// or force disconnection if network path is not responding...
/// </summary>
public bool Force { get; set; }
/// <summary>
/// Option to prompt for user credintals when mapping a drive
/// </summary>
public bool PromptForCredentials { get; set; }
/// <summary>
/// Option to auto select the 'lpLocalName' property to next free driver letter when mapping a network drive
/// </summary>
public bool FindNextFreeDrive { get; set; }
/// <summary>
/// Drive to be used in mapping / unmapping (eg. 's:')
/// </summary>
public string LocalDrive
{
get { return _localDrive; }
set
{
if (string.IsNullOrEmpty(value))
{
_localDrive = null;
}
else
{
_localDrive = value.Substring(0, 1) + ":";
}
}
}
/// <summary>
/// Share address to map drive to. (eg. '\\Computer\C$')
/// </summary>
public string ShareName
{
get { return _shareName; }
set { _shareName = value; }
}
/// <summary>
/// Returns a string array of currently mapped network drives
/// </summary>
public string[] MappedDrives
{
get
{
var driveArray = new List<string>();
foreach (string driveLetter in Directory.GetLogicalDrives())
{
if (PathIsNetworkPath(driveLetter))
{
driveArray.Add(driveLetter);
}
}
return (driveArray.ToArray());
}
}
#endregion
#region Public functions
/// <summary>
/// Map network drive
/// </summary>
public void MapDrive()
{
mapDrive(null, null);
}
/// <summary>
/// Map network drive (using supplied Username and Password)
/// </summary>
/// <param name="username">Username passed for permissions / credintals ('Username' may be passed as null, to map using only a password)</param>
/// <param name="password">Password passed for permissions / credintals</param>
public void MapDrive(string username, string password)
{
mapDrive(username, password);
}
/// <summary>
/// Set common propertys, then map the network drive
/// </summary>
/// <param name="localDrive">lpLocalName to use for connection</param>
/// <param name="shareName">Share name for the connection (eg. '\\Computer\Share')</param>
/// <param name="force">Option to force dis/connection</param>
public void MapDrive(string localDrive, string shareName, bool force)
{
_localDrive = localDrive;
_shareName = shareName;
Force = force;
mapDrive(null, null);
}
/// <summary>
/// Set common propertys, then map the network drive
/// </summary>
/// <param name="localDrive">Password passed for permissions / credintals</param>
/// <param name="force">Option to force dis/connection</param>
public void MapDrive(string localDrive, bool force)
{
_localDrive = localDrive;
Force = force;
mapDrive(null, null);
}
/// <summary>
/// Unmap network drive
/// </summary>
public void UnMapDrive()
{
unMapDrive();
}
/// <summary>
/// Unmap network drive
/// </summary>
public void UnMapDrive(string localDrive)
{
_localDrive = localDrive;
unMapDrive();
}
/// <summary>
/// Unmap network drive
/// </summary>
public void UnMapDrive(string localDrive, bool force)
{
_localDrive = localDrive;
Force = force;
unMapDrive();
}
/// <summary>
/// Check / restore persistent network drive
/// </summary>
public void RestoreDrives()
{
restoreDrive(null);
}
/// <summary>
/// Check / restore persistent network drive
/// </summary>
public void RestoreDrive(string localDrive)
{
restoreDrive(localDrive);
}
/// <summary>
/// Display windows dialog for mapping a network drive (using Desktop as parent form)
/// </summary>
public void ShowConnectDialog()
{
displayDialog(IntPtr.Zero, 1);
}
/// <summary>
/// Display windows dialog for mapping a network drive
/// </summary>
/// <param name="parentFormHandle">Form used as a parent for the dialog</param>
public void ShowConnectDialog(IntPtr parentFormHandle)
{
displayDialog(parentFormHandle, 1);
}
/// <summary>
/// Display windows dialog for disconnecting a network drive (using Desktop as parent form)
/// </summary>
public void ShowDisconnectDialog()
{
displayDialog(IntPtr.Zero, 2);
}
/// <summary>
/// Display windows dialog for disconnecting a network drive
/// </summary>
/// <param name="parentFormHandle">Form used as a parent for the dialog</param>
public void ShowDisconnectDialog(IntPtr parentFormHandle)
{
displayDialog(parentFormHandle, 2);
}
/// <summary>
/// Returns the share name of a connected network drive
/// </summary>
/// <param name="localDrive">Drive name (eg. 'X:')</param>
/// <returns>Share name (eg. \\computer\share)</returns>
public string GetMappedShareName(string localDrive)
{
// collect and clean the passed lpLocalName param
if (localDrive == null || localDrive.Length == 0)
throw new Exception("Invalid 'localDrive' passed, 'localDrive' parameter cannot be 'empty'");
localDrive = localDrive.Substring(0, 1);
// call api to collect lpLocalName's share name
int i = 255;
var bSharename = new byte[i];
int iCallStatus = WNetGetConnection(localDrive + ":", bSharename, ref i);
switch (iCallStatus)
{
case 1201:
throw new Exception(
"Cannot collect 'ShareName', Passed 'DriveName' is valid but currently not connected (API: ERROR_CONNECTION_UNAVAIL)");
case 1208:
throw new Exception("API function 'WNetGetConnection' failed (API: ERROR_EXTENDED_ERROR:" +
iCallStatus.ToString() + ")");
case 1203:
case 1222:
throw new Exception(
"Cannot collect 'ShareName', No network connection found (API: ERROR_NO_NETWORK / ERROR_NO_NET_OR_BAD_PATH)");
case 2250:
throw new Exception(
"Invalid 'DriveName' passed, Drive is not a network drive (API: ERROR_NOT_CONNECTED)");
case 1200:
throw new Exception(
"Invalid / Malfored 'Drive Name' passed to 'GetShareName' function (API: ERROR_BAD_DEVICE)");
case 234:
throw new Exception("Invalid 'Buffer' length, buffer is too small (API: ERROR_MORE_DATA)");
}
// return collected share name
return Encoding.GetEncoding(1252).GetString(bSharename, 0, i).TrimEnd((char) 0);
}
/// <summary>
/// Returns true if passed drive is a network drive
/// </summary>
/// <param name="localDrive">Drive name (eg. 'X:')</param>
/// <returns>'True' if the passed drive is a mapped network drive</returns>
public bool IsNetworkDrive(string localDrive)
{
// collect and clean the passed lpLocalName param
if (localDrive == null || localDrive.Trim().Length == 0)
throw new Exception("Invalid 'localDrive' passed, 'localDrive' parameter cannot be 'empty'");
localDrive = localDrive.Substring(0, 1);
// return status of drive type
return PathIsNetworkPath(localDrive + ":");
}
#endregion
#region Private functions
// map network drive
private void mapDrive(string username, string password)
{
// if drive property is set to auto select, collect next free drive
if (FindNextFreeDrive)
{
_localDrive = nextFreeDrive();
if (string.IsNullOrEmpty(_localDrive))
throw new Exception("Could not find valid free drive name");
}
// create struct data to pass to the api function
var stNetRes = new netResource
{
dwScope = 2,
dwType = RESOURCETYPE_DISK,
dwDisplayType = 3,
dwUsage = 1,
lpRemoteName = _shareName,
lpLocalName = _localDrive
};
// prepare flags for drive mapping options
int iFlags = 0;
if (SaveCredentials)
iFlags += CONNECT_CMD_SAVECRED;
if (Persistent)
iFlags += CONNECT_UPDATE_PROFILE;
if (PromptForCredentials)
iFlags += CONNECT_INTERACTIVE + CONNECT_PROMPT;
// prepare username / password params
if (username != null && username.Length == 0)
username = null;
if (password != null && password.Length == 0)
password = null;
// if force, unmap ready for new connection
if (Force)
{
try
{
unMapDrive();
}
catch
{
}
}
// call and return
int i = WNetAddConnection2W(ref stNetRes, password, username, iFlags);
if (i > 0)
throw new Win32Exception(i);
}
// unmap network drive
private void unMapDrive()
{
// prep vars and call unmap
int iFlags = 0;
int iRet = 0;
// if persistent, set flag
if (Persistent)
{
iFlags += CONNECT_UPDATE_PROFILE;
}
// if local drive is null, unmap with use connection
if (_localDrive == null)
{
// unmap use connection, passing the share name, as local drive
iRet = WNetCancelConnection2W(_shareName, iFlags, Convert.ToInt32(Force));
}
else
{
// unmap drive
iRet = WNetCancelConnection2W(_localDrive, iFlags, Convert.ToInt32(Force));
}
// if errors, throw exception
if (iRet > 0)
throw new Win32Exception(iRet);
}
// check / restore a network drive
private void restoreDrive(string driveName)
{
// call restore and return
int i = WNetRestoreConnection(0, driveName);
// if error returned, throw
if (i > 0)
throw new Win32Exception(i);
}
// display windows dialog
private void displayDialog(IntPtr wndHandle, int dialogToShow)
{
// prep variables
int i = -1;
int iHandle = 0;
// get parent handle
if (wndHandle != IntPtr.Zero)
iHandle = wndHandle.ToInt32();
// choose dialog to show bassed on
if (dialogToShow == 1)
i = WNetConnectionDialog(iHandle, RESOURCETYPE_DISK);
else if (dialogToShow == 2)
i = WNetDisconnectDialog(iHandle, RESOURCETYPE_DISK);
// if error returned, throw
if (i > 0)
throw new Win32Exception(i);
}
// returns the next viable drive name to use for mapping
private string nextFreeDrive()
{
// loop from c to z and check that drive is free
string retValue = null;
for (int i = 67; i <= 90; i++)
{
if (GetDriveType(((char) i).ToString() + ":") == 1)
{
retValue = ((char) i).ToString() + ":";
break;
}
}
// return selected drive
return retValue;
}
#endregion
#region API functions / calls
private const int CONNECT_CMD_SAVECRED = 0x00001000;
private const int CONNECT_INTERACTIVE = 0x00000008;
private const int CONNECT_PROMPT = 0x00000010;
private const int CONNECT_UPDATE_PROFILE = 0x00000001;
private const int RESOURCETYPE_DISK = 1;
[DllImport("mpr.dll", EntryPoint = "WNetAddConnection2W", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int WNetAddConnection2W(ref netResource netRes, string password, string username,
int flags);
[DllImport("mpr.dll", EntryPoint = "WNetCancelConnection2W", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int WNetCancelConnection2W(string name, int flags, int force);
[DllImport("mpr.dll", EntryPoint = "WNetConnectionDialog", SetLastError = true)]
private static extern int WNetConnectionDialog(int hWnd, int type);
[DllImport("mpr.dll", EntryPoint = "WNetDisconnectDialog", SetLastError = true)]
private static extern int WNetDisconnectDialog(int hWnd, int type);
[DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int WNetRestoreConnection(int hWnd, string localDrive);
[DllImport("mpr.dll", EntryPoint = "WNetGetConnection", SetLastError = true)]
private static extern int WNetGetConnection(string localDrive, byte[] remoteName, ref int bufferLength);
[DllImport("shlwapi.dll", EntryPoint = "PathIsNetworkPath", SetLastError = true)]
private static extern bool PathIsNetworkPath(string localDrive);
[DllImport("kernel32.dll", EntryPoint = "GetDriveType", SetLastError = true)]
private static extern int GetDriveType(string localDrive);
[StructLayout(LayoutKind.Sequential)]
private struct netResource
{
#region Data Members (8)
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpLocalName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpRemoteName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpComment;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpProvider;
#endregion Data Members
}
// standard
#endregion
}
}
Basically what I do is the following:
var networkDriveMapper = new Utilities.NetworkDriveMapper
{
PromptForCredentials = false,
Persistent = true,
FindNextFreeDrive = false,
Force = false
};
networkDriveMapper.MapDrive("B:", @"\\server\share", false);
And then the private void mapDrive(string username, string password) method throws the Win32Exception with the error code 67 ...
Anyone else using the the mpr.dll / WNetAddConnection2W entrypoint? And/Or knows how to circumvent/fix this error?
Cheers and thanks, -Jörg
Update: I originally had an Error 1204 ('The specified network provider name is invalid').. but the 2 answers so far kinda helped me a little bit, but not solved the entire problem of not being able to map network drives properly...