这是一个古老的话题,但非常实际且有问题。我会试着解释一下,因为我这几年一直在处理这样的问题。
首先:
Windows 不允许您连接到一个网络共享中的多个子文件夹。
其次:
Windows 正在通过远程名称识别连接。
因此,您可以使用不同的名称与同一服务器建立多个连接,例如:
www.serverName.com 和 123.123.123.123(通过 ip) - 这些将被视为具有不同凭据的单独连接。
所以我的解决方案是将别名 IP 添加到我的服务器。我已经为我的服务器创建了 10 个别名,我的应用程序从列表中获取第一个 IP,然后如果它被阻止,那么接下来等等。
这个解决方案不是很好,但很有效。问题是当您无权访问服务器 IP 时。然后怎样呢?看下一点:
最后:
然后唯一的解决方案是在使用指定的网络共享后断开用户连接,这里开始所有其他问题......连接被许多阻止其他人登录的东西使用。例如,有人从网络共享打开 Word 文档 - 现在您无法断开连接!但是 net.exe 不会显示任何连接!当您在一段时间(大约一分钟)后关闭 Word 文档时,另一个 BUT 连接将自动关闭并允许新连接。
我现在的工作是查找哪些系统元素正在阻止连接并通知用户:关闭 Word,您将能够登录。
希望它可以做到。
PS。我正在使用 WinApi,因为 net.exe 的运行速度要慢得多,并且提供的选项更少。
如果有人需要源代码:
public ServerWinProcessor(string serverAddress)
: base(serverAddress)
{
}
[DllImport("mpr.dll")]
public static extern int WNetAddConnection2(ref NETRESOURCE netResource, string password, string username, uint flags);
[DllImport("mpr.dll")]
public static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);
[DllImport("mpr.dll")]
public static extern int WNetOpenEnum(int dwScope, int dwType, int dwUsage, NETRESOURCE2 lpNetResource, out IntPtr lphEnum);
[DllImport("Mpr.dll", EntryPoint = "WNetCloseEnum", CallingConvention = CallingConvention.Winapi)]
private static extern int WNetCloseEnum(IntPtr hEnum);
[DllImport("mpr.dll")]
private static extern int WNetEnumResource(IntPtr hEnum, ref uint lpcCount, IntPtr buffer, ref uint lpBufferSize);
public OperationResult LoginToNetworkShare(string userName, string password, string shareName)
{
return LoginToNetworkShare(userName, password, shareName, null);
}
public OperationResult LoginToNetworkShare(string userName, string password, string shareName, string shareDrive)
{
NETRESOURCE nr = new NETRESOURCE();
nr.dwType = RESOURCETYPE_DISK;
nr.lpLocalName = shareDrive;
nr.lpRemoteName = @"\\" + ServerAddress + @"\" + shareName;
int result = WNetAddConnection2(ref nr, password, userName, CONNECT_TEMPORARY);
return new OperationResult(result);
}
public Task<OperationResult> LoginToNetworkShareAsync(string userName, string password, string shareName, string shareDrive)
{
return Task.Factory.StartNew(() =>
{
return LoginToNetworkShare(userName, password, shareName, shareDrive);
});
}
public OperationResult LogoutFromNetworkSharePath(string sharePath)
{
int result = WNetCancelConnection2(sharePath, CONNECT_UPDATE_PROFILE, true);
return new OperationResult(result);
}
public OperationResult LogoutFromNetworkShare(string shareName)
{
int result = WNetCancelConnection2(@"\\" + ServerAddress + @"\" + shareName, CONNECT_UPDATE_PROFILE, true);
return new OperationResult(result);
}
public OperationResult LogoutFromNetworkShareDrive(string driveLetter)
{
int result = WNetCancelConnection2(driveLetter, CONNECT_UPDATE_PROFILE, true);
return new OperationResult(result);
}
private ArrayList EnumerateServers(NETRESOURCE2 pRsrc, int scope, int type, int usage, ResourceDisplayType displayType)
{
ArrayList netData = new ArrayList();
ArrayList aData = new ArrayList();
uint bufferSize = 16384;
IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize);
IntPtr handle = IntPtr.Zero;
int result;
uint cEntries = 1;
result = WNetOpenEnum(scope, type, usage, pRsrc, out handle);
if (result == NO_ERROR)
{
do
{
result = WNetEnumResource(handle, ref cEntries, buffer, ref bufferSize);
if (result == NO_ERROR)
{
Marshal.PtrToStructure(buffer, pRsrc);
if (string.IsNullOrWhiteSpace(pRsrc.lpLocalName) == false && pRsrc.lpRemoteName.Contains(ServerAddress))
if (aData.Contains(pRsrc.lpLocalName) == false)
{
aData.Add(pRsrc.lpLocalName);
netData.Add(new NetworkConnectionInfo(null, pRsrc.lpLocalName));
}
if (aData.Contains(pRsrc.lpRemoteName) == false && pRsrc.lpRemoteName.Contains(ServerAddress))
{
aData.Add(pRsrc.lpRemoteName);
netData.Add(new NetworkConnectionInfo(pRsrc.lpRemoteName, null));
}
if ((pRsrc.dwUsage & RESOURCEUSAGE_CONTAINER) == RESOURCEUSAGE_CONTAINER)
netData.AddRange(EnumerateServers(pRsrc, scope, type, usage, displayType));
}
else if (result != ERROR_NO_MORE_ITEMS)
break;
} while (result != ERROR_NO_MORE_ITEMS);
WNetCloseEnum(handle);
}
Marshal.FreeHGlobal(buffer);
return netData;
}
public void CloseAllConnections()
{
NETRESOURCE2 res = new NETRESOURCE2();
ArrayList aData = EnumerateServers(res, RESOURCE_CONNECTED, 0, 0, ResourceDisplayType.RESOURCEDISPLAYTYPE_NETWORK);
foreach (NetworkConnectionInfo item in aData)
{
if (item.IsRemoteOnly)
LogoutFromNetworkSharePath(item.RemoteName);
else
LogoutFromNetworkShareDrive(item.LocalName);
}
}
}
和其他类:
public static class Consts
{
public const int RESOURCETYPE_DISK = 0x1;
public const int CONNECT_TEMPORARY = 0x00000004;
public const int CONNECT_UPDATE_PROFILE = 0x00000001;
public const int RESOURCE_GLOBALNET = 0x00000002;
public const int RESOURCE_CONNECTED = 0x00000001;
public const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
public const int RESOURCEUSAGE_CONTAINER = 0x00000002;
public const int NO_ERROR = 0x000;
public const int ERROR_NOT_CONNECTED = 0x8CA;
public const int ERROR_LOGON_FAILURE = 0x52E;
public const int ERROR_SESSION_CREDENTIAL_CONFLICT = 0x4C3;
public const int ERROR_ALREADY_ASSIGNED = 0x55;
public const int ERROR_INVALID_PASSWORD = 0x56;
public const int ERROR_INVALID_PARAMETER = 0x57;
public const int ERROR_NO_MORE_ITEMS = 0x103;
//public const int ERROR_BAD_PROFILE = 0x4B6;
//public const int ERROR_CANNOT_OPEN_PROFILE = 0x4B5;
//public const int ERROR_DEVICE_IN_USE = 0x964;
//public const int ERROR_EXTENDED_ERROR = 0x4B8;
//public const int ERROR_OPEN_FILES = 0x961;
public enum ResourceDisplayType
{
RESOURCEDISPLAYTYPE_GENERIC,
RESOURCEDISPLAYTYPE_DOMAIN,
RESOURCEDISPLAYTYPE_SERVER,
RESOURCEDISPLAYTYPE_SHARE,
RESOURCEDISPLAYTYPE_FILE,
RESOURCEDISPLAYTYPE_GROUP,
RESOURCEDISPLAYTYPE_NETWORK,
RESOURCEDISPLAYTYPE_ROOT,
RESOURCEDISPLAYTYPE_SHAREADMIN,
RESOURCEDISPLAYTYPE_DIRECTORY,
RESOURCEDISPLAYTYPE_TREE,
RESOURCEDISPLAYTYPE_NDSCONTAINER
};
[StructLayout(LayoutKind.Sequential)]
public struct NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
public string lpLocalName;
public string lpRemoteName;
public string Comment;
public string lpProvider;
}
[StructLayout(LayoutKind.Sequential)]
public class NETRESOURCE2
{
public int dwScope = 0;
public int dwType = 0;
public ResourceDisplayType dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = null;
public string lpRemoteName = null;
public string lpComment = null;
public string lpProvider = null;
};
}
最后一个:
public class NetworkConnectionInfo
{
public string RemoteName { get; set; }
public string LocalName { get; set; }
public bool IsRemoteOnly { get; set; }
public NetworkConnectionInfo(string remoteName, string localName)
{
RemoteName = remoteName;
LocalName = localName;
if (string.IsNullOrWhiteSpace(localName))
IsRemoteOnly = true;
}
}
你不需要 OperationResult 它只是简单的错误容器,不需要。
基类 ServerProcessorBase 只包含一个字段 serverAddress。
重要提示:当您无法正确设置时,这会造成问题:CONNECT_TEMPORARY 选项。如果未设置,则 Windows 将记住已安装的驱动器,并在计算机重新启动后尝试连接它们导致错误:无法连接某些驱动器 :) 很烦 :)