Getting a TRUE PATH

Is there a way in C or C++ or MFC where I can get the TRUE Path of a Subsituted Drive. For example if I use SUBST K: C:\MYTEST\PROGRAMS. I would like a function or method which would return C:\MYTEST\PROGRAMS if I pass K: as the input.
My old DOS program used DOS interrupt register. But, this same code does not work under NT Server.
Appereciate any help.
Who is Participating?
alexoConnect With a Mentor Commented:
PSS ID Number: Q131416
Article last modified on 09-29-1995

The information in this article applies to:
 - Microsoft Win32 Software Development Kit (SDK) version 4.0
The WNetGetUniversalName function takes a drive-based path for a network
resource and obtains a data structure that contains a more universal form
of the name. This function always fails with error 1200 when called from a
32-bit application running under Windows 95.
The functionality provided by WNetGetUniversalName can be implemented using
the Win32 network enumeration functions WNetOpenEnum and WNetEnumResource.
Here is an example of how to use these functions to implement similiar
#include <windows.h>
#include <stdio.h>
// Function Name:  GetUniversalName
// Parameters:     szUniv  - contains the UNC equivalent of szDrive
//                           upon completion
//                 szDrive - contains a drive based path
// Return value:   TRUE if successful, otherwise FALSE
// Comments:       This function assumes that szDrive contains a
//                 valid drive based path.
//                 For simplicity, this code assumes szUniv points
//                 to a buffer large enough to accomodate the UNC
//                 equivalent of szDrive.
BOOL GetUniversalName( char szUniv[], char szDrive[] )
   // get the local drive letter
   char chLocal = toupper( szDrive[0] );
   // cursory validation
   if ( chLocal < 'A' || chLocal > 'Z' )
      return FALSE;
   if ( szDrive[1] != ':' || szDrive[2] != '\\' )
      return FALSE;
   HANDLE hEnum;
                                  0, NULL, &hEnum );
   if ( dwResult != NO_ERROR )
      return FALSE;
   // request all available entries
   const int    c_cEntries   = 0xFFFFFFFF;
   // start with a reasonable buffer size
   DWORD        cbBuffer     = 50 * sizeof( NETRESOURCE );
   NETRESOURCE *pNetResource = (NETRESOURCE*) malloc( cbBuffer );
   BOOL fResult = FALSE;
   while ( TRUE )
      DWORD dwSize   = cbBuffer,
            cEntries = c_cEntries;
      dwResult = WNetEnumResource( hEnum, &cEntries, pNetResource,
                                   &dwSize );
      if ( dwResult == ERROR_MORE_DATA )
         // the buffer was too small, enlarge
         cbBuffer = dwSize;
         pNetResource = (NETRESOURCE*) realloc( pNetResource, cbBuffer );
      if ( dwResult != NO_ERROR )
         goto done;
      // search for the specified drive letter
      for ( int i = 0; i < (int) cEntries; i++ )
         if ( pNetResource[i].lpLocalName &&
              chLocal == toupper(pNetResource[i].lpLocalName[0]) )
            // match
            fResult = TRUE;
            // build a UNC name
            strcpy( szUniv, pNetResource[i].lpRemoteName );
            strcat( szUniv, szDrive + 2 );
            _strupr( szUniv );
            goto done;
   // cleanup
   WNetCloseEnum( hEnum );
   free( pNetResource );
   return fResult;
Microsoft has confirmed this to be a bug in the Microsoft products listed
at the beginning of this article. We are researching this problem and will
post new information here in the Microsoft Knowledge Base as it becomes
Additional reference words: 4.00 Win95
KBCategory: kbnetwork kbbuglist kbcode
KBSubcategory: NtwkWinnet
Copyright Microsoft Corporation 1995.

See the documentation on WNetGetUniversalName()
rianAuthor Commented:
I tried WNetGetUniversalName with my code and I always get a Error Code of 2250 - Network Connection could not be found. Make me think that this function only works for Network resource and not for substituted drive on a local machine.

// Start of Main Program
void main( int argc, char *argv[] )
    DWORD    dwDriveMask = GetLogicalDrives();
    int      i;
    char     szDir[3];
    BYTE     pBuffer[1024];
    DWORD dwBufsize;

    dwBufsize = 1024;

    szDir[1] = TEXT(':');
    szDir[2] = 0;
      int curdrive;
      curdrive = _getdrive();

    /* enumerate all fixed and logical drives */
      for (i=0; i < curdrive; i++)
            dwDriveMask >>=1;
    for (i = curdrive; i < MAX_DRIVES; dwDriveMask >>= 1, i++)
      /* if drive exists */
            if (dwDriveMask & 0x01)
                szDir[0] = TEXT('A') + i;

                  /* if it is a fixed drive */
                if (GetDriveType(szDir) == DRIVE_FIXED)
                        printf(" Validating Drive %s \n", szDir);
                        // Get the True Path of the Drive
                        WNetGetUniversalName(      szDir,
                                                            (LPVOID) &pBuffer,
                        DWORD Error = GetLastError();
                        printf("Error Returned %d \n",Error);
                        if (Error == 0)
                        UNIVERSAL_NAME_INFO *uname;
                      uname = (UNIVERSAL_NAME_INFO *) pBuffer;
                        printf( "Drive True Path %s \n",uname->lpUniversalName);


The new generation of project management tools

With’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

According to my documentation:


Points to a null-terminated string that is a drive-based path for a network resource.

For example, if drive H has been mapped to a network drive share, and the network resource of interest is a file named SAMPLE.DOC in the directory \WIN32\EXAMPLES on that share, the drive-based path is H:\WIN32\EXAMPLES\SAMPLE.DOC.

It's a bit ambiguous but I believe that all the string data for this function is UNICODE.  Your example above is using ASCII.
rianAuthor Commented:
But my substitute drive is not a network resource. I will try it in Unicode.
hmm, alexo, why when rian says he is running on NT did you copy & paste a technical note that allows WNetGetUniversalName to work on WIN95?

Win95 is not the reason WNetGetUniversalName won't work for rian. Also, unicode is not the reason WNetGetUniversalName won't work for rian. If you use ASCII but ask it about an actual network resource (gasp!), as opposed to a local one, it works just fine. The problem is that WNetGetUniversalName deals with Network drives and NOT local ones such as SUBST drives. It's the wrong function, as is implied by the doc and can be easily proven just by trying it.

rian, there is no perfect way to do what you want. The closest is QueryDosDevice (which is also unsupported on Win95, btw, though seems to be supported on Win98). The reason QueryDosDevice is tricky is it seems to know the true identity of all devices but it prepends internal desgnators like \Device which you have to wade through.

It does know the true path of SUBST drives under NT, though it prepends "\??\". I mapped Z: to D:\Program Files, and QueryDosDevice returns Z: as "\??\D:\Program Files". Here's the actual code I used, which enumerates all devices:

char alldrives[1000];
char thisdrive[1000];

QueryDosDevice(NULL, alldrives, sizeof(alldrives));
for (int i=0; alldrives[i]; i+=strlen(alldrives+i)+1) {
 QueryDosDevice(alldrives+i, thisdrive, sizeof(thisdrive));
 printf( "
Hmm, don't know why that cut off, here's the rest...

Strange, happened again, wonder if it's an EE problem. Trying a third time, with a slightly modified version:

 printf( "
I give up :-) There was only a printf with the results, anyway.

Unfortunately rian, I don't see a more elegant way to do what you want, but this does at least work :-)

If you agree that this will work, and alexo's answer won't, then please reject his answer and allow me to repost this comment as an answer. But in any case, good luck!
>> hmm, alexo, why when rian says he is running on NT did you copy & paste a technical note that allows WNetGetUniversalName to work on WIN95?
Duh!  I must have been too tired to notice.

>> If you agree that this will work, and alexo's answer won't, then please reject his answer and allow me to repost this comment as an answer.
Reject my answer anyway.  Sorry for the inconvenience.
rianAuthor Commented:
Dear Alomo,

Can u email the sample code to
I will try QueryDosDevice and let everyone know the results.

rianAuthor Commented:
Dear Experts,

I tried WNetOpenEnum and WNetEnumResource methods. These methods only give you the network connected resources not drives substituted to a local hard drive.

I also tried QueryDosDevice and alamo u are right. For every substituted drive it puts a ?? in front. Unfortunately, I have multiple substituted drives and it would be difficult to find out which drive letter is mapped to which path. Is there a way using some other function to find which drive is mapped to a path.
rian, you misunderstand (partly I think because my printf got cut off due to the EE problem, which I posted in customer service and they have since fixed).

The line that got cut is:

printf( "%s is mapped to %s", alldrives+i, thisdrive);

Try my example again with that line and you'll see that you DO know which drive letter is mapped to which path.

rianAuthor Commented:
Thanks a lot. It works

Duh!  You gave me the points that alamo deserved.  I'll ask Linda to reimburse him.
rianAuthor Commented:
Thanks. I did not know how to give him the points. After I submitted my response, it mentioned u as the owner of the points and I did not know how to change that.
Sorry Alamo and Thanks Alexo.

All Courses

From novice to tech pro — start learning today.