Unfolding the Windows path?

Hi,

I would like to ask you for checking the code below. The intention is to transform the Windows path with disk letter to the form of UNC path (for remote disks) or to the form of the path where the disk is not substed. I do use the QueryDosDevice() function for replacing the substitution in the loop. However, I am not sure about the path returned by the function -- namely about the \??\ prefix of the path. Could you point me to any documentation that explains the path prefix?  

Then, if the path is related to a remote drive, the drive letter is replaced by the mount point.

The related questions and simulated situations are discussed in http:Q_24142140.html

Thanks,
   Petr

#include <Windows.h>
#include <Winnetwk.h>  // WNetGetConnection()
#include <iostream>
#include <string>
 
using namespace std;
 
std::string driveTypeStr(UINT driveType);
 
void unfold3()
{
    string drive("R:");
    string driveRoot(drive + "\\");
    string path(drive + "\\b\\c\\file.txt");
    UINT driveType = ::GetDriveType(driveRoot.c_str());
 
    cout << "Unfold 3\n"
            "========\n"
            "     path: " << path << "\n"
         << "    drive: " << drive << "\n"
         << "driveRoot: " << driveRoot << "\n"
         << "driveType: " << driveType << " (" 
                          << driveTypeStr(driveType) << ")" << "\n"
         << "\n";
 
    char buf[1000];
    DWORD size = sizeof(buf);
    DWORD result = 0;
 
    // Replace the substed drives by their targets.
    //
    while (true)   
    {
        cout << "QueryDosDevice(\"" << drive << "\", ....): ";   
        result = QueryDosDevice(drive.c_str(), buf, size);  
                                  // returns 0 or number of chars
        string path2(buf);
        if (result == 0)
        {
            cout << "failed (" << GetLastError() << ")\n\n";
            break;  // when this can fail?
        }
        else
        {
            cout << path2 << "\n";  // returned by QueryDosDevice
            if (path2.find("\\??\\") == string::npos)
                break;              // it went too far. Stick with previous 
            
            // Get the path2 without the \??\ prefix and replace the 
            // previous drive (R:) letter by the substitution path.
            //
            path = path2.substr(4) + path.substr(2);
            drive = path.substr(0, 2);
            cout << "\nnew drive: " << drive << "\n";
            cout << " new path: " << path << "\n\n";
        }
    }
 
    if (driveType == DRIVE_REMOTE)
    {
        cout << "WNetGetConnection(\"" << drive << "\", ....): ";
        result = WNetGetConnection(drive.c_str(), buf, &size);
        if (result != NO_ERROR)
            cout << "failed (" << result << ")\n";
        else
        {   
            cout << "succeeded!\n\n";
            string path2(buf);
            path = path2 + path.substr(2);
        }
    }
 
    cout << "The wanted path: " << path << "\n\n";
}
 
 
int main()
{
    unfold3();
    return 0;
}
 
 
std::string driveTypeStr(UINT driveType)
{
    #define CASE(x) case x: return #x;
    switch (driveType)
    {
      CASE(DRIVE_UNKNOWN)
      CASE(DRIVE_NO_ROOT_DIR)
      CASE(DRIVE_REMOVABLE)
      CASE(DRIVE_FIXED)
      CASE(DRIVE_REMOTE)
      CASE(DRIVE_CDROM)
      CASE(DRIVE_RAMDISK)
    }
    return "unknown type";
}

Open in new window

LVL 29
peprAsked:
Who is Participating?
 
itsmeandnobodyelseConnect With a Mentor Commented:
>>> Could you point me to any documentation that explains the path prefix

http://stackoverflow.com/questions/341550/on-windows-when-should-you-use-the-filename-prefix
0
 
peprAuthor Commented:
Well, this is probably not the same. For the following subst

D:\Tutorial\PathUnfold\Debug>subst
P:\: => C:\tmp\test
Q:\: => P:\subdir
R:\: => Q:\a

The QueryDosDevice() returns paths like \??\P:\subdir, i.e. prefix with one backslash, two questionmarks, and one backslash... except in the last step that must be ignored -- see below

D:\Tutorial\PathUnfold\Debug>PathUnfold.exe
Unfold 3
========
     path: R:\b\c\file.txt
    drive: R:
driveRoot: R:\
driveType: 3 (DRIVE_FIXED)

QueryDosDevice("R:", ....): \??\Q:\a

new drive: Q:
 new path: Q:\a\b\c\file.txt

QueryDosDevice("Q:", ....): \??\P:\subdir

new drive: P:
 new path: P:\subdir\a\b\c\file.txt

QueryDosDevice("P:", ....): \??\C:\tmp\test

new drive: C:
 new path: C:\tmp\test\subdir\a\b\c\file.txt

QueryDosDevice("C:", ....): \Device\HarddiskVolume3
The wanted path: C:\tmp\test\subdir\a\b\c\file.txt

0
 
itsmeandnobodyelseConnect With a Mentor Commented:
Ok, I tried myself, and got the \??\ when I pass a drive-letter defined by subst. So, it seems to be the standard output of QueryDosDevice for these drive letters. I would assume it is output (only) an  to tell that QueryDosDevice couldn't find a physical device  associated with the path. But that's a guess. And I wonder why non of the docs mention it though I have no idea how to escape a string like '\??\' so that I could find it in an article or in the web.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
peprAuthor Commented:
Yes, exactly :)  You are reading my mind. I have found it once somewhere via Google, but it also did not mention any documentation. And I forgot what lead me to the article (definitely not the \??\ :)
0
 
torimarConnect With a Mentor Commented:
Maybe the following sample code dould be of help. It uses QueryDosDevice to get a list of "normal" volume GUID paths with the "\\?\" prefix:
http://msdn.microsoft.com/en-us/library/cc542456(VS.85).aspx
0
 
itsmeandnobodyelseConnect With a Mentor Commented:
I tested the code of toribar (it was of a newer version of VS and it took me some time to get it compiled with VC7.1) and the output was


Found a device:
 \Device\HarddiskVolume1
Volume name: \\?\Volume{ba252f37-a88e-11dc-9711-806d6172696f}\
Paths:  C:\

Found a device:
 \Device\CdRom0
Volume name: \\?\Volume{ba252f36-a88e-11dc-9711-806d6172696f}\
Paths:  D:\

Unfortunately, I have a dozen of network devices and two drive letters defined with subst, which all were ignored by the above code.

0
 
peprAuthor Commented:
Well, I want to use the "unfolded" path in combination with SID prefix of the computer to which the path belongs to generate the data licence file (data bound to the path on that machine; the application refuses to work with copy of the data unless the location is unlocked). I am going to consider only DRIVE_REMOTE or DRIVE_FIXED.

Any comment to the approach?

Thanks for your help,
    Petr
0
 
itsmeandnobodyelseConnect With a Mentor Commented:
I don't know whether I understand correctly. But a license file which only is valid if a specific network path currently is available, is a very restrictive method. What is when the server was not available or must be exchanged by another. Do you think the administrator wants to reconfigure each client for that case.

You better would put your license information int a server dbms somewhere in the LAN. Then the clients would connect to the dbms and check their license key using that db-connection. In case of a server exchange they would need to reestablish the db connections anyhow, so that normally was no additional efforts. If the license server was not available you could allow to use a local client dbms for some time in case your application doesn't need a central dbms anyhow.
0
 
peprAuthor Commented:
To itsmeandnobodyelse: Yes. It is rather restrictive. On the other hand, the administrator can call us to get the key (for free) to unlock the new location. Also, the number of users of our application at one location is not restricted (no end-user license). The application is not client-server yet. This way, making the application non-functional when "stolen" is probably the only (even though poor) way to get some form of security.

The earlier approach used locking the application to the client workstation. This way it was even more restrictive from the administrator's point of view as he/she was forced to unlock (via phone) every new workplace.

Yes. The first planned step is to move the data to a decent SQL server to ensure better security or to make the application client-server and make the data physically unreachable -- the database has still the legacy, DBF form.

What we try to get is a tradeoff. The application would work without that. However, the customers want something like that. Some of their employees may want to steal the data. The data has the form that is not very useful on its own. The application makes them useful.
0
 
itsmeandnobodyelseCommented:
I wouldn't make much efforts to resolve drive letters or network paths. When I firstly got knowledge of UNC paths the docs told me to not making any assumptions on teh syntax or naming of these paths. And indeed I wathced the whole mess over years and till now some applications were not able to handle all the existing paths correctly. I would go the database approach (SQLServer or not) and if it was for the license database only. It doesn't require a client-server for the first approach. You simply use a database connection which was established at client setup for access to your license information.
0
 
peprAuthor Commented:
Thanks both for the help.
  Petr
0
All Courses

From novice to tech pro — start learning today.