簡體   English   中英

連接到遠程共享文件夾會導致“多個連接不允許”錯誤,但嘗試斷開連接會導致“連接不存在”

[英]Connecting to a remote shared folder results in “multiple connections not allowed” error, but trying to disconnect causes “connection does not exist”

我有一個共享網絡文件夾\\\\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上的任何文件夾)的連接,這都可以\\\\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區別。 但是,嘗試在使用錯誤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添加到我的服務器。 我已經創建了10個服務器的別名,我的應用程序從列表中獲取了第一個IP然后是否被阻止然后是下一個等等。

這個解決方案不是很好但是有效。 問題是當你沒有訪問服務器IP時。 然后怎樣呢? 見下一點:

最后:然后唯一的解決方案是在使用指定的網絡共享后斷開用戶,這里開始所有其他問題...連接被許多阻止他人登錄的東西使用。例如有人從網絡共享打開Word文檔 - 現在你不能斷開! 但是net.exe不會顯示任何連接! 另一個但是在一段時間(大約一分鍾)連接后關閉Word文檔將自動關閉並允許新連接。

我的工作現在指向查找whitch系統元素阻止連接並通知用戶:關閉Word,您將能夠登錄。 有意思的是,它可以完成。

PS。 我正在使用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 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()映射驅動器與共享路徑,即使這是一個不同的函數調用,我覺得這種方法可能會解決。

首先,您需要確保計算機在網絡中的組織方式。

如果它在域中:

您的用戶名應為[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);

注意 :僅當傳遞的用戶名是當前登錄用戶名時,Workgroup解決方案才有效。 如果您使用的是Windows服務,則只需使用特定的用戶憑據更改登錄

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM