-
Aug 7th, 2008, 06:48 PM
#1
[RESOLVED] Detecting Drive Letter of USB Drive
OK so this is kind of following on from someone else's thread that I am trying to help out with (http://www.vbforums.com/showthread.php?t=534932).
If you cant be bothered to read the other thread, here's a brief summary of what I (and the OP in that thread) would like to achieve:
When a USB drive is plugged in, the application automatically searches this drive for a specific file.
So to cut a long story short, this is what I have so far:
I am using VB.NET by the way, not VB6
vb.net Code:
Public Class Form1
Private Const WM_DEVICECHANGE As Integer = &H219
Private Const DBT_DEVICEARRIVAL As Integer = 32768
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
If m.WParam = DBT_DEVICEARRIVAL Then
MessageBox.Show("Removable Drive Detected")
End If
End If
MyBase.WndProc(m)
End Sub
End Class
This works in that when a USB drive is plugged in, it pops up with the messagebox. It took me a lot of trial and error and a lot of reading on the MSDN site to get even this much working (this is only the 3rd or 4th API I have ever tried to use) as there didnt seem to be much useful stuff on google... but anyway yeah, the problem is that its all well and good detecting that a drive was connected but now we need to be able to scan it. So we need to get the drive letter that was assigned to the newly connected drive - According to the MSDN site, the following is passed in through the lparam property of the DEVICECHANGE message:
A pointer to a structure identifying the device inserted. The structure consists of an event-independent header, followed by event-dependent members that describe the device. To use this structure, treat the structure as a DEV_BROADCAST_HDR structure, then check its dbch_devicetype member to determine the device type.
Looking at the DEV_BROADCAST_HDR structure and its dbch_devicetype member in particular I can see that I can check to see if the device is a Volume. Then if it is a volume I can check the DEV_BROADCAST_VOLUME structure member named dbcv_unitmask and this relates to the drive letter that is assigned. Hopefully I didnt explain that too badly... The problem is, like I said, I'm fairly new to APIs and so I havent got a clue how to do what I just explained!
I'm guessing I need to just declare each of these structures and then it will be fairly easy to use them in my managed code but none of the mentioned structures appear in my API Viewer program so I have no idea what type of object each member needs to be declared as etc
Anyone help me out?
Thanks
Chris
-
Aug 8th, 2008, 04:30 AM
#2
Re: Detecting Drive Letter of USB Drive
OK I got it working
Just in case anyone else ever wants to do a similar thing, here's my code:
EDIT: See updated code in post #13 for a better version
vb Code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Const WM_DEVICECHANGE As Integer = &H219
Private Const DBT_DEVICEARRIVAL As Integer = &H8000
Private Const DBT_DEVTYP_VOLUME As Integer = &H2
'Device information structure
Public Structure DEV_BROADCAST_HDR
Public dbch_size As Int32
Public dbch_devicetype As Int32
Public dbch_reserved As Int32
End Structure
'Volume information Structure
Private Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Int32
Public dbcv_devicetype As Int32
Public dbcv_reserved As Int32
Public dbcv_unitmask As Int32
Public dbcv_flags As Int16
End Structure
'<<<< Function that gets the drive letter from the unit mask >>>>
Private Function GetDriveLetterFromMask(ByRef Unit As Int32)
Dim i As Integer
For i = 0 To 25
If Unit And i Then Exit For
Unit = Unit >> 1
Next
Return Chr(i + 1 + Asc("A"))
End Function
'Override message processing to check for the DEVICECHANGE message
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
If m.WParam = DBT_DEVICEARRIVAL Then
Dim DeviceInfo As DEV_BROADCAST_HDR
DeviceInfo = Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_HDR))
If DeviceInfo.dbch_devicetype = DBT_DEVTYP_VOLUME Then
Dim Volume As DEV_BROADCAST_VOLUME
Volume = Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME))
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
Dim FileList() As String = IO.Directory.GetFiles(DriveLetter, "test.txt")
If FileList.Count > 0 Then
MessageBox.Show("Found Config File")
'<<<< The test file has been found >>>>
Else
MessageBox.Show("Could not find config file")
'<<<< Test file has not been found >>>>
End If
End If
End If
End If
MyBase.WndProc(m)
End Sub
End Class
Last edited by chris128; Nov 9th, 2009 at 05:44 PM.
-
Sep 30th, 2008, 11:06 AM
#3
New Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Hi. thanks for your code.
It gives me the wrong drive letter. if I use 1 usb pen, windows says its F: and the code says its G:. can you help me?
-
Sep 30th, 2008, 12:26 PM
#4
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Try replacing this part of the code:
vb Code:
'<<<< Function that gets the drive letter from the unit mask >>>>
Private Function GetDriveLetterFromMask(ByRef Unit As Int32)
Dim i As Integer
For i = 0 To 25
If Unit And i Then Exit For
Unit = Unit >> 1
Next
Return Chr(i + 1 + Asc("A"))
End Function
with this:
vb Code:
'<<<< Function that gets the drive letter from the unit mask >>>>
Private Function GetDriveLetterFromMask(ByRef Unit As Int32)
Dim i As Integer
For i = 0 To 25
If Unit And i Then Exit For
Unit = Unit >> 1
Next
Return Chr(i + Asc("A"))
End Function
Any better?
-
Sep 30th, 2008, 12:54 PM
#5
New Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
I already did that but still doesn't work.
If I change to:
Code:
If Unit And i Then msgbox(Chr(i + 1 + Asc("A")))
It prints G: , H: and I: and the real letter is H:. With another usb pen prints F: and the real letter is G:
-
Sep 30th, 2008, 12:58 PM
#6
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Make your mind up, a moment ago you said Windows says its F and the code says its G, now you say its the other way around..
-
Oct 14th, 2008, 05:18 AM
#7
Re: [RESOLVED] Detecting Drive Letter of USB Drive
I just tested it out on a load of PCs and with the original code I provided it does seem to be one letter out all of the time. But if you just change this line:
vb Code:
Return Chr(i + 1 + Asc("A"))
To this:
Then it works fine on all the machines I tested on.
-
Mar 5th, 2009, 07:25 AM
#8
Hyperactive Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
I found another thread to bookmark in case I need this code later on. Thanks
-
Apr 16th, 2009, 10:44 AM
#9
Re: Detecting Drive Letter of USB Drive
Originally Posted by chris128
OK I got it working
Just in case anyone else ever wants to do a similar thing, here's my code:
vb Code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Const WM_DEVICECHANGE As Integer = &H219
Private Const DBT_DEVICEARRIVAL As Integer = &H8000
Private Const DBT_DEVTYP_VOLUME As Integer = &H2
'Device information structure
Public Structure DEV_BROADCAST_HDR
Public dbch_size As Int32
Public dbch_devicetype As Int32
Public dbch_reserved As Int32
End Structure
'Volume information Structure
Private Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Int32
Public dbcv_devicetype As Int32
Public dbcv_reserved As Int32
Public dbcv_unitmask As Int32
Public dbcv_flags As Int16
End Structure
'<<<< Function that gets the drive letter from the unit mask >>>>
Private Function GetDriveLetterFromMask(ByRef Unit As Int32)
Dim i As Integer
For i = 0 To 25
If Unit And i Then Exit For
Unit = Unit >> 1
Next
Return Chr(i + 1 + Asc("A"))
End Function
'Override message processing to check for the DEVICECHANGE message
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
If m.WParam = DBT_DEVICEARRIVAL Then
Dim DeviceInfo As DEV_BROADCAST_HDR
DeviceInfo = Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_HDR))
If DeviceInfo.dbch_devicetype = DBT_DEVTYP_VOLUME Then
Dim Volume As DEV_BROADCAST_VOLUME
Volume = Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME))
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
Dim FileList() As String = IO.Directory.GetFiles(DriveLetter, "test.txt")
If FileList.Count > 0 Then
MessageBox.Show("Found Config File")
'<<<< The test file has been found >>>>
Else
MessageBox.Show("Could not find config file")
'<<<< Test file has not been found >>>>
End If
End If
End If
End If
MyBase.WndProc(m)
End Sub
End Class
So how does one get this code to work with
Option explicit = On
Option strict = On
There are many problems with them set to On that will not allow this code to compile.
-
Nov 9th, 2009, 01:51 PM
#10
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Hi Chris,
I was trying your code, but it seems to have a few issues:
EDIT: Tested with Vista (if it makes any difference...)
1st
Tested with VB 2008 Express
vb.net Code:
'Override message processing to check for the DEVICECHANGE message Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) If m.Msg = WM_DEVICECHANGE Then If m.WParam = DBT_DEVICEARRIVAL Then Dim DeviceInfo As DEV_BROADCAST_HDR DeviceInfo = Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_HDR)) If DeviceInfo.dbch_devicetype = DBT_DEVTYP_VOLUME Then Dim Volume As DEV_BROADCAST_VOLUME Volume = Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)) Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\") MessageBox.Show(DriveLetter) '<-- Shows G:\, but should be I:\... Dim FileList() As String = IO.Directory.GetFiles(DriveLetter, "test.txt") If FileList.Count > 0 Then MessageBox.Show("Found Config File") '<<<< The test file has been found >>>> Else MessageBox.Show("Could not find config file") '<<<< Test file has not been found >>>> End If End If End If End If MyBase.WndProc(m) End Sub
Messagebox says the drive letter is G:\, but the actual drive is I:\, so the following codeline throws a System.IO.DirectoryNotFoundException.
vb.net Code:
Dim FileList() As String = IO.Directory.GetFiles(DriveLetter, "test.txt")
So when I change the DriveLetter string in the following code to "I:\" the code works fine.
vb.net Code:
Dim FileList() As String = IO.Directory.GetFiles("I:\", "test.txt")
2nd
When testing your code in VB2010 (b2), the WndProc is making trouble (see images).
Last edited by Arve K.; Nov 9th, 2009 at 02:13 PM.
Reason: Typos
-
Nov 9th, 2009, 04:30 PM
#11
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Have you made the changes mentioned in post #7?
As for VS 2010 I havent got that installed so cant test it but I dont think it should be any different... You do know that you have to put that WndProc part in a Form right? You cant just stick that in some random class as your average class wont have a WndProc method for you to override
I just tested it on my Windows 7 PC and it worked fine - although strangely it was the original code that worked (ie without the modifications mentioned in post #7). Cant understand why it seems to be different on different machines :S
Last edited by chris128; Nov 9th, 2009 at 04:36 PM.
-
Nov 9th, 2009, 04:42 PM
#12
Re: Detecting Drive Letter of USB Drive
Originally Posted by kevininstructor
So how does one get this code to work with
Option explicit = On
Option strict = On
There are many problems with them set to On that will not allow this code to compile.
Just do what Option Strict tells you to do to correct the errors I just turned it on and fixed them (and tidied up a couple of little things in the code) - see code below:
vb.net Code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Const WM_DEVICECHANGE As Integer = &H219
Private Const DBT_DEVICEARRIVAL As Integer = &H8000
Private Const DBT_DEVTYP_VOLUME As Integer = &H2
'Device information structure
Public Structure DEV_BROADCAST_HDR
Public dbch_size As Int32
Public dbch_devicetype As Int32
Public dbch_reserved As Int32
End Structure
'Volume information Structure
Private Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Int32
Public dbcv_devicetype As Int32
Public dbcv_reserved As Int32
Public dbcv_unitmask As Int32
Public dbcv_flags As Int16
End Structure
'Function that gets the drive letter from the unit mask
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As Char
Dim i As Integer
For i = 0 To 25
If CBool(Unit And i) Then Exit For
Unit = Unit >> 1
Next
Return Chr(i + 1 + Asc("A"))
End Function
'Override message processing to check for the DEVICECHANGE message
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
If CInt(m.WParam) = DBT_DEVICEARRIVAL Then
Dim DeviceInfo As DEV_BROADCAST_HDR
DeviceInfo = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_HDR)), DEV_BROADCAST_HDR)
If DeviceInfo.dbch_devicetype = DBT_DEVTYP_VOLUME Then
Dim Volume As DEV_BROADCAST_VOLUME
Volume = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
If IO.File.Exists(IO.Path.Combine(DriveLetter, "test.txt")) Then
'<<<< The test file has been found >>>>
MessageBox.Show("Found test file")
Else
'<<<< Test file has not been found >>>>
MessageBox.Show("Could not find test file")
End If
End If
End If
End If
MyBase.WndProc(m)
End Sub
End Class
-
Nov 9th, 2009, 05:43 PM
#13
Re: [RESOLVED] Detecting Drive Letter of USB Drive
OK I've changed the code a bit and it works every time on my PC and another PC I just tested on - it gets the correct letter all of the time. So can you try out this code below and see if it works for you?
vb.net Code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Const WM_DEVICECHANGE As Integer = &H219
Private Const DBT_DEVICEARRIVAL As Integer = &H8000
Private Const DBT_DEVTYP_VOLUME As Integer = &H2
'Device information structure
Public Structure DEV_BROADCAST_HDR
Public dbch_size As Int32
Public dbch_devicetype As Int32
Public dbch_reserved As Int32
End Structure
'Volume information Structure
Private Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Int32
Public dbcv_devicetype As Int32
Public dbcv_reserved As Int32
Public dbcv_unitmask As Int32
Public dbcv_flags As Int16
End Structure
'Function that gets the drive letter from the unit mask
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As Char
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
End Function
'Override message processing to check for the DEVICECHANGE message
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
If CInt(m.WParam) = DBT_DEVICEARRIVAL Then
Dim DeviceInfo As DEV_BROADCAST_HDR
DeviceInfo = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_HDR)), DEV_BROADCAST_HDR)
If DeviceInfo.dbch_devicetype = DBT_DEVTYP_VOLUME Then
Dim Volume As DEV_BROADCAST_VOLUME
Volume = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
If IO.File.Exists(IO.Path.Combine(DriveLetter, "test.txt")) Then
'<<<< The test file has been found >>>>
MessageBox.Show("Found test file")
Else
'<<<< Test file has not been found >>>>
MessageBox.Show("Could not find test file")
End If
End If
End If
End If
MyBase.WndProc(m)
End Sub
-
Nov 9th, 2009, 05:46 PM
#14
Re: [RESOLVED] Detecting Drive Letter of USB Drive
-
Nov 9th, 2009, 05:49 PM
#15
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Oops, I didn't see your last post.. Just give me a few seconds
-
Nov 9th, 2009, 05:54 PM
#16
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Looks like you might have fixed the problem, it came up with the correct drive letter when I tested it (multiple times ).
-
Nov 10th, 2009, 05:44 AM
#17
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Cool so its all working now? Did you find out what was causing the problem with the WndProc override warning/error?
-
Nov 10th, 2009, 07:28 AM
#18
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Looks like I did something wrong when I pasted your code into VS2010 yesterday, cause today it works like a charm
Last edited by Arve K.; Nov 10th, 2009 at 07:40 AM.
-
Nov 10th, 2009, 11:38 AM
#19
Re: [RESOLVED] Detecting Drive Letter of USB Drive
lol glad to hear its working
-
Jul 11th, 2011, 10:31 PM
#20
New Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Hi,
Just implemented the code for my new application. This works like charm. Thanks to all of you. I just found one problem that is already mentioned in the following code:
Code:
Dim i As Integer
For i = 0 To 25
If Unit And i Then Exit For
Unit = Unit >> 1
Next
Return Chr(i + 1 + Asc("A"))
The above is failing for me if the connected disk is at G:. The reason is when "Unit" reaches 4, "i" was also 4 and hence it is showing some other drive letter instead of G:.
I think the problem is same as specified in
I already did that but still doesn't work.
If I change to:
Code:
If Unit And i Then msgbox(Chr(i + 1 + Asc("A")))
It prints G: , H: and I: and the real letter is H:. With another usb pen prints F: and the real letter is G:
I changed the code as follows and it worked perfectly for me now.
Code:
Dim driveMappedPath As String = String.Empty
Dim i As Integer = 0
While unit > 1
i += 1
unit = unit >> 1
End While
driveMappedPath = Chr(i + Asc("A"C))
Return driveMappedPath.Replace(vbNullChar, ":")
Once again thanks a lot for this valuable information.
-
Jul 12th, 2011, 04:24 AM
#21
Re: [RESOLVED] Detecting Drive Letter of USB Drive
I think I already addresses that problem in post #13 but glad to see you got it working anyway
-
Jan 13th, 2012, 03:37 PM
#22
Junior Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Can any one tell me how to actually use this code?? I am in need of detecting a usb drive and getting the drive letter so this code seems perfect, but I have no earthly idea how to actually implement it. I am looking the code over and I don't see how any of this code is actually getting called and executed.
Any help?
-
Jan 13th, 2012, 06:32 PM
#23
Re: [RESOLVED] Detecting Drive Letter of USB Drive
The sub named WndProc that you see used in the code gets automatically called by Windows every time a "Message" is sent to your window (or to all windows).
vb Code:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
So to use the code just copy everything below "Public Class Form1" from the code I posted in post #13 and paste that into your form
-
Jan 18th, 2012, 12:34 PM
#24
Junior Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Originally Posted by chris128
The sub named WndProc that you see used in the code gets automatically called by Windows every time a "Message" is sent to your window (or to all windows).
vb Code:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
So to use the code just copy everything below "Public Class Form1" from the code I posted in post #13 and paste that into your form
You sir are the MAN!! Many humble thanks for that tidbit!
-
Jan 24th, 2012, 06:42 AM
#25
New Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
i am having same error as in the post #10. how to rectify
-
Feb 17th, 2012, 07:03 PM
#26
New Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Interesting this code works.
-
Feb 17th, 2012, 10:27 PM
#27
New Member
Re: [RESOLVED] Detecting Drive Letter of USB Drive
-
Feb 18th, 2012, 06:44 AM
#28
Re: [RESOLVED] Detecting Drive Letter of USB Drive
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|