Solved

Getting a TRUE PATH

Posted on 1998-06-04
17
1,184 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
Comment Utility
See the documentation on WNetGetUniversalName()
0
 

Author Comment

by:rian
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
 
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
Comment Utility
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
Comment Utility
Hmm, don't know why that cut off, here's the rest...

 printf("
0
 
LVL 6

Expert Comment

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

 printf( "
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 6

Expert Comment

by:alamo
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Thanks a lot. It works

0
 
LVL 11

Expert Comment

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

Author Comment

by:rian
Comment Utility
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
Comment Utility
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
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 goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

762 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

11 Experts available now in Live!

Get 1:1 Help Now