Solved

Getting a TRUE PATH

Posted on 1998-06-04
17
1,190 Views
Last Modified: 2010-05-18
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.
0
Comment
Question by:rian
  • 6
  • 5
  • 4
  • +1
17 Comments
 
LVL 32

Expert Comment

by:jhance
ID: 1165245
See the documentation on WNetGetUniversalName()
0
 

Author Comment

by:rian
ID: 1165246
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,
                                                            UNIVERSAL_NAME_INFO_LEVEL,
                                                            (LPVOID) &pBuffer,
                                                            &dwBufsize);
                        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);
                        }

 
                  }
            }
      }

0
 
LVL 32

Expert Comment

by:jhance
ID: 1165247
According to my documentation:

lpLocalPath

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.
0
 

Author Comment

by:rian
ID: 1165248
But my substitute drive is not a network resource. I will try it in Unicode.
0
 
LVL 11

Accepted Solution

by:
alexo earned 100 total points
ID: 1165249
 
PSS ID Number: Q131416
Article last modified on 09-29-1995
 
4.00
 
WINDOWS
 

---------------------------------------------------------------------
The information in this article applies to:
 
 - Microsoft Win32 Software Development Kit (SDK) version 4.0
---------------------------------------------------------------------
 
SYMPTOMS
========
 
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.
 
WORKAROUND
==========
 
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
functionality:
 
#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;
   DWORD dwResult = WNetOpenEnum( RESOURCE_CONNECTED, RESOURCETYPE_DISK,
                                  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 );
         continue;
      }
 
      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;
         }
   }
 
done:
   // cleanup
   WNetCloseEnum( hEnum );
   free( pNetResource );
 
   return fResult;
 
}
 
STATUS
======
 
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
available.
 
Additional reference words: 4.00 Win95
KBCategory: kbnetwork kbbuglist kbcode
KBSubcategory: NtwkWinnet
=============================================================================
Copyright Microsoft Corporation 1995.

0
 
LVL 6

Expert Comment

by:alamo
ID: 1165250
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( "
0
 
LVL 6

Expert Comment

by:alamo
ID: 1165251
Hmm, don't know why that cut off, here's the rest...

 printf("
0
 
LVL 6

Expert Comment

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

 printf( "
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 6

Expert Comment

by:alamo
ID: 1165253
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!
0
 
LVL 11

Expert Comment

by:alexo
ID: 1165254
>> 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.
0
 

Author Comment

by:rian
ID: 1165255
Dear Alomo,

Can u email the sample code to rian@mindspring.com.
I will try QueryDosDevice and let everyone know the results.
Thanks

0
 

Author Comment

by:rian
ID: 1165256
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.
Thanks
0
 
LVL 6

Expert Comment

by:alamo
ID: 1165257
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.


0
 

Author Comment

by:rian
ID: 1165258
Thanks a lot. It works

0
 
LVL 11

Expert Comment

by:alexo
ID: 1165259
Duh!  You gave me the points that alamo deserved.  I'll ask Linda to reimburse him.
0
 

Author Comment

by:rian
ID: 1165260
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.

0
 
LVL 11

Expert Comment

by:alexo
ID: 1165261
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

919 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now