无法使用.Net / WNetAddConnection2W映射网络驱动器(错误67 - 找不到网络名称)?

时间:2009-08-05 12:27:21

标签: .net dllimport

下午好,

我使用下面的代码在.net应用程序中映射网络驱动器..更确切地说,尝试这样做。每当我调用WNetAddConnection2W时,我会得到一个带有错误代码67的win32exception ...它基本上转换为'无法找到网络名称'..但我现在真的知道为什么......任何想法出现此错误可能来自?

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

基本上我所做的是以下内容:

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

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

然后 private void mapDrive(string username,string password)方法抛出 Win32Exception ,错误代码 67 ... < / p>

其他人使用mpr.dll / WNetAddConnection2W入口点?和/或知道如何规避/修复此错误?

干杯谢谢, -Jörg

更新:我原来有错误1204('指定的网络提供商名称无效')..但到目前为止2个答案有点帮助了我,但没有解决整个问题无法正确映射网络驱动器...

2 个答案:

答案 0 :(得分:0)

我相信您的netResource结构的顺序错误(与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;
    }

答案 1 :(得分:0)

要解决错误代码1200,我将WNetAddConnection2A的定义更改为WNetAddConnection2W,也更改了入口点并将字符集设置为Unicode。

我没有看到“我的电脑”中的映射驱动器,但是当我使用您的功能断开映射驱动器时,驱动器位于列表中。