U盘 USB 盘 拔插监测


namespace ConsoleApplication
{
    using System;
    using Microshaoft;
    public class Class1
    {
        static void Main(string[] args)
        {
            DriveDetector x = new DriveDetector();
            x.DeviceArrived += new DriveDetector.DriveDetectorEventHandler(x_DeviceArrived);
            x.DeviceRemoved += new DriveDetector.DriveDetectorEventHandler(x_DeviceRemoved);
            Console.WriteLine("Hello World");
            Console.WriteLine(Environment.Version.ToString());
            Console.ReadLine();
        }
        static void x_DeviceRemoved(DriveDetector sender, DriveDetectorEventArgs e)
        {
            Console.WriteLine("DeviceRemoved {0}", e.Drive);
        }
        static void x_DeviceArrived(DriveDetector sender, DriveDetectorEventArgs e)
        {
            Console.WriteLine("DeviceArrived {0}", e.Drive);
        }
    }
}
namespace Microshaoft
{
    using System;
    using System.Windows.Forms;                // required for Message
    using System.Runtime.InteropServices;    // required for Marshal
    using System.IO;
    using Microsoft.Win32.SafeHandles;
    using System.Threading;
    public class DriveDetectorEventArgs : EventArgs
    {
        public DriveDetectorEventArgs()
        {
            Cancel = false;
            Drive = "";
            HookQueryRemove = false;
        }
        public bool Cancel;
        public string Drive;
        public bool HookQueryRemove;
    }
    public class DriveDetector : IDisposable
    {
        public event DriveDetectorEventHandler DeviceArrived;
        public event DriveDetectorEventHandler DeviceRemoved;
        public event DriveDetectorEventHandler QueryRemove;
        public delegate void DriveDetectorEventHandler(DriveDetector sender, DriveDetectorEventArgs e);
        private WindowsMessagesListener _listener;// = new WindowsMessagesListener();
        private IntPtr _DirHandle = IntPtr.Zero;
        private FileStream _FileOnFlash = null;
        private string _FileToOpen;
        private IntPtr _DeviceNotifyHandle;
        private IntPtr _hWnd;
        private string _CurrentDrive;
        private Thread _thread;
        private class WindowsMessagesListener : Form//NativeWindow
        {
            public delegate void WndProcEventHandler(ref Message m, bool cancel);
            public event WndProcEventHandler BeforeBaseWndProc;
            public event WndProcEventHandler AfterBaseWndProc;
            protected override void WndProc(ref Message m)
            {
                bool b = false;
                if (BeforeBaseWndProc != null)
                {
                    BeforeBaseWndProc(ref m, b);
                }
                if (!b)
                {
                    base.WndProc(ref m);
                    if (AfterBaseWndProc != null)
                    {
                        AfterBaseWndProc(ref m, b);
                    }
                }
            }
        }
        public DriveDetector()
        {
            Init(null);
        }
        public DriveDetector(string FileToOpen)
        {
            Init(FileToOpen);
        }
        private void Init(string fileToOpen)
        {
            _thread = new Thread(new ThreadStart(Run)); //监视线程: 显示滚动计数器
            _thread.Start();
            _FileToOpen = fileToOpen;
            _FileOnFlash = null;
            _DeviceNotifyHandle = IntPtr.Zero;
            _DirHandle = IntPtr.Zero;   // handle to the root directory of the flash drive which we open 
            _CurrentDrive = "";
        }
        private void Run()
        {
            _listener = new WindowsMessagesListener();
            _hWnd = _listener.Handle;
            _listener.AfterBaseWndProc += new WindowsMessagesListener.WndProcEventHandler(_listener_AfterBaseWndProc);
            Application.Run();
        }
        void _listener_AfterBaseWndProc(ref Message m, bool canceledBaseWndProc)
        {
            int devType;
            char c;
            if (m.Msg == Win32Native.WM_DEVICECHANGE)
            {
                // WM_DEVICECHANGE can have several meanings depending on the WParam value...
                switch (m.WParam.ToInt32())
                {
                    //
                    // New device has just arrived
                    //
                    case Win32Native.DBT_DEVICEARRIVAL :
                        devType = Marshal.ReadInt32(m.LParam, 4);
                        if (devType == Win32Native.DBT_DEVTYP_VOLUME)
                        {
                            DEV_BROADCAST_VOLUME vol;
                            vol = (DEV_BROADCAST_VOLUME)
                                Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
                            // Get the drive letter 
                            c = DriveMaskToLetter(vol.dbcv_unitmask);
                            //
                            // Call the client event handler
                            //
                            // We should create copy of the event before testing it and
                            // calling the delegate - if any
                            DriveDetectorEventHandler tempDeviceArrived = DeviceArrived;
                            if (tempDeviceArrived != null)
                            {
                                DriveDetectorEventArgs e = new DriveDetectorEventArgs();
                                e.Drive = c + ":\\";
                                tempDeviceArrived(this, e);
                                // Register for query remove if requested
                                if (e.HookQueryRemove)
                                {
                                    // If something is already hooked, unhook it now
                                    if (_DeviceNotifyHandle != IntPtr.Zero)
                                    {
                                        RegisterForDeviceChange(false, null);
                                    }
                                    RegisterQuery(c + ":\\");
                                }
                            }    // if  has event handler
                        }
                        break;
                    //
                    // Device is about to be removed
                    // Any application can cancel the removal
                    //
                    case Win32Native.DBT_DEVICEQUERYREMOVE :
                        devType = Marshal.ReadInt32(m.LParam, 4);
                        if (devType == Win32Native.DBT_DEVTYP_HANDLE)
                        {
                            // TODO: we could get the handle for which this message is sent 
                            // from vol.dbch_handle and compare it against a list of handles for 
                            // which we have registered the query remove message (?)                                                
                            //DEV_BROADCAST_HANDLE vol;
                            //vol = (DEV_BROADCAST_HANDLE)
                            //   Marshal.PtrToStructure(_.LParam, typeof(DEV_BROADCAST_HANDLE));
                            // if ( vol.dbch_handle ....
                            //
                            // Call the event handler in client
                            //
                            DriveDetectorEventHandler tempQuery = QueryRemove;
                            if (tempQuery != null)
                            {
                                DriveDetectorEventArgs e = new DriveDetectorEventArgs();
                                e.Drive = _CurrentDrive;        // drive which is hooked
                                tempQuery(this, e);
                                // If the client wants to cancel, let Windows know
                                if (e.Cancel)
                                {
                                    m.Result = (IntPtr)Win32Native.BROADCAST_QUERY_DENY;
                                }
                                else
                                {
                                    // Change 28.10.2007: Unregister the notification, this will
                                    // close the handle to file or root directory also. 
                                    // We have to close it anyway to allow the removal so
                                    // even if some other app cancels the removal we would not know about it...
                                    RegisterForDeviceChange(false, null);   // will also close the mFileOnFlash
                                }
                            }
                        }
                        break;
                    //
                    // Device has been removed
                    //
                    case Win32Native.DBT_DEVICEREMOVECOMPLETE :
                        devType = Marshal.ReadInt32(m.LParam, 4);
                        if (devType == Win32Native.DBT_DEVTYP_VOLUME)
                        {
                            devType = Marshal.ReadInt32(m.LParam, 4);
                            if (devType == Win32Native.DBT_DEVTYP_VOLUME)
                            {
                                DEV_BROADCAST_VOLUME vol;
                                vol = (DEV_BROADCAST_VOLUME)
                                    Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
                                c = DriveMaskToLetter(vol.dbcv_unitmask);
                                //
                                // Call the client event handler
                                //
                                DriveDetectorEventHandler tempDeviceRemoved = DeviceRemoved;
                                if (tempDeviceRemoved != null)
                                {
                                    DriveDetectorEventArgs e = new DriveDetectorEventArgs();
                                    e.Drive = c + ":\\";
                                    tempDeviceRemoved(this, e);
                                }
                                // TODO: we could unregister the notify handle here if we knew it is the
                                // right drive which has been just removed
                                //RegisterForDeviceChange(false, null);
                            }
                        }
                        break;
                }
            }
        }
        public bool IsQueryHooked
        {
            get
            {
                if (_DeviceNotifyHandle == IntPtr.Zero)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
        public string HookedDrive
        {
            get
            {
                return _CurrentDrive;
            }
        }
        public FileStream OpenedFile
        {
            get
            {
                return _FileOnFlash;
            }
        }
        public bool EnableQueryRemove(string fileOnDrive)
        {
            if (fileOnDrive == null || fileOnDrive.Length == 0)
            {
                throw new ArgumentException("Drive path must be supplied to register for Query remove.");
            }
            if (fileOnDrive.Length == 2 && fileOnDrive[1] == ':')
            {
                fileOnDrive += '\\';        // append "\\" if only drive letter with ":" was passed in.
            }
            if (_DeviceNotifyHandle != IntPtr.Zero)
            {
                // Unregister first...
                RegisterForDeviceChange(false, null);
            }
            if (Path.GetFileName(fileOnDrive).Length == 0 || !File.Exists(fileOnDrive))
            {
                _FileToOpen = null;    // use root directory...
            }
            else
            {
                _FileToOpen = fileOnDrive;
            }
            RegisterQuery(Path.GetPathRoot(fileOnDrive));
            if (_DeviceNotifyHandle == IntPtr.Zero)
            {
                return false;   // failed to register
            }
            return true;
        }
        public void DisableQueryRemove()
        {
            if (_DeviceNotifyHandle != IntPtr.Zero)
            {
                RegisterForDeviceChange(false, null);
            }
        }
        public void Dispose()
        {
            RegisterForDeviceChange(false, null);
        }
        private void RegisterQuery(string drive)
        {
            bool register = true;
            if (!String.IsNullOrEmpty(_FileToOpen))
            {
                // Make sure the path in mFileToOpen contains valid drive
                // If there is a drive letter in the path, it may be different from the  actual
                // letter assigned to the drive now. We will cut it off and merge the actual drive 
                // with the rest of the path.
                if (_FileToOpen.Contains(":"))
                {
                    string tmp = _FileToOpen.Substring(3);
                    string root = Path.GetPathRoot(drive);
                    _FileToOpen = Path.Combine(root, tmp);
                }
                else
                {
                    _FileToOpen = Path.Combine(drive, _FileToOpen);
                }
            }
            try
            {
                //mFileOnFlash = new FileStream(_FileToOpen, FileMode.Open);
                // Change 28.10.2007 - Open the root directory 
                if (_FileToOpen == null)  // open root directory
                {
                    _FileOnFlash = null;
                }
                else
                {
                    _FileOnFlash = new FileStream(_FileToOpen, FileMode.Open);
                }
            }
            catch (Exception)
            {
                // just do not register if the file could not be opened
                register = false;
            }
            if (register)
            {
                //RegisterForDeviceChange(true, mFileOnFlash.SafeFileHandle);
                //mCurrentDrive = drive;
                // Change 28.10.2007 - Open the root directory 
                if (_FileOnFlash == null)
                {
                    RegisterForDeviceChange(drive);
                }
                else
                {
                    // old version
                    RegisterForDeviceChange(true,_FileOnFlash.SafeFileHandle);
                }
                _CurrentDrive = drive;
            }
        }
        private void RegisterForDeviceChange(string dirPath)
        {
            IntPtr handle = Win32Native.OpenDirectory(dirPath);
            if (handle == IntPtr.Zero)
            {
                _DeviceNotifyHandle = IntPtr.Zero;
                return;
            }
            else
                _DirHandle = handle;    // save handle for closing it when unregistering
            // Register for handle
            DEV_BROADCAST_HANDLE data = new DEV_BROADCAST_HANDLE();
            data.dbch_devicetype = Win32Native.DBT_DEVTYP_HANDLE;
            data.dbch_reserved = 0;
            data.dbch_nameoffset = 0;
            //data.dbch_data = null;
            //data.dbch_eventguid = 0;
            data.dbch_handle = handle;
            data.dbch_hdevnotify = (IntPtr)0;
            int size = Marshal.SizeOf(data);
            data.dbch_size = size;
            IntPtr buffer = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(data, buffer, true);
            _DeviceNotifyHandle = Win32Native.RegisterDeviceNotification(_hWnd, buffer, 0);
        }
        private void RegisterForDeviceChange(bool register, SafeFileHandle fileHandle)
        {
            if (register)
            {
                // Register for handle
                DEV_BROADCAST_HANDLE data = new DEV_BROADCAST_HANDLE();
                data.dbch_devicetype = Win32Native.DBT_DEVTYP_HANDLE;
                data.dbch_reserved = 0;
                data.dbch_nameoffset = 0;
                //data.dbch_data = null;
                //data.dbch_eventguid = 0;
                data.dbch_handle = fileHandle.DangerousGetHandle(); //Marshal. fileHandle; 
                data.dbch_hdevnotify = (IntPtr)0;
                int size = Marshal.SizeOf(data);
                data.dbch_size = size;
                IntPtr buffer = Marshal.AllocHGlobal(size);
                Marshal.StructureToPtr(data, buffer, true);
                _DeviceNotifyHandle = Win32Native.RegisterDeviceNotification(_hWnd, buffer, 0);
            }
            else
            {
                // close the directory handle
                if (_DirHandle != IntPtr.Zero)
                {
                    Win32Native.CloseDirectoryHandle(_DirHandle);
                    //    string er = Marshal.GetLastWin32Error().ToString();
                }
                // unregister
                if (_DeviceNotifyHandle != IntPtr.Zero)
                {
                    Win32Native.UnregisterDeviceNotification(_DeviceNotifyHandle);
                }
                _DeviceNotifyHandle = IntPtr.Zero;
                _DirHandle = IntPtr.Zero;
                _CurrentDrive = "";
                if (_FileOnFlash != null)
                {
                    _FileOnFlash.Close();
                    _FileOnFlash = null;
                }
            }
        }
        private static char DriveMaskToLetter(int mask)
        {
            char c;
            string drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            // 1 = A
            // 2 = B
            // 4 = C...
            int i = 0;
            int p = mask / 2;
            while (p != 0)
            {
                p = p / 2;
                i ++;
            }
            if (i < drives.Length)
            {
                c = drives[i];
            }
            else
            {
                c = '?';
            }
            return c;
        }
        private class Win32Native
        {
            // Win32 constants
            public const int DBT_DEVTYP_DEVICEINTERFACE = 5;
            public const int DBT_DEVTYP_HANDLE = 6;
            public const int BROADCAST_QUERY_DENY = 0x424D5144;
            public const int WM_DEVICECHANGE = 0x0219;
            public const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device
            public const int DBT_DEVICEQUERYREMOVE = 0x8001;   // Preparing to remove (any program can disable the removal)
            public const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // removed 
            public const int DBT_DEVTYP_VOLUME = 0x00000002; // drive type is logical volume
            //   HDEVNOTIFY RegisterDeviceNotification(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            public static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, uint Flags);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            public static extern uint UnregisterDeviceNotification(IntPtr hHandle);
            //
            // CreateFile  - MSDN
            const uint GENERIC_READ = 0x80000000;
            const uint OPEN_EXISTING = 3;
            const uint FILE_SHARE_READ = 0x00000001;
            const uint FILE_SHARE_WRITE = 0x00000002;
            const uint FILE_ATTRIBUTE_NORMAL = 128;
            const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
            static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
            // should be "static extern unsafe"
            [DllImport("kernel32", SetLastError = true)]
            static extern IntPtr CreateFile
                                        (
                                            string FileName,                    // file name
                                            uint DesiredAccess,                // access mode
                                            uint ShareMode,                    // share mode
                                            uint SecurityAttributes,            // Security Attributes
                                            uint CreationDisposition,          // how to create
                                            uint FlagsAndAttributes,            // file attributes
                                            int hTemplateFile                  // handle to template file
                                        );
            [DllImport("kernel32", SetLastError = true)]
            static extern bool CloseHandle
                                        (
                                            IntPtr hObject   // handle to object
                                        );
            static public IntPtr OpenDirectory(string dirPath)
            {
                // open the existing file for reading         
                IntPtr handle = CreateFile
                                        (
                                            dirPath,
                                            GENERIC_READ,
                                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                                            0,
                                            OPEN_EXISTING,
                                            FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
                                            0
                                        );
                if (handle == INVALID_HANDLE_VALUE)
                {
                    return IntPtr.Zero;
                }
                else
                {
                    return handle;
                }
            }
            public static bool CloseDirectoryHandle(IntPtr handle)
            {
                return CloseHandle(handle);
            }
        }
        // Structure with information for RegisterDeviceNotification.
        [StructLayout(LayoutKind.Sequential)]
        public struct DEV_BROADCAST_HANDLE
        {
            public int dbch_size;
            public int dbch_devicetype;
            public int dbch_reserved;
            public IntPtr dbch_handle;
            public IntPtr dbch_hdevnotify;
            public Guid dbch_eventguid;
            public long dbch_nameoffset;
            //public byte[] dbch_data[1]; // = new byte[1];
            public byte dbch_data;
            public byte dbch_data1;
        }
        // Struct for parameters of the WM_DEVICECHANGE message
        [StructLayout(LayoutKind.Sequential)]
        public struct DEV_BROADCAST_VOLUME
        {
            public int dbcv_size;
            public int dbcv_devicetype;
            public int dbcv_reserved;
            public int dbcv_unitmask;
        }
    }
}

posted @ 2008-12-28 01:45  于斯人也  阅读(1188)  评论(0编辑  收藏  举报