MORE INFORMATION
Internal NT Device Names
When a kernel-mode device driver is loaded, its initialization routine
registers a device name with Windows NT's Object Manager. This name is referred to as the Windows NT device name. The kernel-mode components of Windows NT and kernel-mode drivers reference devices by their Windows NT device names. These names have a format, such as \Device\CDRom0 and \Device\Serial0 and also exist in the \device directory of the Object Manager's namespace.
Win32 programs cannot use internal Windows NT device names to access devices because the Win32 subsystem and Win32 API require the more familiar drive letters and MS-DOS device names, such as A:, C:, COM1:, and LPT1:. Although Win32 programs may not use Windows NT device names, they can however, define and remove MS-DOS device names to access devices. They can also retrieve the internal Windows NT device name associated with an MS-DOS device name. The example code in the "Symbolic Links" section of this article describes how to do this.
To gain a better understanding of how the Object Manager tracks names to
devices and other system objects, you can view the Object Manager's namespace with the WinObj.exe tool in the Platform SDK.
MS-DOS Device Names
Win32 programs use devices like drives, serial ports, and parallel ports
through their MS-DOS device names. For disk drives, these are drive letters like A: and C:. For serial and parallel ports these are names like COM1:, COM2:, and LPT1:. Like Windows NT device names, these names reside in the Object Manager's namespace, but in the \?? directory, which is visible to user-mode Win32 programs.
What makes MS-DOS device names different from Windows NT device names is that they are not used by the Windows NT kernel or kernel-mode drivers. Their purpose is to refer to Windows NT device names so that Win32 programs can use the familiar drive letters and device names; for example, COM1:, to access the Windows NT devices. Therefore, MS-DOS device names are called "symbolic links" to Windows NT device names. That is, an MS-DOS device name exists in the Object Manager's \?? directory and points to a Windows NT device name in the Object Manager's \device directory.
Each MS-DOS device name can point to at most one internal Windows NT device. However, multiple MS-DOS device names can point to a single device. For example, while C: can only point to a single partition, it is possible to have two or more drive letters, like D:, E:, and Z:, point to the same
partition.
Symbolic Links
Symbolic links created by the system persist across computer restarts
because they are stored in the registry. Programs may also create symbolic links with the DefineDosDevice() API. These links are valid only until the computer is restarted or turned off unless the registry keys containing information about the links are updated.
There can be multiple symbolic links to a Windows NT device name. However, only the MS-DOS device name that the system initially assigned to the internal Windows NT device remains across reboots. Therefore, it is possible to create additional symbolic links that assign multiple drive letters to a single CD-ROM drive, but the additional drive letters only remain until the machine is turned off or restarted.
Win32 programs can retrieve the Windows NT device name that is associated with a specific MS-DOS device name by calling QueryDosDevice() with the MS-DOS device name. Following is example code that shows how to do this:
char szNtDeviceName[MAX_PATH];
if (QueryDosDevice ("C:", szNtDeviceName, MAX_PATH))
{
printf ("C: is linked to %s\n", szNtDeviceName);
}
Win32 programs can create and delete symbolic links by calling
DefineDosDevice(). To create a symbolic link, call DefineDosDevice with the
DDD_RAW_TARGET_PATH flag. To remove a symbolic link, call it with the
DDD_REMOVE_DEFINITION and DDD_RAW_TARGET_PATH flags. The following sample
program demonstrates both of these operations:
/*
DDD
This sample shows how to associate an MS-DOS device name with a
Windows NT device name. The association is a symbolic link between
device names stored in the Object Manager's namespace. Applications
use the MS-DOS device name, but Windows NT and kernel-mode drivers
use the Windows NT device name.
Usage:
ddd <MS-DOS Device Name> <NT Device Name>
ddd -r <MS-DOS Device Name>
NOTE: If the MS-DOS device name is a driver letter, the trailing
backlash is not accepted by DefineDosDevice or QueryDosDevice.
NOTE: The MS-DOS device name is defined only until the computer is
restarted.
To make the drive letter associations permanent on Window NT 4.0, you
have to update HKEY_LOCAL_MACHINE\SYSTEM\DISK\Information. However,
the contents of the value are undocumented.
On Windows 2000, you have to use the Volume Mount Point APIs.
*/
#define WIN32_LEAN_AND_MEAN /* Reduce number of system headers parsed */
/* during build. */
#include <windows.h>
#include <stdio.h>
void main (int argc, char **argv)
{
char * pszDosDeviceName,
* pszNtDeviceName;
bool fRemoveDeviceName = false;
bool fResult;
/*
Command-line parsing.
1) Make sure correct number of arguments are supplied.
2) See if you should add or remove the MS-DOS Device Name.
*/
if (argc != 3)
{
printf("\nusage: %s <DOS device name> <NT device name> to add\n",
argv[0]);
printf("usage: %s [-r] <DOS device name> to remove\n",
argv[0]);
printf("\n\texample: %s d: \\device\\cdrom0\n", argv[0]);
return;
}
fRemoveDeviceName = !lstrcmpi (argv[1], "-r");
/* Now, add/remove the DOS device name. */
if (fRemoveDeviceName)
{
/*
Remove the MS-DOS device name. First, get the name of the Windows
NT device from the symbolic link, then delete the symbolic link.
*/
pszDosDeviceName = argv[2];
pszNtDeviceName = (char *)LocalAlloc (LPTR, MAX_PATH);
fResult = QueryDosDevice (pszDosDeviceName, pszNtDeviceName,
MAX_PATH);
if (fResult)
{
fResult = DefineDosDevice (DDD_RAW_TARGET_PATH|
DDD_REMOVE_DEFINITION|
DDD_EXACT_MATCH_ON_REMOVE,
pszDosDeviceName, pszNtDeviceName);
}
if (!fResult)
printf("error %lu: could not remove %s\n",
GetLastError(), pszDosDeviceName);
LocalFree (pszNtDeviceName);
}
else
{
/* Add the DOS device name */
pszDosDeviceName = argv[1];
pszNtDeviceName = argv[2];
fResult = DefineDosDevice (DDD_RAW_TARGET_PATH, pszDosDeviceName,
pszNtDeviceName);
if (!fResult)
printf("error %lu: could not link %s to %s\n",
GetLastError(), pszDosDeviceName, pszNtDeviceName);
}
}