« Silverlight 5 pInvoke USB/Removable Drive detector
Hi,
A friend of mine asked me if an elevated trust Silverlight 5 application could monitor windows events, specifically when a USB drive is inserted or removed. I naturally said YES, knowing that pInvoke is supported, but decided to take a few moments to write some code.
After searching the web I found a great sample (written by Alexandra Rusina)
here: http://blogs.msdn.com/b/silverlight_sdk/archive/2011/09/27/pinvoke-in-silverlight5-and-net-framework.aspx
I proceeded to create simple class RemovableDriveMonitor which monitors windows messages by creating an actual window class (WNDCLASS) and hooking into its WndProc message stream as Alexandra demonstrated and added a RemovableDriveStatusChanged event to notify the host app of any changes to USB drives.
RemovableDriveMonitor is initialized by the host application which also subscribes to the RemovableDriveStatusChanged event. This even is fired with a different message for “USB Inserted” or “USB Removed”.
Enjoy,
JW.
How to use?
Add a class called RemovableDriveMonitor like so:
using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace SL5Oob { public class RemovableDriveMonitor { //Delegate public delegate void RemovableDriveMonitorHandler(object sender, RemovableDriveDetectionArgs e); //Event public event RemovableDriveMonitorHandler RemovableDriveStatusChanged; private void OnRemovableDriveStatusChanged(string msg) { if (null != RemovableDriveStatusChanged) { RemovableDriveStatusChanged(this, new RemovableDriveDetectionArgs(msg)); } } // Importing a set of necessary native methods from Win32 API. [DllImport("User32", EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto, SetLastError = true)] static extern IntPtr CreateWindowEx(int dwExStyle, string lpszClassName, string lpszWindowName, int style, int x, int y, int width, int height, IntPtr hWndParent, IntPtr hMenu, IntPtr hInst, [MarshalAs(UnmanagedType.AsAny)] object pvParam); [DllImport("user32.dll")] static extern IntPtr DefWindowProc(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] public static extern short RegisterClass(WNDCLASS wc); // Marshaling the Window structure. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class WNDCLASS { public int style; public WndProc lpfnWndProc; public int cbClsExtra; public int cbWndExtra; public IntPtr hInstance; public IntPtr hIcon; public IntPtr hCursor; public IntPtr hbrBackground; public string lpszMenuName; public string lpszClassName; } //system detects USB insertion/removal const int WM_DEVICECHANGE = 0x0219; // system detects a new device const int DBT_DEVICEARRIVAL = 0x8000; // device removed const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // Callbacks must have AllowReversePInvokeCalls attribute. [AllowReversePInvokeCalls] private IntPtr Callback( IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) { if (msg == WM_DEVICECHANGE) { if (wparam.ToInt32() == DBT_DEVICEARRIVAL) { Debug.WriteLine("USB inserted"); //<<<<<<<<<<<<<<<<<<<<<<<<<< OnRemovableDriveStatusChanged("USB Inserted"); } if (wparam.ToInt32() == DBT_DEVICEREMOVECOMPLETE) { Debug.WriteLine("USB removed"); //<<<<<<<<<<<<<<<<<<<<<<<<<< OnRemovableDriveStatusChanged("USB Removed"); } } return DefWindowProc(hWnd, msg, wparam, lparam); } public delegate IntPtr WndProc( IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); // Preventing garbage collection of the delegate private static WndProc dontGCthis; /// <summary> /// Default Constructor /// </summary> public RemovableDriveMonitor() { WNDCLASS wc = new WNDCLASS(); // Preventing garbage collection of the delegate dontGCthis = new WndProc(Callback); wc.lpfnWndProc = dontGCthis; // Note that you need to ensure unique names // for each registered class. // For example, if you open the same plugin // in two different tabs of the browser, // you still should not end up with // two registered classes with identical names. wc.lpszClassName = "foobar" + (new Random()).Next(); RegisterClass(wc); IntPtr createResult = CreateWindowEx(0, wc.lpszClassName, "Window title", 0, 100, 100, 500, 500, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0); } } }
This uses a class RemovableDriveDetectionArgs:
public class RemovableDriveDetectionArgs { public string Message { get; set; } public RemovableDriveDetectionArgs(string msg) { this.Message = msg; } }
In your app, add an instance of RemoveDriveMonitor:
/// <summary> /// local member holding an instance of RemoveDriveMonitor in the host app/page/usercontrol /// </summary> private RemovableDriveMonitor usbMonitor = null;
Then make sure you create an instance of RemovableDriveMonitor and subscribe to the RemovableDriveStatusChanged event:
usbMonitor = new RemovableDriveMonitor(); usbMonitor.RemovableDriveStatusChanged += new RemovableDriveMonitor.RemovableDriveMonitorHandle (usbMonitor_RemovableDriveStatusChanged);
Implement an event sink function like so and present the e.Message in your UI:
void usbMonitor_RemovableDriveStatusChanged(object sender, RemovableDriveDetectionArgs e) { usbMonitorStatusWidget.Text = e.Message; }
0
-