The whole concept of "installation" is not something which is designed for the use of removable media. Still, many good products work perfectly well on removable media or have two different kinds of packaging: installation and one without installation, which is usually called "portable" and can be well used on removable media.
Moreover, many good or even better products do not require installation in principle. Finally, I saw Microsoft recommendations to prefer such "self-installing" or "no installation" products. Many installations are redundant and only contaminate the system registry. When would you really need installation? One typical case is: you need to register some data file type(s) in the system the way your application would be automatically launched if the Shell starts the file, recognized by its name, such as "*.myFileType". Do you really need it?
Even if such files do exist, you should not try to do what you are trying to achieve. First of all, there can be more than one removable drive in the system. Finding your application is easy, but finding it by name is not a reliable options; the user always has a chance to have another executable file under the same name. I think what you should review your concept of the application and the application user. You really
should assume that your user is not an idiot. If some user put your application on a removable media, such person is supposed to understand that the media is removable. Such user will use some file manager (or even command line) to open that removable drive and click on the application, not on some data file.
More importantly, standard mechanisms of registration of some software products do not make provision on putting a registered application anywhere where if won't have a fixed name. To work around this limitation, you would have to install some other software, something like your custom "application launcher". I could explain in detail how to do it, but
it would defeat the purpose of using your application on the removable media.
Develop your application the way not requiring installation; this is the best you can do.
[EDIT]
If you need to find something of known file name, in the set of removable volumes, this can be needed for some reasonable purposes. Here is what you can do:
- Use WMI: http://msdn.microsoft.com/en-us/library/system.management.instrumentation%28v=vs.110%29.aspx[^].
- Traverse all drives using the class "Win32_DiskDrive". System Capabilities property will tell you if the drive is removable or not; ignore non-removable ones. Remember values of the Name property.
- Traverse all partitions using the class "Win32_DiskPartition"; ignoring partitions without file systems.
- For each partition, find its drive by the property "DiskIndex", ignore those pointing to non-removable drive.
- Traverse all logical disk volumes using the class "Win32_LogicalDiskToPartition"; it will give you the root name of each volume associated with some partition.
- Create collection of partitions ignoring those not pointing to logical volume; it will allow to associate some subset of partitions with drives (just to determine if a partition on the removable drive or not) and root paths of logical volumes, which are needed to perform file search.
- After such filtering, you will obtain the collection of root directory names of the partitions on removable drives. Find your file(s) in it.
It could be something like:
const string selectFormat = "SELECT * FROM {0}";
const string wmiTypeDrive = "Win32_DiskDrive";
const string wmiTypePartition = "Win32_DiskPartition";
const string wmiTypeLogicalDriveToPartitionAssociation = "Win32_LogicalDiskToPartition";
System.Func<string, ManagementObjectCollection> getAllWmiObjects = (wmiType) => {
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(string.Format(selectFormat, wmiType));
return searcher.Get();
};
ManagementObjectCollection partitions = getAllWmiObjects(wmiTypePartition);
ManagementObjectCollection drives = getAllWmiObjects(wmiTypeDrive);
ManagementObjectCollection driveToPartitionAssociations =
getAllWmiObjects(wmiTypeLogicalDriveToPartitionAssociation);
foreach (ManagementObject drive in drives) {
ushort[] capabilities = (ushort[])ManagementObject["Capabilities"];
bool sRemovable = capabilities != null && System.Array.FindIndex<ushort>(
capabilities, (element) => { return element == 7; }) >= 0;
}
It only sounds complicated, but the whole code will be few tens of lines.
—SA