Não é possível mapear unidade de rede utilizando .Net / WNetAddConnection2W (Erro 67 - O nome da rede não pode ser encontrado)?

StackOverflow https://stackoverflow.com/questions/1232937

  •  22-07-2019
  •  | 
  •  

Pergunta

Boa tarde,

Eu estou usando o código abaixo para mapear uma unidade de rede em um aplicativo .NET .. bem mais precisamente, tentar fazê-lo. Sempre que eu faço fazer a chamada para WNetAddConnection2W, eu recebo um Win32Exception com o código de erro 67 ... o que se traduz, basicamente, em 'O nome da rede não pode ser encontrado' .. mas eu realmente agora sei por que ... quaisquer ideias quando esse erro poderia vir de?

Aqui está a classe NetworkMapper:

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
    }
}

Basicamente o que eu faço é a seguinte:

var networkDriveMapper = new Utilities.NetworkDriveMapper
                {
                    PromptForCredentials = false,
                    Persistent = true,
                    FindNextFreeDrive = false,
                    Force = false
                };

                networkDriveMapper.MapDrive("B:", @"\\server\share", false);

E então o mapDrive private void (string username, password string) método lança o Win32Exception com o código de erro 67 ...

Qualquer outra pessoa usando o a mpr.dll / WNetAddConnection2W entrypoint? E / ou sabe como contornar / corrigir este erro?

Cheers e graças, -Jörg

Atualizar : Originalmente, eu tinha um erro 1204 ( 'O nome do provedor de rede especificado é inválido') .. mas as 2 respostas até agora meio que me ajudou um pouco, mas não resolvido todo o problema de não ser capaz de mapear unidades de rede corretamente ...

Foi útil?

Solução

Acredito que sua estrutura NETRESOURCE é na ordem errada (vs. kb173011 )

    [StructLayout(LayoutKind.Sequential)]
    private struct netResource
    {
        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;
    }

Outras dicas

Para resolver o código de erro 1200 eu mudei a definição de WNetAddConnection2A para WNetAddConnection2W, mudar o ponto de entrada e também definir o charset para Unicode.

Eu não consegui ver a unidade mapeada no meu computador, mas quando eu usei a função de desconectar unidades mapeadas, a unidade estava na lista.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top