我有一个共享网络文件夹\\some.domain.net\Shared
,它包含对不同用户具有不同权限的多个共享子文件夹。我希望打开来自同一个Windows帐户的多个子文件夹的连接,但是使用不同的凭据--这是否可能不需要先断开到同一个共享的其他连接?
确切地说:在C#方法中,我尝试使用WNetUseConnection()
(p/invoke)以以下方式连接到特定的子文件夹:
ConnectToSharedFolder("\\some.domain.net\Shared\Subfolder1", user, password); // calls WNetUseConnection() internally
只要在连接到子文件夹的根文件夹(即\\some.domain.net\Shared
)或另一个共享子文件夹(或一般情况下,\\some.domain.net
上的任何文件夹)都没有建立连接到子文件夹的连接,就可以正常工作。也就是说,在连接到子文件夹之前,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
之间的区别。但是,如果出现错误1219,则尝试取消连接。
WNetCancelConnection2(@"\\some.domain.net\Shared\Subfolder1", 0, true); // error 2250
结果错误2250:
This network connection does not exist.
因此,我似乎首先需要手动取消到\\some.domain.net\
的所有打开的连接,因为看起来一次只能打开一个连接,但是,由于另一个进程可能同时访问已连接的共享文件夹,这似乎不太可靠。
是否有方法解决此问题并与同一台远程计算机上的多个共享文件夹进行活动连接?
发布于 2016-01-30 13:35:41
这是一个古老的话题,但非常实际和有问题。我试着把它弄清楚,因为我已经处理了这些问题好几年了。
首先,Windows不允许您连接到一个网络共享中的多个子文件夹。
第二: Windows是通过远程名称标识连接。因此,您可以通过不同的名称建立到同一服务器的多个连接,例如: www.serverName.com和123.123.123.123 (通过ip) --这些连接将被视为具有不同凭据的单独连接。
因此,我的解决方案是向我的服务器添加别名IP。我已经为我的服务器创建了10个别名,我的应用程序从列表中获取了第一个IP,然后如果它被阻止,那么接下来等等。
这个解决方案不是很好,但有效。问题是当您无法访问服务器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将记住已安装的驱动器,并在计算机重新启动后尝试连接这些驱动器,从而导致错误:无法连接某些驱动器:)
发布于 2014-01-07 17:03:14
好的- 这是问题所在。它给出了几个建议的解决方案;对我来说,这两个方案听起来都有点粗糙,但对您来说可能还可以。听起来,这种行为是故意的(可能是出于安全考虑)。
干杯-
发布于 2017-01-19 09:27:40
我希望共享用于错误代码1219的解决方案,同时使用WNetCancelConnection2()
将驱动器映射到共享路径,尽管这是一个不同的函数调用,但我认为这种方法可能会解决。
首先,您需要确保您的计算机是如何组织在一个网络中。
(如果它在域中:)
您的用户名应该是DomainName[UserName],有时您可以简单地使用UserName。
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,那么只需更改登录,就像使用特定的用户凭据一样
https://stackoverflow.com/questions/20976349
复制相似问题