编辑 - 看起来我发现了问题
对不起。显然这都是我的错。有关详细信息,请参阅下面的我自己写的答案。
我正在对一个SUBST
-ed 驱动器进行测试,该驱动器包含在一个更大的方法中,该方法测试一个字符串以确保它(至少,可能)是一个有效的路径。经过一些验证后,“封装”方法将字符串转换为 UNC 或绝对路径,具体取决于传入的路径,以在其他地方返回。
几个例子:
对于
U:\
映射到的驱动器\\SERVERNAME\Share
,使用\HKCU\Network\
Windows 注册表中的键查找本地计算机上的网络驱动器映射,U:\PublicFolder\SomeFile.txt
变为\\SERVERNAME\Share\PublicFolder\SomeFile.txt
或者,
C:\SomeFolder\SomeFile.txt
保持不变,因为(在方法中确定)它是本地物理驱动器的绝对路径。
到目前为止,其中大部分似乎运行良好且符合预期,但我遇到了与SUBST
Windows 10 中的命令创建的驱动器有关的问题(至少 - 我目前尚未在另一个操作系统下运行任何测试因为我现在没有其他可用的)。
老实说,我对这个SUBST
命令没有太多经验,也不经常使用它,所以一开始,我什至无法让驱动器在 Windows 中正确显示。在阅读了 Microsoft 社区页面上的讨论后(Windows 10 问题“Subst”命令不起作用),我终于能够“正确”设置驱动器(不要使用提升的命令提示符,顺便说一句),但是我用来测试 -ed 驱动器的代码- 从这个答案SUBST
转换为 VB.NET - 仍然没有正确解析完整路径。
这是我正在使用的转换后的代码(我打算稍后在一切正常后进行一些“调整”,但这是当前状态):
<DllImport("kernel32.dll", SetLastError:=True)>
Private Shared Function QueryDosDevice(ByVal lpDeviceName As String, ByVal lpTargetPath As System.Text.StringBuilder, ByVal ucchMax As Integer) As UInteger
End Function
Private Shared Function IsSubstPath(ByVal pathToTest As String, <Out> ByRef realPath As String) As Boolean
Dim PathInformation As System.Text.StringBuilder = New System.Text.StringBuilder(260)
Dim DriveLetter As String = Nothing
Dim WinApiResult As UInteger = 0
realPath = Nothing
Try
' Get the drive letter of the path
DriveLetter = IO.Path.GetPathRoot(pathToTest).Replace("\\", "")
Catch ex As ArgumentException
Return False
End Try
WinApiResult = QueryDosDevice(DriveLetter, PathInformation, 260)
If WinApiResult = 0 Then
Dim LastWinError As Integer = Marshal.GetLastWin32Error()
Return False
End If
' If the drive is SUBST'ed, the result will be in the format of "\??\C:\realPath\".
If PathInformation.ToString().StartsWith("\??\") Then
Dim RealRoot As String = PathInformation.ToString().Remove(0, 4)
RealRoot += If(PathInformation.ToString().EndsWith("\"), "", "\")
realPath = IO.Path.Combine(RealRoot, pathToTest.Replace(IO.Path.GetPathRoot(pathToTest), ""))
Return True
End If
realPath = pathToTest
Return False
End Function
我这样称呼我使用创建的驱动器SUBST H: D:\substtest
:
Dim TestFile As New IO.FileInfo("H:\0984\CPI.TXT")
Dim SubstPath As String = String.Empty
Dim FullPath As String = String.Empty
If IsSubstPath(FullPath, SubstPath) Then
FullPath = SubstPath
End If
我的期望是该IsSubstPath()
方法应该D:\substtest\0984\CPI.TXT
通过realPath
变量返回。执行SUBST
(不带附加参数)在命令提示符 ( H:\: => D:\substtest
) 中正确显示了映射。在调试时检查TestFile
对象表明它的Exists()
属性返回True
,因此文件系统显然知道它在那里。
在这一点上,每次我执行代码时,QueryDosDevice()
方法调用都会返回一个值0
,尽管我从调用中得到了不同的结果,Marshal.GetLastWin32Error()
因为我继续尝试让它工作。
在我的机器上“正确”设置了 -ed 驱动器后,我的第一次尝试SUBST
导致Marshal.GetLastWin32Error()
返回错误代码1008 - ERROR_NO_TOKEN(“尝试引用不存在的令牌”)。
在链接的 MS 社区线程中的进一步阅读表明,运行SUBST
两次-一次在正常命令提示符下,再次在提升的命令提示符下 -应该使驱动器可用于常规登录用户以及任何提升的用户操作。我在提升的命令提示符下重新运行SUBST
,并使用与上面相同的测试代码再次尝试。这一次,Marshal.GetLastWin32Error()
返回错误代码6 - ERROR_INVALID_HANDLE ( "The handle is invalid." )。
考虑到这个特定的操作可能取决于系统上实际存在的文件/路径(而不是 .NETIO.FileInfo
或IO.DirectoryInfo
对象),我手动创建了特定的子文件夹和文件来代表我在代码中测试的内容(H:\0984\CPI.TXT
)并尝试了再一次(再次,使用与上面相同的代码):
再次,QueryDosDevice()
未能正确解析真实路径(返回0
),但这次Marshal.GetLastWin32Error()
方法返回值0 - ERROR_SUCCESS(“操作成功完成。”)。考虑到,也许代码中有一些“缺陷”可能会无意中跳过一个步骤或其他什么,我检查了PathInformation
变量 -Text.StringBuilder
保存结果的对象QueryDosDevice()
- 在中断模式下,但是,可惜它也是空的。
注意:我也尝试使用目录而不是文件,但H:\0984\
导致Marshal.GetLastWin32Error()
返回值0
whileH:\0984
导致值6
. 根据之前的测试,这一切都是有道理的,但它仍然会导致一个空PathInformation
变量(失败)。
阅读所有关于 Interwebz 的文章,似乎很多人SUBST
在 Windows 10 下遇到了 -ed 驱动器的各种问题,所以我现在想知道这是否是这些意外结果的原因。有没有其他人遇到过这些问题,如果有,您是否能够在代码中解决它们?
如果它很重要(我想它肯定可能),这里有一些额外的细节:
- 我正在使用 Visual Studio 2017 CE,我的项目正在 .NET Framework 4.7.2 下编译
- 我要创建
SUBST
路径的物理驱动器是一对用 NTFS 格式化的 RAID 1 驱动器,并且有足够的空间 (178 GB)。
注意:我还尝试SUBST
为我的 OS 驱动器 ( ) 创建一个 -ed 路径以C:\
进行测试,但这会得到与上述相同的结果。
如果我遗漏了任何内容,或者您需要进一步澄清,请在评论中告诉我,我会根据需要更新问题。