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.
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\MountedDevicesMy 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.
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.
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.
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.
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.
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.