DOSDEV.EXE - a misterious tool

Once in a while, you might encounter this tool in some Microsoft-provided SDKs, or Resource Kits, for example in the Windows Resource Kit, the Exchange Report Toolkit, and others.

But this tool never came with any relevant documentation. It just displays the following cryptic help message:

   DOSDEV [-a] [-s] [-h] [[-r] [-d [-e]] DeviceName [TargetPath]]

What's all this about?

Answer: DOSDEV.EXE is a very thin wrapper around the DefineDosDevice( ) Win32 API. Fortunately, this API is well-documented on MSDN, and here are its parameters:

Given a device, the DefineDosDevice function defines, redefines, or deletes MS-DOS device names. These "MS-DOS" device names are nothing more than symbolic links in the Object Manager namespace - i.e. symbolic links that reside in the [\\?\](file://\\?\) namespace (this is the user-mode representation) which is equivalently represented as \??\... namespace prefix in kernel mode. If you do not know what the Object Manager is, then go ahead and buy the book Microsoft Windows Internals - believe me, it's interesting :-)

BOOL DefineDosDevice(
DWORD dwFlags,
LPCTSTR lpDeviceName,
LPCTSTR lpTargetPath
);

Parameters:
dwFlags [in] - Controllable aspects of the DefineDosDevice function. This parameter can be one or more of the following values. Value Meaning
- DDD_EXACT_MATCH_ON_REMOVE If this value is specified along with DDD_REMOVE_DEFINITION, the function will use an exact match to determine which mapping to remove. Use this value to insure that you do not delete something that you did not define.
- DDD_NO_BROADCAST_SYSTEM Do not broadcast the WM_SETTINGCHANGE message. By default, this message is broadcast to notify the shell and applications of the change.
- DDD_RAW_TARGET_PATH Uses the lpTargetPath string as is. Otherwise, it is converted from an MS-DOS path to a path.
- DDD_REMOVE_DEFINITION Removes the specified definition for the specified device. To determine which definition to remove, the function walks the list of mappings for the device, looking for a match of lpTargetPath against a prefix of each mapping associated with this device. The first mapping that matches is the one removed, and then the function returns. If lpTargetPath is NULL or a pointer to a NULL string, the function will remove the first mapping associated with the device and pop the most recent one pushed. If there is nothing left to pop, the device name will be removed. I

f this value is not specified, the string pointed to by the lpTargetPath parameter will become the new mapping for this device.  

lpDeviceName [in] Pointer to an MS-DOS device name string specifying the device the function is defining, redefining, or deleting. The device name string must not have a trailing colon, unless a drive letter (C or D, for example) is being defined, redefined, or deleted. In no case is a trailing backslash allowed.
lpTargetPath [in] Pointer to a path string that will implement this device. The string is an MS-DOS path string unless the DDD_RAW_TARGET_PATH flag is specified, in which case this string is a path string.

Now, it should be obvious what DeviceName and TargetPath are. Basically, the first parameter of DOSDEV is whatever will be passed in the lpDeviceName in DefineDosDevice (which is a regular Windows device). The TargetPath is a MS-DOS style device symbolic link that will be assigned to the device.

Now, what are all these command-line options? I listed them here for you:

1) Show the (relatively useless) help:

      DOSDEV -h  

2) Show all devices, not only drives. When you use "-a" you don't need to specify anything else. The "-a" option can also be used when trying to map/remove devices:

      DOSDEV -a  

Example:
- show all drive letter mappings:

Z:\> dosdev
A: = \Device\Floppy0 [Removable]
C: = \Device\HarddiskVolume1 [Fixed]
D: = \Device\CdRom0 [CDRom]
E: = \Device\CdRom1 [CDRom]
G: = \Device\HarddiskVolume7 [Fixed]
H: = \Device\HarddiskVolume4 [Fixed]
...

- show all devices:

Z:\> dosdev -a
A: = \Device\Floppy0 [Removable]
C: = \Device\HarddiskVolume1 [Fixed]
D: = \Device\CdRom0 [CDRom]
E: = \Device\CdRom1 [CDRom]
G: = \Device\HarddiskVolume7 [Fixed]
H: = \Device\HarddiskVolume4 [Fixed]
R: = \Device\HarddiskVolume8 [Fixed]
U: = \Device\HarddiskVolume5 [Fixed]
X: = \Device\HarddiskVolume3 [Fixed]
Y: = \Device\HarddiskVolume2 [Fixed]
Z: = \Device\HarddiskVolume10 [Fixed]

$VDMLPT1 = \Device\ParallelVdm0
1394BUS0 = \Device\1394BUS0
ACPI#FixedButton#2&daba3ff&0#{4afa3d53-74a7-11d0-be5e-00a0c9062857} = \Device\0000004f
ACPI#GenuineIntel_-_x86_Family_15_Model_1#_0#{97fadb10-4e33-40ae-359c-8bef029dbdd0} = \Device\0000004b
ACPI#GenuineIntel_-_x86_Family_15_Model_1#_1#{97fadb10-4e33-40ae-359c-8bef029dbdd0} = \Device\0000004c
ACPI#PNP0303#4&33a96545&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} = \Device\0000005e
ACPI#PNP0401#4&33a96545&0#{97f76ef0-f883-11d0-af1f-0000f800845c} = \Device\00000061
ACPI#PNP0501#1#{4d36e978-e325-11ce-bfc1-08002be10318} = \Device\0000005f
ACPI#PNP0501#1#{86e0d1e0-8089-11d0-9ce4-08003e301f73} = \Device\0000005f
ACPI#PNP0501#2#{4d36e978-e325-11ce-bfc1-08002be10318} = \Device\00000060
ACPI#PNP0501#2#{86e0d1e0-8089-11d0-9ce4-08003e301f73} = \Device\00000060
ACPI#PNP0C0C#2&daba3ff&0#{4afa3d53-74a7-11d0-be5e-00a0c9062857} = \Device\0000004a
ARP1394 = \Device\ARP1394
AUX = \DosDevices\COM1
CdRom0 = \Device\CdRom0
CdRom1 = \Device\CdRom1
...

3) Map a device to a target path:

      DOSDEV [-a] [-r] DevicePath TargetPath 

where the flags can be:
      -r   = Use flag DDD_RAW_TARGET_PATH 
      -a   = Deal with devices not mapped to non-drive letters too.

4) Map the system partition to a target path 

      DOSDEV [-a] -s TargetPath 

This maps the current system partition (as a RAW device) to the given target path. The system partition will show up with the given DOS device. Example: 

Z: > dosdev.exe -s k:
Current definition: k: = \Device\HarddiskVolume1

This option implicitly uses "-r".

5) Remove a DOS device mapping (WARNING: Use it at your own risk! )

      DOSDEV [-a] -r -d [-e] DevicePath TargetPath

where the flags can be a combination of those:
      -r   = Use flag DDD_RAW_TARGET_PATH
      -d   = Additionally, use flag DDD_REMOVE_DEFINITION
      -e   = Additionally, use flag DDD_EXACT_MATCH_ON_REMOVE (you have to specify -d too)
      -s   = Can substitute the DevicePath; in this case it represents the device for the volume hosting the system partition. 
      -a   = Deal with devices not mapped to non-drive letters too.

6) Remove a DOS device mapping for the system partition (WARNING: Use it at your own risk! )

      DOSDEV -r -d [-e] [-a] -s TargetPath

where the flags can be a combination of those:
      -r   = Use flag DDD_RAW_TARGET_PATH
      -d   = Additionally, use flag DDD_REMOVE_DEFINITION
      -e   = Additionally, use flag DDD_EXACT_MATCH_ON_REMOVE (you have to specify -d too)
      -s   = Can substitute the DevicePath; in this case it represents the device for the volume hosting the system partition. 
      -a   = Deal with devices not mapped to non-drive letters too.

Example:

Z:\> c:\idw\dosdev.exe -d -r -s k:
Current definition: k: = \Device\HarddiskVolume1
k: deleted.

To conclude - as you can see, DOSDEV.EXE is nothing special. As an exercise for you, you can go ahread and write your own DOSDEV.EXE now :-). All you need to do is read carefully the DefineDosDevice documentation.

WARNING: This post was provided for your experminentation pleasure - do not attempt to try removing DOS devices on a production system! In addition, I am not sure if this tool is even supported. You should not use it to randomly remove DOS devices that are unknown to you. You could cause serious system instability.

[update: add more warnings]