JackOfPH
asked on
Detect if a usb device was inserted.
Hi,
Is there any other way to detect when a USB drives was inserted or deleted without the use of wmi or systeminfo of vb6?
If there is an alternative, I will raise the points to 500.
I am using visual basic 2005.
Thanks,
Jack.
Is there any other way to detect when a USB drives was inserted or deleted without the use of wmi or systeminfo of vb6?
If there is an alternative, I will raise the points to 500.
I am using visual basic 2005.
Thanks,
Jack.
ASKER
Hi,
Please have it converted?
I really do not know how to convert it in vb. I do not know how to use c#...
thanks.
Jack.
PS.
Sorry for the inconvinience. I can't find away to convert it. Jack
Please have it converted?
I really do not know how to convert it in vb. I do not know how to use c#...
thanks.
Jack.
PS.
Sorry for the inconvinience. I can't find away to convert it. Jack
ASKER
Will try...
ASKER
Classes can inherit only from other classes.
'Public Event DeviceArrived(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
'Public Event QueryRemove(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
'Public Event DeviceRemoved(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
Can't make it run. having this error.
'Public Event DeviceArrived(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
'Public Event QueryRemove(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
'Public Event DeviceRemoved(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
Can't make it run. having this error.
do like this
RaiseEvent New DeviceArrived(this, new DriveDetectorEventArgs(etc ...
RaiseEvent New DeviceArrived(this, new DriveDetectorEventArgs(etc
ASKER
Is this in vb?
copy the code converted you got here i will modify it
ASKER
Dim tempDeviceArrived As DriveDetectorEventHandler = DeviceArrived
This is the line that gives the error...
This is the line that gives the error...
ASKER
This is the generated code from the link you had given...
Have a look...
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Forms
' required for Message
Imports System.Runtime.InteropServ ices
' required for Marshal
Imports System.IO
Imports Microsoft.Win32.SafeHandle s
Namespace Dolinay
' Delegate for event handler to handle the device events
Public Delegate Sub DriveDetectorEventHandler( ByVal sender As Object, ByVal e As DriveDetectorEventArgs)
''' <summary>
''' Our class for passing in custom arguments to our event handlers
'''
''' </summary>
Public Class DriveDetectorEventArgs
Inherits EventArgs
''' <summary>
''' Get/Set the value indicating that the event should be cancelled
''' Only in QueryRemove handler.
''' </summary>
Public Cancel As Boolean
''' <summary>
''' Drive letter for the device which caused this event
''' </summary>
Public Drive As String
''' <summary>
''' Set to true in your DeviceArrived event handler if you wish to receive the
''' QueryRemove event for this drive.
''' </summary>
Public HookQueryRemove As Boolean
Public Sub New()
MyBase.New()
Cancel = False
Drive = ""
HookQueryRemove = False
End Sub
End Class
''' <summary>
''' Detects insertion or removal of removable drives.
''' Use it in 2 steps:
''' 1) Create instance of this class in your project and add handlers for the
''' DeviceArrived, DeviceRemoved and QueryRemove events.
''' 2) Override WndProc in your form and call DriveDetector's WndProc from there.
''' </summary>
Class DriveDetector
Inherits IDisposable
''' <summary>
''' Class which contains also handle to the file opened on the flash drive
''' </summary>
Private mFileOnFlash As FileStream = Nothing
''' <summary>
''' Name of the file to try to open on the removable drive for query remove registration
''' </summary>
Private mFileToOpen As String
''' <summary>
''' Handle to file which we keep opened on the drive if query remove message is required by the client
''' </summary>
Private mDeviceNotifyHandle As IntPtr
''' <summary>
''' Handle of the window which receives messages from Windows. This will be a form.
''' </summary>
Private mRecipientHandle As IntPtr
''' <summary>
''' Drive which is currently hooked for query remove
''' </summary>
Private mCurrentDrive As String
' Win32 constants
Private Const DBT_DEVTYP_DEVICEINTERFACE As Integer = 5
Private Const DBT_DEVTYP_HANDLE As Integer = 6
Private Const BROADCAST_QUERY_DENY As Integer = 1112363332
Private Const WM_DEVICECHANGE As Integer = 537
Private Const DBT_DEVICEARRIVAL As Integer = 32768
' system detected a new device
Private Const DBT_DEVICEQUERYREMOVE As Integer = 32769
' Preparing to remove (any program can disable the removal)
Private Const DBT_DEVICEREMOVECOMPLETE As Integer = 32772
' removed
Private Const DBT_DEVTYP_VOLUME As Integer = 2
''' <summary>
''' Default constructor.
''' </summary>
''' <param name="control">object which will receive Windows messages.
''' Pass "this" as this argument from your form class.</param>
Public Sub New(ByVal control As Control)
MyBase.New()
mFileToOpen = Nothing
mDeviceNotifyHandle = IntPtr.Zero
mRecipientHandle = control.Handle
mCurrentDrive = ""
End Sub
''' <summary>
''' Consructs DriveDetector object setting also path to file which should be opened
''' when registering for query remove.
''' </summary>
'''<param name="control">object which will receive Windows messages.
''' Pass "this" as this argument from your form class.</param>
''' <param name="FileToOpen">Optional . Name of a file on the removable drive which should be opened.
''' If null, any file on the drive will be opened. Opening a file is needed for us
''' to be able to register for the query remove message. TIP: Use relative path without drive letter.
''' e.g. "SomeFolder\file_on_flash. txt"</para m>
Public Sub New(ByVal control As Control, ByVal FileToOpen As String)
MyBase.New()
mFileToOpen = FileToOpen
mDeviceNotifyHandle = IntPtr.Zero
mRecipientHandle = control.Handle
mCurrentDrive = ""
End Sub
''' <summary>
''' Gets the value indicating whether the query remove event will be fired.
''' </summary>
Public ReadOnly Property IsQueryHooked() As Boolean
Get
If (mDeviceNotifyHandle = IntPtr.Zero) Then
Return False
Else
Return True
End If
End Get
End Property
''' <summary>
''' Gets letter of drive which is currently hooked. Empty string if none.
''' See also IsQueryHooked.
''' </summary>
Public ReadOnly Property HookedDrive() As String
Get
Return mCurrentDrive
End Get
End Property
''' <summary>
''' Gets the file stream for file which this class opened on a drive to be notified
''' about it's removal.
''' </summary>
Public ReadOnly Property OpenedFile() As FileStream
Get
Return mFileOnFlash
End Get
End Property
''' <summary>
''' Events signalized to the client app.
''' Add handlers for these events in your form to be notified of removable device events
''' </summary>
Public Event DeviceArrived As DriveDetectorEventHandler
Public Event DeviceRemoved As DriveDetectorEventHandler
Public Event QueryRemove As DriveDetectorEventHandler
''' <summary>
''' Hooks specified drive to receive a message when it is being removed.
''' This can be achieved also by setting e.HookQueryRemove to true in your
''' DeviceArrived event handler. In that case mFileToOpen (which can be set using second constructor)
''' is used as the file to open.
''' </summary>
''' <param name="fileOnDrive">drive letter or relative path to a file on the drive which should be
''' used to get a handle - required for registering to receive query remove messages.
''' If only drive letter is specified (e.g. "D:\\", any file found on the flash drive can be used.</param>
''' <returns>true if hooked ok, false otherwise</returns>
Public Function EnableQueryRemove(ByVal fileOnDrive As String) As Boolean
If ((fileOnDrive = Nothing) _
OrElse (fileOnDrive.Length = 0)) Then
Throw New ArgumentException("Drive path must be supplied to register for Query remove.")
End If
If ((fileOnDrive.Length = 2) _
AndAlso (fileOnDrive(1) = Microsoft.VisualBasic.ChrW (58))) Then
fileOnDrive = (fileOnDrive + Microsoft.VisualBasic.ChrW (92))
End If
' append "\\" if only drive letter with ":" was passed in.
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
RegisterForDeviceChange(Fa lse, Nothing)
End If
If Not File.Exists(fileOnDrive) Then
mFileToOpen = Nothing
End If
' use any file
mFileToOpen = fileOnDrive
RegisterQuery(Path.GetPath Root(fileO nDrive))
If (mDeviceNotifyHandle = IntPtr.Zero) Then
Return False
End If
' failed to register
Return True
End Function
''' <summary>
''' Unhooks any currently hooked drive so that the query remove
''' message is not generated for it.
''' </summary>
Public Sub DisableQueryRemove()
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
RegisterForDeviceChange(Fa lse, Nothing)
End If
End Sub
''' <summary>
''' Unregister and close the file we may have opened on the removable drive.
''' Garbage collector will call this method.
''' </summary>
Public Sub Dispose()
RegisterForDeviceChange(Fa lse, Nothing)
End Sub
''' <summary>
''' Message handler which must be called from client form.
''' Processes Windows messages and calls event handlers.
''' </summary>
''' <param name="m"></param>
Public Sub WndProc(ByRef m As Message)
Dim devType As Integer
Dim c As Char
If (m.Msg = WM_DEVICECHANGE) Then
' WM_DEVICECHANGE can have several meanings depending on the WParam value...
Select Case (m.WParam.ToInt32)
Case DBT_DEVICEARRIVAL
devType = Marshal.ReadInt32(m.LParam , 4)
If (devType = DBT_DEVTYP_VOLUME) Then
Dim vol As DEV_BROADCAST_VOLUME
vol = CType(Marshal.PtrToStructu re(m.LPara m, GetType(DEV_BROADCAST_VOLU ME)), 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
Dim tempDeviceArrived As DriveDetectorEventHandler = DeviceArrived
If (Not (tempDeviceArrived) Is Nothing) Then
Dim e As DriveDetectorEventArgs = New DriveDetectorEventArgs
e.Drive = (c + ":\\")
tempDeviceArrived(Me, e)
' Register for query remove if requested
If e.HookQueryRemove Then
' If something is already hooked, unhook it now
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
RegisterForDeviceChange(Fa lse, Nothing)
End If
RegisterQuery((c + ":\\"))
End If
End If
' if has event handler
End If
Case DBT_DEVICEQUERYREMOVE
devType = Marshal.ReadInt32(m.LParam , 4)
If (devType = DBT_DEVTYP_HANDLE) Then
' TODO: we could get the handle for which this message is sent
' from vol.dbch_handle and compare it agains a list of handles for
' which we have registered the query remove message (?)
'DEV_BROADCAST_HANDLE vol;
'vol = (DEV_BROADCAST_HANDLE)
' Marshal.PtrToStructure(m.L Param, typeof(DEV_BROADCAST_HANDL E));
' if ( vol.dbch_handle ....
'
' Call the event handler in client
'
Dim tempQuery As DriveDetectorEventHandler = QueryRemove
If (Not (tempQuery) Is Nothing) Then
Dim e As DriveDetectorEventArgs = New DriveDetectorEventArgs
e.Drive = mCurrentDrive
' drive which is hooked
tempQuery(Me, e)
' If the client wants to cancel, let Windows know
If e.Cancel Then
m.Result = CType(BROADCAST_QUERY_DENY , IntPtr)
Else
' Close the handle so that the drive can be unmounted
If (Not (mFileOnFlash) Is Nothing) Then
mFileOnFlash.Close()
mFileOnFlash = Nothing
End If
End If
End If
End If
Case DBT_DEVICEREMOVECOMPLETE
devType = Marshal.ReadInt32(m.LParam , 4)
If (devType = DBT_DEVTYP_VOLUME) Then
devType = Marshal.ReadInt32(m.LParam , 4)
If (devType = DBT_DEVTYP_VOLUME) Then
Dim vol As DEV_BROADCAST_VOLUME
vol = CType(Marshal.PtrToStructu re(m.LPara m, GetType(DEV_BROADCAST_VOLU ME)), DEV_BROADCAST_VOLUME)
c = DriveMaskToLetter(vol.dbcv _unitmask)
'
' Call the client event handler
'
Dim tempDeviceRemoved As DriveDetectorEventHandler = DeviceRemoved
If (Not (tempDeviceRemoved) Is Nothing) Then
Dim e As DriveDetectorEventArgs = New DriveDetectorEventArgs
e.Drive = (c + ":\\")
tempDeviceRemoved(Me, e)
End If
' TODO: we could unregister the notify handle here if we knew it is the
' right drive which has been just removed
'RegisterForDeviceChange(f alse, null);
End If
End If
End Select
End If
End Sub
' drive type is logical volume
''' <summary>
''' Registers for receiving the query remove message for a given drive.
''' We need to open a handle on that drive and register with this handle.
''' CLient can specify this file in mFileToOpen or we will use any file we fing on the drive
''' </summary>
''' <param name="drive">drive for which to register. </param>
Private Sub RegisterQuery(ByVal drive As String)
Dim register As Boolean = True
If (mFileToOpen = Nothing) Then
' If client gave us no file, let's pick one on the drive...
mFileToOpen = GetAnyFile(drive)
If (mFileToOpen.Length = 0) Then
Return
End If
' no file found on the flash drive
Else
' 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 mFileToOpen.Contains(":") Then
Dim tmp As String = mFileToOpen.Substring(3)
Dim root As String = Path.GetPathRoot(drive)
mFileToOpen = Path.Combine(root, tmp)
Else
mFileToOpen = Path.Combine(drive, mFileToOpen)
End If
End If
Try
mFileOnFlash = New FileStream(mFileToOpen, FileMode.Open)
Catch ex As Exception
' just do not register if the file could not be opened
register = False
End Try
If register Then
RegisterForDeviceChange(Tr ue, mFileOnFlash.SafeFileHandl e)
mCurrentDrive = drive
End If
End Sub
''' <summary>
''' Registers to be notified when the volume is about to be removed
''' This is requierd if you want to get the QUERY REMOVE messages
''' </summary>
''' <param name="register">true to register, false to unregister</param>
''' <param name="fileHandle">handle of a file opened on the removable drive</param>
Private Sub RegisterForDeviceChange(By Val register As Boolean, ByVal fileHandle As SafeFileHandle)
If register Then
' Register for handle
Dim data As DEV_BROADCAST_HANDLE = New DEV_BROADCAST_HANDLE
data.dbch_devicetype = DBT_DEVTYP_HANDLE
data.dbch_reserved = 0
data.dbch_nameoffset = 0
'data.dbch_data = null;
'data.dbch_eventguid = 0;
data.dbch_handle = fileHandle.DangerousGetHan dle
'Marshal. fileHandle;
data.dbch_hdevnotify = CType(0, IntPtr)
Dim size As Integer = Marshal.SizeOf(data)
data.dbch_size = size
Dim buffer As IntPtr = Marshal.AllocHGlobal(size)
Marshal.StructureToPtr(dat a, buffer, True)
mDeviceNotifyHandle = Native.RegisterDeviceNotif ication(mR ecipientHa ndle, buffer, 0)
Else
' unregister
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
Native.UnregisterDeviceNot ification( mDeviceNot ifyHandle)
End If
mDeviceNotifyHandle = IntPtr.Zero
mCurrentDrive = ""
If (Not (mFileOnFlash) Is Nothing) Then
mFileOnFlash.Close()
mFileOnFlash = Nothing
End If
End If
End Sub
''' <summary>
''' Gets drive letter from a bit mask where bit 0 = A, bit 1 = B etc.
''' There can actually be more than one drive in the mask but we
''' just use the last one in this case.
''' </summary>
''' <param name="mask"></param>
''' <returns></returns>
Private Shared Function DriveMaskToLetter(ByVal mask As Integer) As Char
Dim letter As Char
Dim drives As String = "ABCDEFGHIJKLMNOPQRSTUVWXY Z"
' 1 = A
' 2 = B
' 4 = C...
Dim cnt As Integer = 0
Dim pom As Integer = (mask / 2)
While (pom <> 0)
' while there is any bit set in the mask
' shift it to the righ...
pom = (pom / 2)
cnt = (cnt + 1)
End While
If (cnt < drives.Length) Then
letter = drives(cnt)
Else
letter = Microsoft.VisualBasic.ChrW (63)
End If
Return letter
End Function
''' <summary>
''' Searches for any file in a given path and returns its full path
''' </summary>
''' <param name="drive">drive to search</param>
''' <returns>path of the file or empty string</returns>
Private Function GetAnyFile(ByVal drive As String) As String
Dim file As String = ""
' First try files in the root
Dim files() As String = Directory.GetFiles(drive)
If (files.Length = 0) Then
' if no file in the root, search whole drive
files = Directory.GetFiles(drive, "*.*", SearchOption.AllDirectorie s)
End If
If (files.Length > 0) Then
file = files(0)
End If
' get the first file
' return empty string if no file found
Return file
End Function
''' <summary>
''' WinAPI functions
''' </summary>
Private Class Native
' HDEVNOTIFY RegisterDeviceNotification (HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags);
Public Declare Function RegisterDeviceNotification Lib "user32.dll" (ByVal hRecipient As IntPtr, ByVal NotificationFilter As IntPtr, ByVal Flags As UInteger) As IntPtr
Public Declare Function UnregisterDeviceNotificati on Lib "user32.dll" (ByVal hHandle As IntPtr) As UInteger
End Class
' Structure with information for RegisterDeviceNotification .
<StructLayout(LayoutKind.S equential) > _
Public Structure DEV_BROADCAST_HANDLE
Public dbch_size As Integer
Public dbch_devicetype As Integer
Public dbch_reserved As Integer
Public dbch_handle As IntPtr
Public dbch_hdevnotify As IntPtr
Public dbch_eventguid As Guid
Public dbch_nameoffset As Long
'public byte[] dbch_data[1]; // = new byte[1];
Public dbch_data As Byte
Public dbch_data1 As Byte
End Structure
' Struct for parameters of the WM_DEVICECHANGE message
<StructLayout(LayoutKind.S equential) > _
Public Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Integer
Public dbcv_devicetype As Integer
Public dbcv_reserved As Integer
Public dbcv_unitmask As Integer
End Structure
End Class
End Namespace
Have a look...
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Forms
' required for Message
Imports System.Runtime.InteropServ
' required for Marshal
Imports System.IO
Imports Microsoft.Win32.SafeHandle
Namespace Dolinay
' Delegate for event handler to handle the device events
Public Delegate Sub DriveDetectorEventHandler(
''' <summary>
''' Our class for passing in custom arguments to our event handlers
'''
''' </summary>
Public Class DriveDetectorEventArgs
Inherits EventArgs
''' <summary>
''' Get/Set the value indicating that the event should be cancelled
''' Only in QueryRemove handler.
''' </summary>
Public Cancel As Boolean
''' <summary>
''' Drive letter for the device which caused this event
''' </summary>
Public Drive As String
''' <summary>
''' Set to true in your DeviceArrived event handler if you wish to receive the
''' QueryRemove event for this drive.
''' </summary>
Public HookQueryRemove As Boolean
Public Sub New()
MyBase.New()
Cancel = False
Drive = ""
HookQueryRemove = False
End Sub
End Class
''' <summary>
''' Detects insertion or removal of removable drives.
''' Use it in 2 steps:
''' 1) Create instance of this class in your project and add handlers for the
''' DeviceArrived, DeviceRemoved and QueryRemove events.
''' 2) Override WndProc in your form and call DriveDetector's WndProc from there.
''' </summary>
Class DriveDetector
Inherits IDisposable
''' <summary>
''' Class which contains also handle to the file opened on the flash drive
''' </summary>
Private mFileOnFlash As FileStream = Nothing
''' <summary>
''' Name of the file to try to open on the removable drive for query remove registration
''' </summary>
Private mFileToOpen As String
''' <summary>
''' Handle to file which we keep opened on the drive if query remove message is required by the client
''' </summary>
Private mDeviceNotifyHandle As IntPtr
''' <summary>
''' Handle of the window which receives messages from Windows. This will be a form.
''' </summary>
Private mRecipientHandle As IntPtr
''' <summary>
''' Drive which is currently hooked for query remove
''' </summary>
Private mCurrentDrive As String
' Win32 constants
Private Const DBT_DEVTYP_DEVICEINTERFACE
Private Const DBT_DEVTYP_HANDLE As Integer = 6
Private Const BROADCAST_QUERY_DENY As Integer = 1112363332
Private Const WM_DEVICECHANGE As Integer = 537
Private Const DBT_DEVICEARRIVAL As Integer = 32768
' system detected a new device
Private Const DBT_DEVICEQUERYREMOVE As Integer = 32769
' Preparing to remove (any program can disable the removal)
Private Const DBT_DEVICEREMOVECOMPLETE As Integer = 32772
' removed
Private Const DBT_DEVTYP_VOLUME As Integer = 2
''' <summary>
''' Default constructor.
''' </summary>
''' <param name="control">object which will receive Windows messages.
''' Pass "this" as this argument from your form class.</param>
Public Sub New(ByVal control As Control)
MyBase.New()
mFileToOpen = Nothing
mDeviceNotifyHandle = IntPtr.Zero
mRecipientHandle = control.Handle
mCurrentDrive = ""
End Sub
''' <summary>
''' Consructs DriveDetector object setting also path to file which should be opened
''' when registering for query remove.
''' </summary>
'''<param name="control">object which will receive Windows messages.
''' Pass "this" as this argument from your form class.</param>
''' <param name="FileToOpen">Optional
''' If null, any file on the drive will be opened. Opening a file is needed for us
''' to be able to register for the query remove message. TIP: Use relative path without drive letter.
''' e.g. "SomeFolder\file_on_flash.
Public Sub New(ByVal control As Control, ByVal FileToOpen As String)
MyBase.New()
mFileToOpen = FileToOpen
mDeviceNotifyHandle = IntPtr.Zero
mRecipientHandle = control.Handle
mCurrentDrive = ""
End Sub
''' <summary>
''' Gets the value indicating whether the query remove event will be fired.
''' </summary>
Public ReadOnly Property IsQueryHooked() As Boolean
Get
If (mDeviceNotifyHandle = IntPtr.Zero) Then
Return False
Else
Return True
End If
End Get
End Property
''' <summary>
''' Gets letter of drive which is currently hooked. Empty string if none.
''' See also IsQueryHooked.
''' </summary>
Public ReadOnly Property HookedDrive() As String
Get
Return mCurrentDrive
End Get
End Property
''' <summary>
''' Gets the file stream for file which this class opened on a drive to be notified
''' about it's removal.
''' </summary>
Public ReadOnly Property OpenedFile() As FileStream
Get
Return mFileOnFlash
End Get
End Property
''' <summary>
''' Events signalized to the client app.
''' Add handlers for these events in your form to be notified of removable device events
''' </summary>
Public Event DeviceArrived As DriveDetectorEventHandler
Public Event DeviceRemoved As DriveDetectorEventHandler
Public Event QueryRemove As DriveDetectorEventHandler
''' <summary>
''' Hooks specified drive to receive a message when it is being removed.
''' This can be achieved also by setting e.HookQueryRemove to true in your
''' DeviceArrived event handler. In that case mFileToOpen (which can be set using second constructor)
''' is used as the file to open.
''' </summary>
''' <param name="fileOnDrive">drive letter or relative path to a file on the drive which should be
''' used to get a handle - required for registering to receive query remove messages.
''' If only drive letter is specified (e.g. "D:\\", any file found on the flash drive can be used.</param>
''' <returns>true if hooked ok, false otherwise</returns>
Public Function EnableQueryRemove(ByVal fileOnDrive As String) As Boolean
If ((fileOnDrive = Nothing) _
OrElse (fileOnDrive.Length = 0)) Then
Throw New ArgumentException("Drive path must be supplied to register for Query remove.")
End If
If ((fileOnDrive.Length = 2) _
AndAlso (fileOnDrive(1) = Microsoft.VisualBasic.ChrW
fileOnDrive = (fileOnDrive + Microsoft.VisualBasic.ChrW
End If
' append "\\" if only drive letter with ":" was passed in.
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
RegisterForDeviceChange(Fa
End If
If Not File.Exists(fileOnDrive) Then
mFileToOpen = Nothing
End If
' use any file
mFileToOpen = fileOnDrive
RegisterQuery(Path.GetPath
If (mDeviceNotifyHandle = IntPtr.Zero) Then
Return False
End If
' failed to register
Return True
End Function
''' <summary>
''' Unhooks any currently hooked drive so that the query remove
''' message is not generated for it.
''' </summary>
Public Sub DisableQueryRemove()
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
RegisterForDeviceChange(Fa
End If
End Sub
''' <summary>
''' Unregister and close the file we may have opened on the removable drive.
''' Garbage collector will call this method.
''' </summary>
Public Sub Dispose()
RegisterForDeviceChange(Fa
End Sub
''' <summary>
''' Message handler which must be called from client form.
''' Processes Windows messages and calls event handlers.
''' </summary>
''' <param name="m"></param>
Public Sub WndProc(ByRef m As Message)
Dim devType As Integer
Dim c As Char
If (m.Msg = WM_DEVICECHANGE) Then
' WM_DEVICECHANGE can have several meanings depending on the WParam value...
Select Case (m.WParam.ToInt32)
Case DBT_DEVICEARRIVAL
devType = Marshal.ReadInt32(m.LParam
If (devType = DBT_DEVTYP_VOLUME) Then
Dim vol As DEV_BROADCAST_VOLUME
vol = CType(Marshal.PtrToStructu
' Get the drive letter
c = DriveMaskToLetter(vol.dbcv
'
' Call the client event handler
'
' We should create copy of the event before testing it and
' calling the delegate - if any
Dim tempDeviceArrived As DriveDetectorEventHandler = DeviceArrived
If (Not (tempDeviceArrived) Is Nothing) Then
Dim e As DriveDetectorEventArgs = New DriveDetectorEventArgs
e.Drive = (c + ":\\")
tempDeviceArrived(Me, e)
' Register for query remove if requested
If e.HookQueryRemove Then
' If something is already hooked, unhook it now
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
RegisterForDeviceChange(Fa
End If
RegisterQuery((c + ":\\"))
End If
End If
' if has event handler
End If
Case DBT_DEVICEQUERYREMOVE
devType = Marshal.ReadInt32(m.LParam
If (devType = DBT_DEVTYP_HANDLE) Then
' TODO: we could get the handle for which this message is sent
' from vol.dbch_handle and compare it agains a list of handles for
' which we have registered the query remove message (?)
'DEV_BROADCAST_HANDLE vol;
'vol = (DEV_BROADCAST_HANDLE)
' Marshal.PtrToStructure(m.L
' if ( vol.dbch_handle ....
'
' Call the event handler in client
'
Dim tempQuery As DriveDetectorEventHandler = QueryRemove
If (Not (tempQuery) Is Nothing) Then
Dim e As DriveDetectorEventArgs = New DriveDetectorEventArgs
e.Drive = mCurrentDrive
' drive which is hooked
tempQuery(Me, e)
' If the client wants to cancel, let Windows know
If e.Cancel Then
m.Result = CType(BROADCAST_QUERY_DENY
Else
' Close the handle so that the drive can be unmounted
If (Not (mFileOnFlash) Is Nothing) Then
mFileOnFlash.Close()
mFileOnFlash = Nothing
End If
End If
End If
End If
Case DBT_DEVICEREMOVECOMPLETE
devType = Marshal.ReadInt32(m.LParam
If (devType = DBT_DEVTYP_VOLUME) Then
devType = Marshal.ReadInt32(m.LParam
If (devType = DBT_DEVTYP_VOLUME) Then
Dim vol As DEV_BROADCAST_VOLUME
vol = CType(Marshal.PtrToStructu
c = DriveMaskToLetter(vol.dbcv
'
' Call the client event handler
'
Dim tempDeviceRemoved As DriveDetectorEventHandler = DeviceRemoved
If (Not (tempDeviceRemoved) Is Nothing) Then
Dim e As DriveDetectorEventArgs = New DriveDetectorEventArgs
e.Drive = (c + ":\\")
tempDeviceRemoved(Me, e)
End If
' TODO: we could unregister the notify handle here if we knew it is the
' right drive which has been just removed
'RegisterForDeviceChange(f
End If
End If
End Select
End If
End Sub
' drive type is logical volume
''' <summary>
''' Registers for receiving the query remove message for a given drive.
''' We need to open a handle on that drive and register with this handle.
''' CLient can specify this file in mFileToOpen or we will use any file we fing on the drive
''' </summary>
''' <param name="drive">drive for which to register. </param>
Private Sub RegisterQuery(ByVal drive As String)
Dim register As Boolean = True
If (mFileToOpen = Nothing) Then
' If client gave us no file, let's pick one on the drive...
mFileToOpen = GetAnyFile(drive)
If (mFileToOpen.Length = 0) Then
Return
End If
' no file found on the flash drive
Else
' 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 mFileToOpen.Contains(":") Then
Dim tmp As String = mFileToOpen.Substring(3)
Dim root As String = Path.GetPathRoot(drive)
mFileToOpen = Path.Combine(root, tmp)
Else
mFileToOpen = Path.Combine(drive, mFileToOpen)
End If
End If
Try
mFileOnFlash = New FileStream(mFileToOpen, FileMode.Open)
Catch ex As Exception
' just do not register if the file could not be opened
register = False
End Try
If register Then
RegisterForDeviceChange(Tr
mCurrentDrive = drive
End If
End Sub
''' <summary>
''' Registers to be notified when the volume is about to be removed
''' This is requierd if you want to get the QUERY REMOVE messages
''' </summary>
''' <param name="register">true to register, false to unregister</param>
''' <param name="fileHandle">handle of a file opened on the removable drive</param>
Private Sub RegisterForDeviceChange(By
If register Then
' Register for handle
Dim data As DEV_BROADCAST_HANDLE = New DEV_BROADCAST_HANDLE
data.dbch_devicetype = DBT_DEVTYP_HANDLE
data.dbch_reserved = 0
data.dbch_nameoffset = 0
'data.dbch_data = null;
'data.dbch_eventguid = 0;
data.dbch_handle = fileHandle.DangerousGetHan
'Marshal. fileHandle;
data.dbch_hdevnotify = CType(0, IntPtr)
Dim size As Integer = Marshal.SizeOf(data)
data.dbch_size = size
Dim buffer As IntPtr = Marshal.AllocHGlobal(size)
Marshal.StructureToPtr(dat
mDeviceNotifyHandle = Native.RegisterDeviceNotif
Else
' unregister
If (mDeviceNotifyHandle <> IntPtr.Zero) Then
Native.UnregisterDeviceNot
End If
mDeviceNotifyHandle = IntPtr.Zero
mCurrentDrive = ""
If (Not (mFileOnFlash) Is Nothing) Then
mFileOnFlash.Close()
mFileOnFlash = Nothing
End If
End If
End Sub
''' <summary>
''' Gets drive letter from a bit mask where bit 0 = A, bit 1 = B etc.
''' There can actually be more than one drive in the mask but we
''' just use the last one in this case.
''' </summary>
''' <param name="mask"></param>
''' <returns></returns>
Private Shared Function DriveMaskToLetter(ByVal mask As Integer) As Char
Dim letter As Char
Dim drives As String = "ABCDEFGHIJKLMNOPQRSTUVWXY
' 1 = A
' 2 = B
' 4 = C...
Dim cnt As Integer = 0
Dim pom As Integer = (mask / 2)
While (pom <> 0)
' while there is any bit set in the mask
' shift it to the righ...
pom = (pom / 2)
cnt = (cnt + 1)
End While
If (cnt < drives.Length) Then
letter = drives(cnt)
Else
letter = Microsoft.VisualBasic.ChrW
End If
Return letter
End Function
''' <summary>
''' Searches for any file in a given path and returns its full path
''' </summary>
''' <param name="drive">drive to search</param>
''' <returns>path of the file or empty string</returns>
Private Function GetAnyFile(ByVal drive As String) As String
Dim file As String = ""
' First try files in the root
Dim files() As String = Directory.GetFiles(drive)
If (files.Length = 0) Then
' if no file in the root, search whole drive
files = Directory.GetFiles(drive, "*.*", SearchOption.AllDirectorie
End If
If (files.Length > 0) Then
file = files(0)
End If
' get the first file
' return empty string if no file found
Return file
End Function
''' <summary>
''' WinAPI functions
''' </summary>
Private Class Native
' HDEVNOTIFY RegisterDeviceNotification
Public Declare Function RegisterDeviceNotification
Public Declare Function UnregisterDeviceNotificati
End Class
' Structure with information for RegisterDeviceNotification
<StructLayout(LayoutKind.S
Public Structure DEV_BROADCAST_HANDLE
Public dbch_size As Integer
Public dbch_devicetype As Integer
Public dbch_reserved As Integer
Public dbch_handle As IntPtr
Public dbch_hdevnotify As IntPtr
Public dbch_eventguid As Guid
Public dbch_nameoffset As Long
'public byte[] dbch_data[1]; // = new byte[1];
Public dbch_data As Byte
Public dbch_data1 As Byte
End Structure
' Struct for parameters of the WM_DEVICECHANGE message
<StructLayout(LayoutKind.S
Public Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Integer
Public dbcv_devicetype As Integer
Public dbcv_reserved As Integer
Public dbcv_unitmask As Integer
End Structure
End Class
End Namespace
ASKER
This are the errors:
1) Classes can inherit only from other classes.
2) Public Event DeviceArrived(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
3) Public Event QueryRemove(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
4) Public Event DeviceRemoved(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
1) Classes can inherit only from other classes.
2) Public Event DeviceArrived(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
3) Public Event QueryRemove(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
4) Public Event DeviceRemoved(sender As Object, e As DriveDetectorEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
here the link
http://www.codeproject.com/cs/system/DriveDetector.asp