我有一个共享的networking文件夹\\some.domain.net\Shared
包含不同的用户具有不同权限的多个共享子文件夹。 我希望从同一个Windows帐户打开连接到多个子文件夹,但使用不同的凭据 – 这是可能的,而不必断开其他连接到同一个共享第一?
确切地说:在C#方法中,我尝试使用WNetUseConnection()
(p / invoke)以如下方式连接到特定的子文件夹:
ConnectToSharedFolder("\\some.domain.net\Shared\Subfolder1", user, password); // calls WNetUseConnection() internally
只要没有build立到任一根文件夹(即\\some.domain.net\Shared
)或另一个共享子文件夹(或者一般来说, \\some.domain.net
上的任何文件夹)的连接,此工作\\some.domain.net
)在调用WNetUseConnection()
的时候连接到一个子文件夹 。 即,考虑到在连接到子文件夹之前, net use
返回:
Status Local Remote ------------------------------------------------ OK \\some.domain.net\Shared
现在我还想连接到共享子文件夹\\some.domain.net\Shared\Subfolder1
,如本文顶部所示。 这将导致Windows错误1219:
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
因此,Windows(Server 2008 R2)似乎无法识别\\some.domain.net\Shared
和\\some.domain.net\Shared\Subfolder1
区别,尽pipe提供了不同的访问凭据。 但是,试图通过使用错误1219的情况下取消连接
WNetCancelConnection2(@"\\some.domain.net\Shared\Subfolder1", 0, true); // error 2250
导致错误2250:
This network connection does not exist.
因此,我似乎首先需要手动取消所有打开的连接到\\some.domain.net\
因为它看起来只有一个可以打开一次 – 但是,这似乎不是很强大,因为另一个进程可能是同时访问连接的共享文件夹。
有没有办法解决这个问题,并有活动连接到同一个远程机器上的多个共享文件夹?
这是一个老话题,但非常实际和有问题。 我会试着说一些,因为几年来我一直在处理这样的问题。
首先:Windows不允许您连接到一个网络共享中的多个子文件夹。
其次,Windows正在通过远程名称识别连接。 因此,您可以建立多个不同名称的连接到不同的名称,如:www.serwerName.com和123.123.123.123(通过ip) – 这些将被视为具有不同证书的独立连接。
所以我的解决方案是添加别名IP到我的服务器。 我已经创建了10个serwer别名,我的应用程序从列表中取得第一个IP,然后如果它被阻塞,然后下一个等。
这个解决方案不是很好,但它的工作原理。 问题是当你不能访问serwer IP。 然后怎样呢? 看下一点:
最后一点:那么唯一的解决办法是断开用户使用指定的网络共享后,在这里开始所有其他问题…连接被阻碍他人登录许多事情。例如,某人从网络共享打开Word文档 – 现在你不能断开连接! 但net.exe不会显示任何连接! 另一个,但是当你关闭Word文档一段时间后(约一分钟)连接将自动关闭,并将允许新的连接。
我的工作是现在指导找到系统元素阻止连接,并通知用户:关闭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将记住安装的驱动器,并尝试将它们连接后,重新启动计算机导致错误:无法连接一些驱动器:) anoying 🙂
好的 – 这是问题所在。 它提供了几个建议的解决方案; 对我来说听起来都有些笨拙,但是对你来说可能还行。 这听起来像这样的行为是设计(可能是一个安全考虑)。
干杯 –
我想分享我使用错误代码1219的解决方案,同时使用WNetCancelConnection2()
映射驱动器与共享路径,即使这是一个不同的函数调用,我感觉这种方法可能会解决。
首先,你需要确定你的电脑是如何在网络中组织的。
如果在域中:
您的用户名应该是[域名] \ [用户名],有时您可以简单地使用[用户名]。
var userName = string.IsNullOrEmpty(credentials.Domain) ? credentials.UserName : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);
如果在工作组中:
您的用户名应该是[serverName] \ [UserName],从不使用[UserName]。
这里的serverName是你的共享路径的主机名。
var userName = string.Format(@"{0}\{1}", serverMachineName, credentials.UserName);
注意 :只有当传递的用户名是当前登录用户名时,工作组解决方案才有效。 如果您正在使用Windows服务,那么就像更改特定的用户凭证一样更改日志