Solved

Getting a TRUE PATH

Posted on 1998-06-04
17
1,222 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

718 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