Преобразование буквы диска Windows в путь (подстановка и сеть)

Интересно, существует ли универсальный способ преобразования пути с использованием буквы диска (например, X:\foo\bar.txt) в его эквивалентный путь UNC, который может быть одним из следующих:

  • X:\foo\bar.txt, если X: - настоящий диск (например, жесткий диск, USB-накопитель и т. Д.)
  • \\server\share\foo\bar.txt, если X: - сетевой диск, установленный на \\server\share
  • C:\xyz\foo\bar.txt, если X: является результатом SUBST преобразования команды X: в C:\xyz

Я знаю, что есть частичные решения, которые:

  1. Разрешите сетевой диск (см., Например, вопрос 556649, основанный на WNetGetUniversalName)

  2. Определите SUBST букву диска (см. QueryDosDevice, который работает должным образом, но не возвращает UNC-пути для таких вещей, как локальные или сетевые диски).

Мне не хватает простого способа реализовать это разрешение буквы диска в Win32? Или мне действительно нужно возиться с WNetGetUniversalName и QueryDosDevice, чтобы получить то, что мне нужно?


person Pierre Arnaud    schedule 19.08.2009    source источник


Ответы (2)


Да, вам нужно будет определить букву диска самостоятельно.

WNetGetUniversalName() подходит близко, но работает только для букв дисков, которые сопоставлены с фактическими общими ресурсами UNC, что не всегда так. Не существует единой функции API, которая бы выполняла всю работу за вас.

person Remy Lebeau    schedule 20.08.2009
comment
Как выглядит кейс, если он не сопоставлен с общим ресурсом UNC? Может ли он отображаться на путь UNC, который не является допустимым общим ресурсом? Или к пути, который вообще не является UNC-путем? Некоторые конкретные примеры могут помочь. - person Zyl; 19.04.2021

Вот пакет для перевода букв дисков в пути UNC или обратные пути с подстановкой. Хотя не гарантируется, что это работает.

Пример использования: 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!
person Benoit    schedule 12.01.2011
comment
ах, да, пойти по пути CMD - это решение, которое я изначально отверг. Я действительно пытался найти Win32 API, который помог бы мне. Очевидно, что ваше решение должно работать для людей, которые пытаются делать то же самое в среде пакетной обработки / сценария. Большое спасибо за ваши идеи; это был повод для меня (заново) открыть для себя некоторые уловки CMD. - person Pierre Arnaud; 13.01.2011
comment
Этот сценарий потрясающий. Только одна ошибка - он не поддерживает пробелы в подставленном пути к диску. Чтобы исправить это, измените первый цикл for с: ... tokens = 1,2 ... на ... tokens = 1 * ... - person Mr. Bungle; 11.04.2011
comment
@MrBungle: Спасибо! Я не знал о tokens=1*, займусь расследованием. Вы уверены, что это не 1,2*? - person Benoit; 11.04.2011