VB6 - Get USB Flash Media Serial without WMI or Admin Rights
This is a Proposal
Update: This is only partially successful, working properly in Vista and later but not XP.
I am not putting this forward as "finished code, ready for prime time" but instead as a proposed technique and a testing prototype.
If we get enough positive testing feedback (and possibly some adjustments or bug fixes) it may well be of use in the future.
As a code sample needing more testing, I've marked this thread with a "question mark" icon. But it looks good enough and the prototype contains enough other useful sample code to be worth posting here instead of in the Testing forum. If the moderators disagree they can always move it of course.
Some Background
Authors of portable software designed to be installed onto a Flash Drive often need some way to enforce licensing. Usually they do this through an installer utility that verifies the number of copies left and then performs the install.
The "copies left" part is important because often the product license allows only 1, 2, or some limited number of Flash Drives to be installed to. Some of the better products allow an uninstall as well allowing license recapture, permitting users to move a license from an old device onto a new one.
None of that is addressed here. Beyond that however there is a need for license enforcement, and that's the issue that is addressed here.
Flash Devices and Software Licensing
The kinds of devices I'm talking about are USB Flash Drives and Flash media cards used in "USB Card Reader" devices.
These normally have a media serial number asigned during manufacture that can't be trivially altered, unlike the volume serial number created during formatting. So this MediaSerial value can often be used in license enforcement much as other things like network adapter MAC addresses and hard drive serial numbers can for non-portable desktop software.
Getting the MediaSerial
Obtaining drive media serial numbers can be fairly painful.
Some people try to use hardware-level I/O which can be reliable but fails without admin rights in modern Windows versions. Others rely on WMI which does he same thing via a system service that many people disable because (a.) it's a pig, and (b.) it's a potential security hazard.
Even though shutting it off has become more difficult to sustain in modern Windows versions (as parts of the system management utilities have moved to .Net there is more and more sloppy use of WMI by these tools), it would be cleaner and safer to use some non-WMI approach. After all, WMI is an administration tool, not something an application should ever rely on.
Another aproach involves going through USB enumeration data, either through API calls or directly from the registry. This can also get a bit convoluted.
Proposal and Prototype
It appears that starting with Windows 2000 we can get the MediaSerial by fishing around in the registry key:
HKLM\SYSTEM\MountedDevices
My idea is that given a drive letter to check, if we can (a.) verify that the drive is a "removable" type drive, and (b.) verify that the device is "ready" then the \DosDevices\x: value contains the info we need in a predictable format (where "x" is our drive letter).
This indeed seems to be the same or very similar information format used by enumeration spelunking techniques, but in this case we don't have to fish around as much. Of course those "verification" steps amount to the same thing, but we have less coding to do in our application.
Notes:
This approach works without using WMI and does not require administrator rights.
It is not intended as a means of getting hard drive serial numbers, but you might consider the WGA attributes as a possible solution.
It does not work for USB hard drives.
Issues
I have tested this with a number of types of Flash memory devices on a number of systems, but I still don't know if this technique is accurate enough "for prime time." It needs further testing.
So far I have tested it on Windows Vista 32-bit, Windows Vista 64-bit, and Windows 7 32-bit. I plan to test on Windows XP 32-bit soon.
I have tried several models of SanDisk USB Flash Drives. I've also tested several kinds of Flash memory cards in several card drives ("readers"): SmartMedia, XD, SD & microSD, and CF.
So far so good, the results are consistent with those of the 3rd party utility ListUsbDrives by Uwe Sieber. Reports of more test results would be appreciated. Also look at a discussion of some issues in comments at the head of DriveInfo.cls.
Additional Drive Attributes
As written, my prototype is a VB6 Class, included here as part of a demo Project.
It can also return a number of other things about the drives on a system, some of them are also useful in a "licensed portable software installer" program.
WGA Attributes
The DriveInfo class also has properties for fetching several Windows Genuine Advantage registry key values. These may or may not prove useful to you for licensing purposes. Their presence and reliability is probably such that they'd prove impractical.
This topic is also addressed in the comments inside DriveInfo.cls.
I included these because they might be of value to some people. A lot of people aren't aware of them.
Feedback
If anyone has some serious experience with using the WGA attributes for licensing that might be of interest. Otherwise opinions about this are off topic - I already know this isn't solid data. If you've used this for license enforcement and can give us a "viability" reading on it that would worth hearing about.
I just don't want to see 300 posts about how dumb the idea of using WGA is, ok? One or two are plenty!
Of much more interest to me (and probably to others) would be test results for MediaSerial values using other equipment and software configurations, and any bug reports or suggestions that improve the heuristics used.
32 vs. 64-bit doesn't appear important. Windows 2000, Windows XP, and Windows 8 test coverage would be useful though. The same is true for Server OSs such as Windows Server 2003, 2003 R2, 2008, and 2008 R2.
Other Flash Drive media results would be good too. So far I haven't found any that don't return unique MediaSerial values except for an Android Phone's internal media I'm suspicious of. Even there its microSD card returned good results.
Testing
The easiest approach here may be to just compile the example Project and copy the EXE to a Flash Drive. It has no dependencies that are not already present in the target range of Windows OSs (Win2K and later).
For local testing you won't even need to copy the program. Just run from the IDE or compile and then run the EXE.
Use the Report menu to report on all drives or else those that appear to be returning recognized MediaSerial values.
Of course without plugging in a USB Flash Drive or memory card the test wouldn't be too meaningful.
Last edited by dilettante; Mar 31st, 2012 at 05:25 AM.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
The lack of data returned by the WGA properties isn't really surprising. There are probably several categories of machines that will never have this data. For example machines with Windows installed under Microsoft Volume License programs probably won't if users have never performed any downloads requiring WGA validation.
Your drive I:\ results are of more interest.
What sort of drive is this?
I may have to post a "diagnostic" version of the program to aid in troubleshooting this issue. I should have thought about doing that earlier I suppose.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
Ok, here is a version that has another menu choice to display all removable devices along with a hex dump of their "DosDevice" registry value's contents.
This should make it easier to figure out where the logic fails for some devices, though it will report on floppy drives and such as well. In feedback please specify which of your USB Flash drives get an empty MediaSerial value. It would help to know which drive letter, what make/model/type of device it is, and of course to see the dump of the DosDevice data.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
Sorry, somehow I had missed your comments in post #5 above, oops! The Kingston DataTraveller series products are indeed Flash Memory devices, and actually fairly generic ones from what the Kingston data sheets say. Hmm.
I'm not sure whether USB Safely Remove has an impact here. I suppose it might but I'll have to look deeper.
What I suspect now is that XP handles these devices somewhat differently from the way Vista, Windows 7, and Windows 8 do. It could actually be the USB drivers rather than Windows itself, but in most cases we'd be using the generic drivers that come with Windows. But for all I know USB Safely Remove installs a custom driver.
I'll have to try some of the devices that I have here on an XP machine.
That .Net project appears to be using hardware-level I/O that requires admin rights on current versions of Windows. Windows XP was the last version allowing such unsecured access. So that defeats the intended purpose I was targeting, which requires access to the serial number when the user does not have admin rights.
This caused no end of problems for existing software that "broke" when users moved away from XP.
This did seem all too easy, so perhaps the idea just isn't going to work for enough systems to make it viable.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
What about trying the hardware level IO first, and if it fails then trying your method?
If WinVista+ consistently works with your method and the admin/hardware IO method when logged in as an administrator, and WinXP works consistently with only the hardware IO method, then this should be sufficient for the code to perform as expected under the vast majority of scenarios.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
After testing I've confirmed that XP doesn't store the necessary information for USB Flash drives where Vista and later do, so more effort is required in order to support XP.
I can use hardware I/O (actually this seems to be driver interrogation) to get serial numbers w/o admin rights for internal hard drives but it doesn't return a serial number for USB Flash drives or even for USB hard drives. Same results for this on XP, Vista, and Win7.
Actually true hardware I/O can also get the serial number from internal hard drives, but this requires admin rights and still doesn't work for USB devices.
It appears that the info is available for USB drives, but it may take a lot more effort to get it.
The more I fiddle with this the shakier it all seems. It looks like a new version of Windows could easily come along and break what's working now. Even the WMI method is erratic about returning the information, requiring different logic for various OSs.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
Originally Posted by dilettante
I can use hardware I/O (actually this seems to be driver interrogation) to get serial numbers w/o admin rights for internal hard drives...
This isn't true for all combinations of OS and drive either.
It looks like a more reliable method for either hard drives or flash drives will be substantially more work. So much so that if I get it working I probably won't be just giving it away.
The approach I was exploring here seems to be a dead end.
I meant to follow up on this but I haven't gotten around to cleaning up the code until now.
Trying Again
Here is another approach to getting USB Flash Drive media serial numbers.
It does not work for regular hard drives, SSDs, or even USB hard drives or SSDs, or any other type of drive. It is very specialized, but after all the goal here was reliably getting USB Flash Drive serial numbers.
It seems to be reliable for your typical USB Flash Drive devices as well as Flash Memory Card media connected via at least some USB "readers." As far as I can determine it should work for Window XP or anything later (through at least Windows 8).
I have only tested it on Vista SP2 and Windows 7 SP1 however. I don't have a handy XP machine or Win8 machine to test it on right now.
The code given there was some version of VB.Net, and he appears to have another example written in some version of C# as well but I didn't look at that. I have rewritten this in VB6 doing some major cleanup, taking care of some handle leaks and stripping out some redundant logic. I also added a filter for only "removable drives" since USB hard drives return a bogus result using his code.
This is now a VB6 Class UsbFlashSerial with just one method Lookup that you pass a drive letter to.
This returns either the USB Flash Drive media serial number or an empty String. The empty String value means the drive was not removable, not a USB drive, some API call error occurred, etc. I did not bother providing any API error codes or other information about failed calls because the way you'd probably use this code in your own programs a simple good-or-bad is all you can use anyway.
Good results should be the actual media serial number. I have not tested what happens if you call this passing a drive letter for one partition of a (rare) partitioned USB Flash Drive.
Looks Pretty Clean
This might be what you want if you don't require pre-XP support. It doesn't require admin rights, and it doesn't use WMI so you don't have to worry about the WMI Service being active.
The code is "packaged" as a Class so your program can create an instance, look up the drive serial number(s), and release the instance. This saves memory over the life of your program compared to putting the code in a static (BAS) module.
The Attachment
The attachment is a simple demo program listing all of the drives found and the results of calling Lookup on them. You should be able to just take the UsbFlashSerial.cls module from this demo project and use it in your own programs - it doesn't need any other files.
Maybe somebody can test this on an XP machine and report their results before I get around to it.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
I hope this proves to work and be reliable for people.
I left out all of the other things like enumerating the drives, returning drive types and returning hard drive serial numbers. The last one turns out to be complicated too: some methods work for IDE/ATA drives, other ones work for true SCSI drives, and I haven't found one that works for USB hard drives. Results can be hit or miss even using WMI.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
Thanks, I'm glad it seems to be working for you. I haven't plugged a monitor, keyboard, and mouse into my XP system to test this myself yet either. Hopefully we now have a reliable way to do this in VB6 programs.
Re: VB6 - Get USB Flash Media Serial without WMI or Admin Rights
test.7z
in my computer the drive serial get in IDE are not the same as in EXE
i do not know what is the problem.
my computer is win10 x64
InEXE: LENSE20256GMSP34MEAT2TA|A032_9911_9501_0501.;WDCWD10SPZX-08Z10|WD-WXK1A87J7C8E
InIDE: LENSE20256GMSP34MEAT2TA|0A239_19_159100_05.1;WDCWD10SPZX-08Z10|W-DXW1K8AJ7C7E8