Resolve Windows drive letter to a path (subst and network)
Asked Answered
S

2

8

I wonder if there is a universal way of resolving a path using a drive letter (such as X:\foo\bar.txt) into its equivalent UNC path, which might be one of the following:

  • X:\foo\bar.txt if X: is a real drive (i.e. hard disk, USB stick, etc.)
  • \\server\share\foo\bar.txt if X: is a network drive mounted on \\server\share
  • C:\xyz\foo\bar.txt if X: is the result of a SUBST command mapping X: to C:\xyz

I know that there are partial solutions which will:

  1. Resolve a network drive (see for instance question 556649 which relies on WNetGetUniversalName)

  2. Resolve the SUBST drive letter (see QueryDosDevice which works as expected, but does not return UNC paths for things such as local drives or network drives).

Am I missing some straightforward way of implementing this drive letter resolution in Win32? Or do I really have to mess with both WNetGetUniversalName and QueryDosDevice to get what I need?

Shae answered 19/8, 2009 at 13:5 Comment(0)
B
5

Yes, you would need to resolve the drive letter independently.

WNetGetUniversalName() comes close, but only works for drive letters that are mapped to actual UNC shares, which is not always the case. There is no single API function that does all of the work for you.

Borsch answered 20/8, 2009 at 0:24 Comment(1)
What does a case look like where it is not mapped to a UNC share? Can it map to a UNC path that is not a valid share? Or to a path which is not a UNC path at all? Some concrete examples would help.Stomatology
T
6

Here is a batch to translate drive letters to UNC paths or reverse substed paths. Not guaranteed it works though.

Example of use: script.cmd echo Z: Y: W:

@echo off
:: u is a variable containing all arguments of the current command line
set u=%*

:: enabledelayedexpansion: exclamation marks behave like percentage signs and enable
:: setting variables inside a loop
setlocal enabledelayedexpansion

:: parsing result of command subst
:: format:  I: => C:\foo\bar
:: variable %G will contain I: and variable H will contain C:\foo\bar
for /f "tokens=1* delims==> " %%G IN ('subst') do (
set drive=%%G
:: removing extra space
set drive=!drive:~0,2!
:: expanding H to a short path in order not to break the resulting command line
set subst=%%~sfH
:: replacing command line.
call set u=%%u:!drive!=!subst!%%
)

:: parsing result of command net use | findstr \\ ; this command is not easily tokenized because not always well-formatted
:: testing whether token 2 is a drive letter or a network path.
for /f "tokens=1,2,3 delims= " %%G IN ('net use ^| findstr \\') do (
set tok2=%%H
if "!tok2:~0,2!" == "\\" (
  set drive=%%G
  set subst=%%H
) else (
  set drive=%%H
  set subst=%%I
)
:: replacing command line.
call set u=%%u:!drive!=!subst!%%
)

call !u!
Toe answered 12/1, 2011 at 14:50 Comment(3)
ah, yes, going the CMD way is a solution I rejected initially. I really was trying to find a Win32 API which would do the trick. Obviously, your solution should work for people trying to do the same thing in a batch/scripting environment. Thanks a lot for your ideas; it was the occasion for me to (re-)discover some CMD tricks.Shae
This script is awesome. Just one bug - it doesn't support spaces in the substituted drive path. To fix, change the first for loop from: ... tokens=1,2 ... to ... tokens=1* ...Splutter
@MrBungle: Thanks! I didn't know about tokens=1*, will investigate. Are you sure it is not 1,2*?Toe
B
5

Yes, you would need to resolve the drive letter independently.

WNetGetUniversalName() comes close, but only works for drive letters that are mapped to actual UNC shares, which is not always the case. There is no single API function that does all of the work for you.

Borsch answered 20/8, 2009 at 0:24 Comment(1)
What does a case look like where it is not mapped to a UNC share? Can it map to a UNC path that is not a valid share? Or to a path which is not a UNC path at all? Some concrete examples would help.Stomatology

© 2022 - 2024 — McMap. All rights reserved.