1台のPC上で動く複数のアプリによる共有フォルダアクセスについてメモ。OSはWindows XP。
共有フォルダに対してネットワークドライブを割り当てられるWNetAddConnection2と、割り当てを解除(切断)するWNetCancelConnection2の動作について確認しました。コードの信頼性等については保障できませんので、もし参考にされる奇特な方がいらっしゃいましたら各自確認願います(Visual Studio 2008/VB.NET利用)。
確認はすべて「1台のパソコンからもう1台の共有フォルダを見る」という方針で行っています。
結論
- 別ユーザー名義で動くプログラムであれば、ネットワークドライブ名が重複していても全く問題無く、独立して接続状態を操作できる。
- 同一ユーザー名義で動くプログラムの場合、1プログラム、複数プログラムを問わず、ネットワークドライブ割り当てに関する制約が発生する。
- 1共有フォルダへの複数リモートアカウントでの接続はできない(あとから接続した方がエラーになる)。
- (当然のことながら)同一のネットワークドライブ名での接続はできない(あとから接続した方がエラーになる)。
接続
- 1プログラムが、同一のリモートアカウントで同一の共有フォルダに同一ドライブ名で接続。
- 「(Error 85) ローカル デバイス名は既に使用されています。」が発生。
- 1プログラムが、同一のリモートアカウントで同一の共有フォルダに別のドライブ名で接続。
- 問題無く割り当て完了(たとえば、共有フォルダAにドライブWとZを割り当て)。
- 1プログラムが、複数のリモートアカウントで同一の共有フォルダに別のドライブ名で接続。
- 「(Error 1219) 同じユーザーによる、サーバーまたは共有リソースへの複数のユーザー名での複数の接続は許可されません。サーバーまたは共有リソースへの以前の接続をすべて切断してから、再試行してください。」が発生。エラーが戻るまで数十秒かかる。
- 2プログラムが、同一のリモートアカウントで同一の共有フォルダに同一ドライブ名で接続。
- 「(Error 85) ローカル デバイス名は既に使用されています。」が発生。
- 2プログラムが、同一のリモートアカウントで同一の共有フォルダに別のドライブ名で接続。
- 問題無く割り当て完了(たとえば、共有フォルダAにドライブWとZを割り当て)。
- 2プログラムが、複数のリモートアカウントで同一の共有フォルダに別のドライブ名で接続。
- 「(Error 1219) 同じユーザーによる、サーバーまたは共有リソースへの複数のユーザー名での複数の接続は許可されません。サーバーまたは共有リソースへの以前の接続をすべて切断してから、再試行してください。」が発生。エラーが戻るまで数十秒かかる。
- 同一PCの別アカウントで動く2プログラム*1が、同一の共有フォルダに接続。
- ドライブ名、アカウントの如何に関わらず、問題無く割り当て完了。
切断
- 切断については、同一ユーザーによる1つ以上のプログラムでの接続が、「同一リモートアカウントで、ネットワークドライブ名を変えた場合だけ重複接続可能」であることから、どこかを切断すると予期しない別の接続切れるというケースは無い。
- ただ、MSDNにある「切断先としてドライブ名ではなくリモートリソース名(\\192.168.0.10\Test1 など)を指定した場合、そこへの全接続が切断されるというケースはあるのかもしれない……が、実際上記のような文字列を指定して切断した場合、「(Error 2250) このネットワーク接続はありません。」が発生して切断できなかった。
作って覚える Visual Basic 2017 デスクトップアプリ入門
- 作者: 荻原裕之,宮崎昭世
- 出版社/メーカー: 秀和システム
- 発売日: 2017/09/23
- メディア: 単行本
- この商品を含むブログを見る
サンプルとして使ったコード(抜粋)
WNetAddConnection2に渡すデータ構造用の構造体宣言は下記。
''' <summary> ''' WNetAddConnection2用の構造体定義 ''' </summary> ''' <remarks></remarks> Public Structure NETRESOURCE Public dwScope As Integer Public dwType As Integer Public dwDisplayType As Integer Public dwUsage As Integer Public LocalName As String Public RemoteName As String Public Comment As String Public Provider As String End Structure
接続処理の呼び出しは下記。
Declare Function WNetAddConnection2 Lib "mpr.dll" Alias "WNetAddConnection2A" (ByRef netResource As NETRESOURCE, ByVal password As String, ByVal Username As String, ByVal Flag As Integer) As Integer Declare Function WNetCancelConnection2 Lib "mpr.dll" Alias "WNetCancelConnection2A" (ByVal lpName As String, ByVal dwFlags As Long, ByVal fForce As Long) As Integer 'WNetAddConnection2用の定数定義 Private Const RESOURCE_CONNECTED As Long = &H1 Private Const RESOURCETYPE_ANY As Long = &H0 Private Const RESOURCEDISPLAYTYPE_SHARE As Long = &H3 Private Const CONNECT_UPDATE_PROFILE As Long = &H1 'これはWNetCancelConnection2と共用 ''' <summary> ''' ネットワークドライブとしてリソースに接続する ''' </summary> ''' <param name="RemoteName">リモートリソースをサーバー名からのURIで指定。</param> ''' <param name="LocalName">ローカルで割り当てるドライブ名を指定("Z:"など)。</param> ''' <param name="username">接続に用いるユーザー名。</param> ''' <param name="password">接続に用いるパスワード。</param> ''' <returns></returns> ''' <remarks></remarks> Public Function ConnectDrive(ByVal RemoteName As String, ByVal LocalName As String, _ Optional ByVal username As String = Nothing, _ Optional ByVal password As String = Nothing) Dim myResource As NETRESOURCE Try '接続 Dim returnValue As Integer myResource.dwScope = 2 myResource.dwType = 1 myResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE myResource.LocalName = LocalName myResource.RemoteName = RemoteName myResource.dwUsage = Nothing myResource.Comment = Nothing myResource.Provider = Nothing returnValue = WNetAddConnection2(myResource, password, username, 0) '結果判定 If returnValue <> 0 Then Dim errorMsg = New System.ComponentModel.Win32Exception(returnValue).Message Dim resultMsg As String = RemoteName & "に接続できません。 エラーメッセージ: " & vbNewLine & vbNewLine & "(Error " & returnValue & ") " & errorMsg Throw New System.ApplicationException(resultMsg) End If Return returnValue Catch ex As System.ApplicationException 'ApplicationExceptionの場合→スルー Throw Catch ex As Exception 'エラー発生時 Dim errorMsg As String = RemoteName & "に接続できません。 エラーメッセージ: " & vbNewLine & vbNewLine & ex.Message Throw New System.ApplicationException(errorMsg, ex) End Try End Function
切断処理は下記。
''' <summary> ''' ネットワークドライブを切断する。 ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Public Function DisconnectDrive(ByVal targetName As String) Try '切断 Dim returnValue As Integer returnValue = WNetCancelConnection2(targetName, CONNECT_UPDATE_PROFILE, -1) '結果判定 If returnValue <> 0 Then Dim errorMsg = New System.ComponentModel.Win32Exception(returnValue).Message Dim resultMsg = targetName & " を切断できません。 エラーメッセージ: " & vbNewLine & vbNewLine & "(Error " & returnValue & ") " & errorMsg Throw New System.ApplicationException(resultMsg) End If Return returnValue Catch ex As System.ApplicationException 'ApplicationExceptionの場合→スルー Throw Catch ex As Exception 'エラー発生時 Dim errorMsg As String = targetName & " を切断できません。 エラーメッセージ: " & vbNewLine & vbNewLine & ex.Message Throw New System.ApplicationException(errorMsg, ex) End Try End Function
*1:具体的には、XP上に作った2つのユーザーで、ユーザーを切り替えながらそれぞれプログラムを起動。