Win 32 API netapi 32を呼び出す.dll UNC(ネットワーク共有)接続の管理を実現(一)


本章ではWin 32 API netapi 32を使用する.dllはUNCの接続許可を実現し、接続を切断し、UNCの接続状態の3つの機能を取得する.
一.まずDLLファイルをインポートします.
#region Register Win32 DLL File netapi32.dll
//        NetUseAdd
        [DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        static extern int NetUseAdd(
         string UncServerName, // not used
         int Level,  // use info struct level 1 or 2
         IntPtr Buf,  // Buffer
         ref int ParmError
        );
//        NetUseDel
        [DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        static extern int NetUseDel(
        string UncServerName,   //not used
        string UseName,         //Network Resource what do you want to disconnect;
        uint ForceCond          //disconnect mode;
        );
//  Get      NetUseGetInfo
        [DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        static extern int NetUseGetInfo(
        string UncServerName,
        string UseName,
        int Level,
        ref IntPtr BufPtr);
パラメータタイプを変換したC#用のコードですが、関数のプロトタイプについてはMSDNを参照してください.
次に、上記のパラメータについて簡単に説明します.この章で説明した内容に対応するには十分です(詳細はMSDNを参照してください):
(上から順に紹介)
string UncServerName:
このパラメータは使わないで、Callの時に空にします.
int Level:
そのstructを使用してパラメータを関数に入力し、1はUSE_を表します.INFO_1または2はUSEを表します.INFO_2、知能は両者の間で一つを選択する.
IntPtr Buf, 
上の対応する構造を指すポインタ(C#にはポインタはありませんが、この役割はポインタに似ていて、もっと専門的な教法を知っている友达に知らせることができます).
ref int ParmError:
これはあまり使われていないようなので、よく研究していないので、SourceCodeの使い方を直接見てください
uint ForceCond:
接続解除時のモードは、3種類あります.
    private const uint USE_NOFORCE = 0;    //Do not fail the disconnection if open files exist son the connection.    private const uint USE_FORCE = 1;      //Fail the disconnection if open files exists on the connection.    private const uint USE_LOTS_OF_FORCE = 2;  //Close any open files and delete the connection.
ref IntPtr BufPtr:
GetNetUseInfoに伝達するStruct IntPrtオブジェクトは、取得した情報を持ち出す責任を負う.
 
3つの機能を実現するための完全なSource Codeについて説明します.
 
class WinNet
    {
        #region Define netapi32.dll need data structure
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct _USE_INFO_2
        {
            internal string ui2_local;
            internal string ui2_remote;
            //internal IntPtr ui2_password; // don't pass a string or StringBuilder here!!
            internal string ui2_password;
            internal uint ui2_status;
            internal uint ui2_asg_type;
            internal uint ui2_refcount;
            internal uint ui2_usecount;
            internal string ui2_username;
            internal string ui2_domainname;
        }
        const uint USE_WILDCARD = 0xFFFFFFFF;

        private const uint USE_NOFORCE = 0;     //Do not fail the disconnection if open files exist son the connection.
        private const uint USE_FORCE = 1;       //Fail the disconnection if open files exists on the connection.
        private const uint USE_LOTS_OF_FORCE = 2;   //Close any open files and delete the connection.

        private const uint USE_OK = 0;        //The connection is valid.
        private const uint USE_PAUSED = 1;    // Paused by local workstation.
        private const uint USE_SESSLOST = 2;// Disconnected.
        private const uint USE_DISCONN = 3;// An error occurred.
        private const uint USE_NETERR = 4;// A network error occurred.
        private const uint USE_CONN = 5;// The connection is being made.
        private const uint USE_RECONN = 6;// Reconnecting.

        private static WinNet _instance = new WinNet();

        public static WinNet Instance
        {
            get { return _instance; }
        }
        #endregion

        #region Register Win32 DLL File netapi32.dll
        [DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        static extern int NetUseAdd(
         string UncServerName, // not used
         int Level,  // use info struct level 1 or 2
         IntPtr Buf,  // Buffer
         ref int ParmError
        );

        [DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        static extern int NetUseDel(
        string UncServerName,   //not used
        string UseName,         //Network Resource what do you want to disconnect;
        uint ForceCond          //disconnect mode;
        );
        [DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        static extern int NetUseGetInfo(
        string UncServerName,
        string UseName,
        int Level,
        ref IntPtr BufPtr);

        #endregion

        /// 
        /// Establish a use record
        /// 
        /// 
        /// 
        /// 
        /// 
        public static bool UseRecord(string resource, string user, string password, string domain)
        {
            bool RtnValue = false;
            int ret = 1;
            int paramError = 0;
            _USE_INFO_2 use2 = new _USE_INFO_2();
            IntPtr pBuf = IntPtr.Zero;
            //use2.ui2_password = IntPtr.Zero;
            try
            {
                pBuf = Marshal.AllocHGlobal(Marshal.SizeOf(use2));
                use2.ui2_local = null;
                use2.ui2_asg_type = USE_WILDCARD;
                use2.ui2_remote = resource;
                //use2.ui2_password = Marshal.StringToHGlobalAuto(password);
                use2.ui2_password = password;
                use2.ui2_username = user;
                use2.ui2_domainname = domain;
                Marshal.StructureToPtr(use2, pBuf, true);
                ret = NetUseAdd(null, 2, pBuf, ref paramError);
                if (ret != 0)
                {
                    throw new Exception(ErrorCodeHandler(ret));
                }
                RtnValue = true;
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                Marshal.FreeHGlobal(pBuf);
            }
            return RtnValue;
        }

        /// 
        /// Destroy a use record  
        /// 
        ///     
        public static void DeleteRecord(string resource)
        {
            int ret = 1;
            try
            {
                ret = NetUseDel(null, resource, USE_LOTS_OF_FORCE);
                if (ret != 0)
                {
                    throw new Exception(ErrorCodeHandler(ret));
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public static _USE_INFO_2 GetUseInfo(string resource)
        {
            int ret = 1;
            _USE_INFO_2 ui2 = new _USE_INFO_2();
            IntPtr pBuf = IntPtr.Zero;
            try
            {
                pBuf = Marshal.AllocHGlobal(Marshal.SizeOf(new _USE_INFO_2()));
                ret = NetUseGetInfo(null, resource, 2, ref pBuf);
                if (ret != 0)
                {
                    throw new Exception(ErrorCodeHandler(ret));
                }
                ui2 = (_USE_INFO_2)Marshal.PtrToStructure(pBuf, typeof(_USE_INFO_2));
            }
            catch
            {
                //throw e;                
            }
            finally
            {
                Marshal.FreeHGlobal(pBuf);
            }
            return ui2;
        }

        #region Win32 ErrorCode Handler Code
        public static string ErrorCodeHandler(int Win32ErrorCode)
        {
            string RtnMessage = string.Empty;
            switch (Win32ErrorCode)
            {
                case 67:
                    RtnMessage = "      .";
                    break;
                case 1219:
                    RtnMessage = "                                。                 ,      ... ";
                    break;
                case 2250:
                    RtnMessage = "        .";
                    break;

                default:
                    RtnMessage = "Unkown Error Code.";
                    break;
            }
            return RtnMessage + "/r/nWin32 Error Code:" + Win32ErrorCode;
        }
        #endregion
    }
 
 
API呼び出し異常の処理については、コードをデバッグするときに出会ったバグでもあります.ついでに、これを共有します.
通常、Api呼び出しに異常が発生した場合、GetLastError()メソッドで最後のエラーが取得されますが、私が実際に実行している間にN(N>10)回のエラーが発生し、GetLastError()で得られたエラー情報はすべて「オーバーラップI/O操作が進行中」であり、あちこち助けを求めても答えが得られませんでしたが、その後、各APIが終了した後にintタイプの戻り値:0が実行成功を表していることに気づきました.本章でよく用いられるErrorCodeHandler()法について説明した.
 
次に暇があれば、Windows UNC共有管理のウィジェットを書く予定です.その中には、現在のすべての共有の様々な状態と、すべての共有に対する操作がリストされます.
 
Remark:
上の取得共有状態は現在connection or disconnectionのみと判断でき、私のプロジェクトにはこれに対してこの2つの状態のみを要求すべきであるため、詳細な分類は行われていない.