セージ の メモ書き

メモこそ命の恩人だ

C# - 共有フォルダーアクセス

注意点

  • UNCパスの最後に「\」をセットしないこと。アクセスに失敗する。
    • NG:\192.168.0.1\Sample\
    • OK:\192.168.0.1\Sample

実装例

コード:86, メッセージ:指定されたネットワーク パスワードが間違っています。
=> パスワードの間違い

コード:1219, メッセージ:同じユーザーによる、サーバーまたは共有リソースへの複数のユーザー名での複数の接続は許可されません。サーバーまたは共有リソースへの以前の接続をすべて切断してから、再試行してください
=> Windowsに資格情報が登録済み。資格情報を削除して、OSを再起動する。
/// <summary>
/// フォルダーアクセス可能にする
/// </summary>
/// <param name="uncPath">UNCパス</param>
/// <param name="userName">ユーザー名</param>
/// <param name="userPassword">ユーザーパスワード</param>
/// <returns>true:成功、false:失敗</returns> 
/// <remarks>
/// 処理に成功した場合、UNCパスのフォルダーにアクセス可能になる。
/// </remarks>
public bool AccessFolder(string uncPath, string userName, string userPassword)
{
    if (!CancelConnection(uncPath)) return false;
    return AddConnection(uncPath, userName, userPassword);

    // 接続解除(※ 接続前に実施すること)
    bool CancelConnection(string uncPath)
    {
        try
        {
            var result = NativeMethods.WNetCancelConnection2(uncPath, dwFlags: 0, fForce: true);

            const int success = 0;
            const int errorNotConnected = 2250; // 初回、未接続状態で実施した場合の応答
            if ((result == success) || (result == errorNotConnected))
            {
                Debug.WriteLine($"接続解除成功 <UNC:{uncPath}>");
                return true;
            }
            var errorMessage = new System.ComponentModel.Win32Exception(result).Message;
            Debug.WriteLine($"接続解除エラー <コード:{result}, メッセージ:{errorMessage}, UNC:{uncPath}>");
            return false;
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"接続解除エラー {ex}");
            return false;
        }
    }

    // 接続実行
    bool AddConnection(string uncPath, string userName, string userPassword)
    {
        var netResource = new NETRESOURCE
        {
            dwScope = 0,
            dwType = 1,
            dwDisplayType = 0,
            dwUsage = 0,
            lpLocalName = "",
            lpRemoteName = uncPath,
            lpProvider = ""
        };

        try
        {
            var result = NativeMethods.WNetAddConnection2(ref netResource, userPassword, userName, dwFlags: 0);

            const int success = 0;
            if (result == success)
            {
                Debug.WriteLine($"接続成功 <UNC:{uncPath}, ユーザー:{userName}>");
                return true;
            }
            var errorMessage = new System.ComponentModel.Win32Exception(result).Message;
            Debug.WriteLine($"接続エラー <コード:{result}, メッセージ:{errorMessage}, UNC:{uncPath}, ユーザー:{userName}>");
            return false;
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"接続エラー {ex}");
            return false;
        }
    }
}

#region 非公開内部クラス
/// <summary>
/// P/Invoke(プラットフォーム呼出)メソッド定義用クラス
/// </summary>
/// <remarks>
/// DllImportを使用する場合、NativeMethods内に定義すること。(コード分析対応:CA1060、CA1401)
/// https://docs.microsoft.com/ja-jp/visualstudio/code-quality/ca1060-move-p-invokes-to-nativemethods-class
/// </remarks>
private static class NativeMethods
{
    #region 接続に関するライブラリのインポート
    /// <summary>
    /// ネットワークドライブに接続する
    /// </summary>
    /// <param name="lpNetResource"> NETRESOURCE構造体</param>
    /// <param name="lpPassword">パスワード</param>
    /// <param name="lpUsername">ユーザー名</param>
    /// <param name="dwFlags">接続オプション(※ 0 固定:認証の資格情報を更新しない)</param>
    /// <returns>エラーコード</returns>
    /// <remarks>
    /// https://www.tokovalue.jp/function/WNetAddConnection2.htm
    /// </remarks>
    [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2", CharSet = CharSet.Unicode)]
    internal static extern int WNetAddConnection2(ref NETRESOURCE lpNetResource, string lpPassword, string lpUsername, int dwFlags);

    /// <summary>
    /// ネットワークドライブへの接続を切断する
    /// </summary>
    /// <param name="lpName">UNCパス or ネットワークドライブ名</param>
    /// <param name="dwFlags">接続オプション(※ 0 固定:認証の資格情報を更新しない)</param>
    /// <param name="fForce">強制的な切断フラグ(※ true固定:リモート先で参照しているファイルがある場合に切断する)</param>
    /// <returns>エラーコード</returns>
    /// <remarks>
    /// https://www.tokovalue.jp/function/WNetCancelConnection2.htm
    /// </remarks>
    [DllImport("mpr.dll", EntryPoint = "WNetCancelConnection2", CharSet = CharSet.Unicode)]
    internal static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);
    #endregion
}
#endregion

#region 内部構造体
/// <summary>
/// NETRESOURCE構造体
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct NETRESOURCE
{
    /// <summary>
    /// リソース範囲
    /// </summary>
    /// <remarks>
    /// 1(RESOURCE_CONNECTED):現在接続されたリソースを列挙する。dwUsageメンバーを指定できない。
    /// 2(RESOURCE_GLOBALNET):ネットワークに関するすべてのリソースを列挙する。
    /// 3(RESOURCE_REMEMBERED):接続を列挙する。dwUsageメンバーを指定できない。
    /// </remarks>
    public int dwScope;

    /// <summary>
    /// リソースタイプ
    /// </summary>
    /// <remarks>
    /// 0(RESOURCETYPE_ANY):すべてのリソース
    /// 1(RESOURCETYPE_DISK):ディスクリソース
    /// 2(RESOURCETYPE_PRINT):プリンタリソース
    /// </remarks>
    public int dwType;

    /// <summary>
    /// 表示タイプ
    /// </summary>
    /// <remarks>
    /// 0(RESOURCEDISPLAYTYPE_GENERIC):オブジェクトの表示は重要ではないことを示す
    /// 1(RESOURCEDISPLAYTYPE_DOMAIN):ドメインオブジェクトを表示する
    /// 2(RESOURCEDISPLAYTYPE_SERVER):サーバオブジェクトを表示する
    /// 3(RESOURCEDISPLAYTYPE_SHARE):シェアオブジェクトを表示する
    /// </remarks>
    public int dwDisplayType;

    /// <summary>
    /// リソース用途
    /// </summary>
    /// <remarks>
    /// 1(RESOURCEUSAGE_CONNECTABLE):接続可能なリソースであることを示す。lpRemoteNameメンバーによって示された名前はWNetAddConnection機能に通過できる。
    /// 2(RESOURCEUSAGE_CONTAINER):リソースはコンテナリソースです。lpRemoteNameメンバーによって示された名前はWNetOpenEnum機能に通過できる。
    /// </remarks>
    public int dwUsage;

    /// <summary>
    /// ローカルデバイス名(未使用の場合はNULL)
    /// </summary>
    /// <remarks>
    /// ネットワークドライブに接続する場合、ドライブレターを指定する。
    /// </remarks>
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpLocalName;

    /// <summary>
    /// リモートネットワーク名(未使用の場合はNULL)
    /// </summary>
    /// <remarks>
    /// 共有フォルダーに接続する場合、UNCパスを指定する。
    /// </remarks>
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpRemoteName;

    /// <summary>
    /// ネットワーク内の提供者に提供された文字列
    /// </summary>
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpComment;

    /// <summary>
    /// リソースを所有しているプロバイダ名
    /// </summary>
    [MarshalAs(UnmanagedType.LPWStr)]
    public string lpProvider;
}
#endregion



以上