Friday, February 6, 2009

Windows service detecting USB

When i got a chance to create an application on USB detection i used WndProc method which will be receiving the Windows Messages. But in the case of a service creation it never helped me . Then i went through other message tracking part which was quiet interesting .
here i m loading my exe whenever a USB is inserted . The exe path is being read from my registry .



using System;
using System.IO;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Diagnostics;
using Microsoft.Win32;
namespace USBDetectionService
{
public partial class Service1 : ServiceBase
{
#region Fields
private FileSystemWatcher fileSystemWatcher;
private IntPtr deviceNotifyHandle;
private IntPtr directoryHandle;
private Win32.ServiceControlHandlerEx myCallback;

#endregion

#region USB Detection

private int ServiceControlHandler(int control, int eventType, IntPtr eventData, IntPtr context)
{
if (control == Win32.SERVICE_CONTROL_STOP || control == Win32.SERVICE_CONTROL_SHUTDOWN)
{
UnregisterHandles();
Win32.UnregisterDeviceNotification(this.ServiceHandle);

base.Stop();
}
else if (control == Win32.SERVICE_CONTROL_DEVICEEVENT)
{
switch (eventType)
{
case Win32.DBT_DEVICEARRIVAL:
try
{
Registry.LocalMachine.OpenSubKey("SOFTWARE", true);
RegistryKey masterKey = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\FlukeAppPath");
string strProcessName = "";
if (masterKey != null)
{
strProcessName = masterKey.GetValue("PATH").ToString();
string strExeName = System.IO.Path.GetFileName(strProcessName);
strExeName = strExeName.Substring(0, strExeName.Length - 4);
Process[] pname = Process.GetProcessesByName(strExeName);
if (pname.Length == 0)
{
Process.Start(strProcessName);
}
}
masterKey.Close();
}
catch (Exception e)
{
}
break;

case Win32.DBT_DEVICEQUERYREMOVE:
UnregisterHandles();
fileSystemWatcher.EnableRaisingEvents = false;
break;
}
}

return 0;
}

private void UnregisterHandles()
{
if (directoryHandle != IntPtr.Zero)
{
Win32.CloseHandle(directoryHandle);
directoryHandle = IntPtr.Zero;
}
if (deviceNotifyHandle != IntPtr.Zero)
{
Win32.UnregisterDeviceNotification(deviceNotifyHandle);
deviceNotifyHandle = IntPtr.Zero;
}
}

private void RegisterForHandle(char c)
{
Win32.DEV_BROADCAST_HANDLE deviceHandle = new Win32.DEV_BROADCAST_HANDLE();
int size = Marshal.SizeOf(deviceHandle);
deviceHandle.dbch_size = size;
deviceHandle.dbch_devicetype = Win32.DBT_DEVTYP_HANDLE;
directoryHandle = CreateFileHandle(c + ":\\");
deviceHandle.dbch_handle = directoryHandle;
IntPtr buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(deviceHandle, buffer, true);
deviceNotifyHandle = Win32.RegisterDeviceNotification(this.ServiceHandle, buffer, Win32.DEVICE_NOTIFY_SERVICE_HANDLE);
if (deviceNotifyHandle == IntPtr.Zero)
{
// TODO handle error
}
}

private void RegisterDeviceNotification()
{
myCallback = new Win32.ServiceControlHandlerEx(ServiceControlHandler);
Win32.RegisterServiceCtrlHandlerEx(this.ServiceName, myCallback, IntPtr.Zero);

if (this.ServiceHandle == IntPtr.Zero)
{
// TODO handle error
}

Win32.DEV_BROADCAST_DEVICEINTERFACE deviceInterface = new Win32.DEV_BROADCAST_DEVICEINTERFACE();
int size = Marshal.SizeOf(deviceInterface);
deviceInterface.dbcc_size = size;
deviceInterface.dbcc_devicetype = Win32.DBT_DEVTYP_DEVICEINTERFACE;
IntPtr buffer = default(IntPtr);
buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(deviceInterface, buffer, true);
IntPtr r = default(IntPtr);
r = Win32.RegisterDeviceNotification(this.ServiceHandle, buffer, Win32.DEVICE_NOTIFY_SERVICE_HANDLE | Win32.DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
if (r == IntPtr.Zero)
{
// TODO handle error
}
}

#endregion

public Service1()
{
InitializeComponent();
}

#region Events

void fileSystemWatcher_Created(object sender, System.IO.FileSystemEventArgs e)
{
// TODO handle event
}

void fileSystemWatcher_Renamed(object sender, System.IO.RenamedEventArgs e)
{
// TODO handle event
}

void fileSystemWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
// TODO handle event
}

void fileSystemWatcher_Deleted(object sender, System.IO.FileSystemEventArgs e)
{
// TODO handle event
}

#endregion

#region Private Helper Methods

public static IntPtr CreateFileHandle(string driveLetter)
{
// open the existing file for reading
IntPtr handle = Win32.CreateFile(
driveLetter,
Win32.GENERIC_READ,
Win32.FILE_SHARE_READ | Win32.FILE_SHARE_WRITE,
0,
Win32.OPEN_EXISTING,
Win32.FILE_FLAG_BACKUP_SEMANTICS | Win32.FILE_ATTRIBUTE_NORMAL,
0);

if (handle == Win32.INVALID_HANDLE_VALUE)
{
return IntPtr.Zero;
}
else
{
return handle;
}
}

#endregion

#region ServiceBase Implementation

protected override void OnStart(string[] args)
{
base.OnStart(args);

RegisterDeviceNotification();

fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Created += new System.IO.FileSystemEventHandler(fileSystemWatcher_Created);
fileSystemWatcher.Deleted += new System.IO.FileSystemEventHandler(fileSystemWatcher_Deleted);
fileSystemWatcher.Changed += new System.IO.FileSystemEventHandler(fileSystemWatcher_Changed);
fileSystemWatcher.Renamed += new System.IO.RenamedEventHandler(fileSystemWatcher_Renamed);
}

#endregion
}

public class Win32
{
public const int DEVICE_NOTIFY_SERVICE_HANDLE = 1;
public const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4;

public const int SERVICE_CONTROL_STOP = 1;
public const int SERVICE_CONTROL_DEVICEEVENT = 11;
public const int SERVICE_CONTROL_SHUTDOWN = 5;

public const uint GENERIC_READ = 0x80000000;
public const uint OPEN_EXISTING = 3;
public const uint FILE_SHARE_READ = 1;
public const uint FILE_SHARE_WRITE = 2;
public const uint FILE_SHARE_DELETE = 4;
public const uint FILE_ATTRIBUTE_NORMAL = 128;
public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

public const int DBT_DEVTYP_DEVICEINTERFACE = 5;
public const int DBT_DEVTYP_HANDLE = 6;

public const int DBT_DEVICEARRIVAL = 0x8000;
public const int DBT_DEVICEQUERYREMOVE = 0x8001;
public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;

public const int WM_DEVICECHANGE = 0x219;

public delegate int ServiceControlHandlerEx(int control, int eventType, IntPtr eventData, IntPtr context);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern IntPtr RegisterServiceCtrlHandlerEx(string lpServiceName, ServiceControlHandlerEx cbex, IntPtr context);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVolumePathNamesForVolumeNameW(
[MarshalAs(UnmanagedType.LPWStr)]
string lpszVolumeName,
[MarshalAs(UnmanagedType.LPWStr)]
string lpszVolumePathNames,
uint cchBuferLength,
ref UInt32 lpcchReturnLength);

[DllImport("kernel32.dll")]
public static extern bool GetVolumeNameForVolumeMountPoint(string
lpszVolumeMountPoint, [Out] StringBuilder lpszVolumeName,
uint cchBufferLength);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr RegisterDeviceNotification(IntPtr IntPtr, IntPtr NotificationFilter, Int32 Flags);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern uint UnregisterDeviceNotification(IntPtr hHandle);

[DllImport("kernel32.dll", SetLastError = true)]
public 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.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DEV_BROADCAST_DEVICEINTERFACE
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)]
public byte[] dbcc_classguid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] dbcc_name;
}

[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_HDR
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
}

[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;
public byte dbch_data1;
}
}
}