2014-01-07 2 views
6

서로 다른 사용 권한을 가진 여러 공유 하위 폴더가 포함 된 공유 네트워크 폴더가 \\some.domain.net\Shared입니다. 동일한 Windows 계정의 여러 하위 폴더에 대한 연결을 열려고하지만 자격 증명이 다른 경우 - 먼저 동일한 공유에 대한 다른 연결을 끊지 않고이 작업을 수행 할 수 있습니까?원격 공유 폴더에 연결하면 "다중 연결이 허용되지 않음"오류가 발생하지만 연결을 끊으려는 경우 "연결이 없습니다"라는 메시지가 나타납니다.

것은 정확하게하려면

ConnectToSharedFolder("\\some.domain.net\Shared\Subfolder1", user, password); // calls WNetUseConnection() internally 

이만큼 아무런 관련이 없기 때문에 잘 작동 : C#을 방법, 나는의 방식으로 (/ P 호출) WNetUseConnection()를 사용하여 특정 하위 폴더에 연결을 시도 이미 하위 폴더에 연결 WNetUseConnection() 호출의 순간에 하나 루트 폴더 (예 : \\some.domain.net\Shared) 또는 (\\some.domain.net에있는 모든 폴더에 일반적이나,) 다른 공유 하위 폴더로 설립했다. 이 게시물의 상단에 그림과 같이

Status  Local  Remote 
------------------------------------------------ 
OK      \\some.domain.net\Shared 

지금 나는 또한 공유 하위 폴더 \\some.domain.net\Shared\Subfolder1에 연결하려면 : 즉, 하위 폴더에 net use 수익률을 연결하기 전에하는 것이 좋습니다. 이것은 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. 

그래서 윈도우 (서버 2008 R2)를 제공하는 다른 액세스 자격 증명에도 불구하고, \\some.domain.net\Shared\\some.domain.net\Shared\Subfolder1 사이의 차이를 인식하지 않는 것 같습니다. 그러나, 오류 2250에

WNetCancelConnection2(@"\\some.domain.net\Shared\Subfolder1", 0, true); // error 2250 

결과를 사용하여 오류 1219의 경우 연결을 취소하려고 :

This network connection does not exist. 

것은 그래서 내가 먼저 수동으로 \\some.domain.net\에 열려있는 모든 연결을 취소해야하는 것 같다 한 번에 하나만 열 수있는 것처럼 보입니다. 그러나 다른 프로세스가 연결된 공유 폴더에 동시에 액세스 할 수 있으므로이 방법은 매우 강력하지 않습니다.

이 문제를 해결하고 동일한 원격 컴퓨터의 여러 공유 폴더에 활성 연결이있는 방법이 있습니까?

+0

루트 공유에 연결 했으므로 해당 폴더의 하위 폴더에 연결하려고합니다. . 두 연결에 대해 서로 다른 자격 증명을 사용하고 있습니까? –

+0

@simonatrcl : 정확함, 예. 두 경우 모두 동일한 Windows 계정에서 연결을 설정하고 있지만 실제 지정된 자격 증명은 다릅니다. 루트 폴더의 경우 user1/password1이고 하위 폴더의 경우 user2/password2 - 이들은 'net use'에 전달하는 것과 동일한 자격 증명입니다 '. – w128

+0

조금 더 조사한 후에는 나에게 어떤 의미가 없지만 결함에 의한 것처럼 보일지라도 확실히 "디자인상의"문제 일 것 같습니다. – w128

답변

1

확인 - this이 문제입니다. 몇 가지 제안 된 솔루션을 제공합니다. 둘 다 나 한테 상냥하지 만 괜찮아. 이 동작은 의도적으로 설계된 것 (아마도 보안 고려 사항) 인 것처럼 들립니다.

환호 -

+0

감사합니다,하지만 불행히도 방법 1은 상황을 해결하지 않으며, 방법이 나를 위해 받아 들일 수없는 것입니다. – w128

3

이전 주제이지만 실제로는 문제가 많습니다. 내가 몇 년 동안 그런 문제를 다루었 기 때문에 나는 그것에 약간의 빛을 두려고 노력할 것이다.

우선 : Windows에서는 하나의 네트워크 공유에서 여러 하위 폴더에 연결할 수 없습니다.

두 번째로 : Windows가 원격 이름으로 연결을 식별하고 있습니다. 따라서 서로 다른 이름을 사용하여 같은 서버에 둘 이상의 연결을 설정할 수 있습니다. www.serwerName.com 및 123.123.123.123 (ip 기준) - 이들은 서로 다른 자격 증명으로 별도의 연결로 처리됩니다.

내 솔루션은 내 serwer에 별칭 IP를 추가하는 것이 었습니다. 내 serwer의 별칭을 10 개 만들었고 내 응용 프로그램이 목록에서 첫 번째 IP를 가져온 다음 차단 된 경우 다음 등.

이 솔루션은 좋지 않지만 작동합니다. 문제는 당신이 serwer IP에 접근 할 수 없을 때입니다. 그 때 무엇? 다음 지점을 확인하십시오 :

마지막으로 : 다음 유일한 해결책은 지정된 네트워크 공유를 사용한 후 사용자의 연결을 끊는 것입니다. 여기에 다른 모든 문제가 시작됩니다 ... 로그인이 다른 사람을 차단하는 많은 것들에 의해 사용됩니다. 예를 들어 누군가가 네트워크 공유에서 Word 문서를 엽니 다. 이제 연결을 끊을 수 없습니다. 하지만 net.exe는 연결을 표시하지 않습니다! 또 다른하지만 ​​몇 분 (약 1 분) 후에 Word 문서를 닫을 때 자동으로 닫히고 새로운 연결을 허용합니다.

내 작업이 이제 연결을 차단하고 사용자에게 알리는 시스템 시스템 요소를 찾으라는 지시가 내려집니다. 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 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 옵션을 올바르게 설정하지 않으면 문제가 발생합니다. 설정되지 않은 경우, 창문이 탑재 된 드라이브를 기억하고 오류의 원인이 ofcource 컴퓨터를 다시 시작 후에 다시 연결을 시도합니다 : 일부 드라이브를 연결할 수 없습니다 : 억세스 할수 :)

0

을 내가 오류 코드에 사용되는 솔루션을 공유 할 1219 다른 경로로도 WNetCancelConnection2()을 사용하여 공유 경로로 드라이브를 매핑하는 동안이 방법이 해결 될 수 있다고 생각합니다.

우선 네트워크에 컴퓨터가 구성되어 있는지 확인해야합니다. 이 도메인에있는 경우

:

사용자 이름은 \ [사용자 이름] [도메인 이름]해야한다, 때때로 당신은 단순히 [사용자 이름]을 사용할 수 있습니다.

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 서비스를 사용하는 경우 특정 사용자 자격 증명과 마찬가지로 로그온을 변경하십시오.