Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 连接到远程共享文件夹会导致“0”;“不允许多个连接”;错误,但尝试断开原因“;“连接不存在”;_C#_Windows_Winapi_Remote Access_Network Share - Fatal编程技术网

C# 连接到远程共享文件夹会导致“0”;“不允许多个连接”;错误,但尝试断开原因“;“连接不存在”;

C# 连接到远程共享文件夹会导致“0”;“不允许多个连接”;错误,但尝试断开原因“;“连接不存在”;,c#,windows,winapi,remote-access,network-share,C#,Windows,Winapi,Remote Access,Network Share,我有一个共享网络文件夹\\some.domain.net\shared,其中包含多个共享子文件夹,对不同的用户具有不同的权限。我希望从同一个Windows帐户打开到多个子文件夹的连接,但使用不同的凭据-这是否可能,而不必先断开到同一共享的其他连接 确切地说:在C#方法中,我尝试使用WNetUseConnection()(p/invoke)以以下方式连接到特定的子文件夹: ConnectToSharedFolder("\\some.domain.net\Shared\Subfolder1", us

我有一个共享网络文件夹
\\some.domain.net\shared
,其中包含多个共享子文件夹,对不同的用户具有不同的权限。我希望从同一个Windows帐户打开到多个子文件夹的连接,但使用不同的凭据-这是否可能,而不必先断开到同一共享的其他连接

确切地说:在C#方法中,我尝试使用
WNetUseConnection()
(p/invoke)以以下方式连接到特定的子文件夹:

ConnectToSharedFolder("\\some.domain.net\Shared\Subfolder1", user, password); // calls WNetUseConnection() internally 
只要在调用连接到子文件夹的
WNetUseConnection()
时,尚未建立到根文件夹(即
\\some.domain.net\Shared
)或另一个共享子文件夹(或者,通常是到
\\some.domain.net
上的任何文件夹)的连接,此操作就可以正常工作。也就是说,在连接到子文件夹之前,请考虑<代码> NET使用< /代码>返回:

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\
的连接,因为看起来一次只能打开一个连接-但是,这似乎不是很可靠,因为另一个进程可能同时访问连接的共享文件夹

是否有办法解决此问题,并与同一远程计算机上的多个共享文件夹建立活动连接?

确定-这就是问题所在。它给出了几个建议的解决方案;对我来说这两个听起来都有点像男人,但对你来说可能没问题。听起来这种行为是出于设计(可能是出于安全考虑)


干杯-

这是一个古老的话题,但非常现实和有问题。我会尽力解释一下,因为我已经处理这些问题好几年了

首先: Windows不允许您连接到一个网络共享中的多个子文件夹

第二点: Windows正在通过远程名称标识连接。 因此,您可以使用不同的名称与同一服务器建立多个连接,如: www.serverName.com和123.123.123.123(通过ip)-这些将被视为具有不同凭据的单独连接

因此,我的解决方案是将别名IP添加到我的服务器。我已经为我的服务器创建了十个别名,我的应用程序从列表中获取了第一个IP,然后如果它被阻止了,然后是下一个,等等

这个解决方案不是很好,但很有效。问题是当您无法访问服务器IP时。然后呢?见下一点:

最后: 然后,唯一的解决方案是在使用指定的网络共享后断开用户连接,并在这里开始所有其他问题。。。许多东西使用连接来阻止其他人登录。例如,有人从网络共享打开Word文档-现在您无法断开连接!但是net.exe不会显示任何连接!另一个问题是,当您在一段时间(大约一分钟)后关闭Word文档时,连接将自动关闭,并允许新的连接

我现在的工作是找到which系统元素正在阻止连接,并通知用户:关闭Word,您就可以登录了。 希望可以做到

另外,我正在使用WinApi cos 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 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\u临时选项。如果未设置,windows将记住已安装的驱动器,并在计算机重新启动资源后尝试连接这些驱动器,导致错误:无法连接某些驱动器:)异常:)

我想在使用
WNetCancelConnection2()映射具有共享路径的驱动器时,共享用于错误代码1219的解决方案
尽管这是一个不同的函数调用,但我觉得这种方法可以解决问题

首先,你需要确定你的计算机在网络中是如何组织的

如果在域中:

您的用户名应该是[DomainName]\[username],有时您可以简单地使用[username]

var userName = string.IsNullOrEmpty(credentials.Domain) ? credentials.UserName : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);
如果在工作组中:

您的用户名应为[ServerName]\[username],切勿使用[username]

var userName = string.IsNullOrEmpty(credentials.Domain) ? credentials.UserName : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);
这里ServerName是共享路径的主机名

var userName = string.Format(@"{0}\{1}", serverMachineName, credentials.UserName);

注意:仅当传递的用户名是当前登录用户名时,工作组解决方案才有效。如果您使用的是Windows服务,那么只需使用特定的用户凭据更改登录身份即可

这确实非常烦人,而且Microsoft早就应该解决这一问题了

然而,这种不好的特性并不总是出现。我已经能够在同一台服务器上映射三个不同的子目录,使用来自同一个Windows用户(Windows 10/64位Pro)的不同远程凭据,并且它工作了多年,每次启动时都会出现。我使用了文件资源管理器的设备映射功能。当它工作时,它将工作,但一旦发生更改,例如其中一个远程用户的密码更改,则此问题也可能发生。当Windows由于密码不正确而无法映射特定驱动器时,也会出现此错误,然后它会获取下一个远程用户凭据并尝试设备映射。如果服务器已确认此用户,则它