windows 如何将本机 (NT) 路径名转换为 Win32 路径名?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4445108/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I convert a native (NT) pathname into a Win32 path name?
提问by Billy ONeal
I'm working on reporting some information gleaned from native system APIs. (I know this is bad.... but I'm getting information that I can't get otherwise, and I have little issue with having to update my app if/when that time comes around.)
我正在报告从本机系统 API 收集的一些信息。(我知道这很糟糕......但我得到了我无法通过其他方式获得的信息,如果/当那个时候到来时,我不得不更新我的应用程序几乎没有问题。)
The native API returns native pathnames, as seen by ob
, i.e. \SystemRoot\System32\Ntoskrnl.exe
, or \??\C:\Program Files\VMWare Workstation\vstor-ws60.sys
.
本机 API 返回本机路径名,如ob
、 ie\SystemRoot\System32\Ntoskrnl.exe
或 所示\??\C:\Program Files\VMWare Workstation\vstor-ws60.sys
。
I can replace common prefixes, i.e.
我可以替换常用前缀,即
std::wstring NtPathToWin32Path( std::wstring ntPath )
{
if (boost::starts_with(ntPath, L"\\?\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 4);
return ntPath;
}
if (boost::starts_with(ntPath, L"\??\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 4);
}
if (boost::starts_with(ntPath, L"\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 1);
}
if (boost::istarts_with(ntPath, L"globalroot\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 11);
}
if (boost::istarts_with(ntPath, L"systemroot"))
{
ntPath.replace(ntPath.begin(), ntPath.begin() + 10, GetWindowsPath());
}
if (boost::istarts_with(ntPath, L"windows"))
{
ntPath.replace(ntPath.begin(), ntPath.begin() + 7, GetWindowsPath());
}
return ntPath;
}
TEST(Win32Path, NtPathDoubleQuestions)
{
ASSERT_EQ(L"C:\Example", NtPathToWin32Path(L"\??\C:\Example"));
}
TEST(Win32Path, NtPathUncBegin)
{
ASSERT_EQ(L"C:\Example", NtPathToWin32Path(L"\\?\C:\Example"));
}
TEST(Win32Path, NtPathWindowsStart)
{
ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\World"), NtPathToWin32Path(L"\Windows\Hello\World"));
}
TEST(Win32Path, NtPathSystemrootStart)
{
ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\World"), NtPathToWin32Path(L"\SystemRoot\Hello\World"));
}
TEST(Win32Path, NtPathGlobalRootSystemRoot)
{
ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\World"), NtPathToWin32Path(L"\globalroot\SystemRoot\Hello\World"));
}
but I'd be strongly surprised if there's not some API, native or otherwise, which will convert these into Win32 path names. Does such an API exist?
但是如果没有一些 API(本地或其他方式)将这些 API 转换为 Win32 路径名,我会感到非常惊讶。这样的API存在吗?
回答by Luke
We do this in production code. As far as I know there is no API (public or private) that handles this. We just do some string comparisons with a few prefixes and it works for us.
我们在生产代码中执行此操作。据我所知,没有处理此问题的 API(公共或私有)。我们只是用一些前缀做一些字符串比较,它对我们有用。
Apparently there is a function named RtlNtPathNameToDosPathName() in ntdll.dll (introduced with XP?), but I have no idea what it does; I would guess it has more to do with stuff like \Device\Harddisk0, though.
显然,ntdll.dll 中有一个名为 RtlNtPathNameToDosPathName() 的函数(在 XP 中引入?),但我不知道它是做什么的;不过,我猜它更多地与 \Device\Harddisk0 之类的东西有关。
I'm not sure there is really a need for such a function, though. Win32 passes paths (in the sense of CreateFile, etc) to NT; NT doesn't pass paths to Win32. So ntdll.dll doesn't really have a need to go from NT paths to Win32 paths. In the rare case where some NT query function returns a full path, any conversion function could be internal to the Win32 dll (e.g. not exported). I don't even know if they bother, as stuff like GetModuleFileName() will just return whatever path was used to load the image. I guess this is just a leaky abstraction.
不过,我不确定是否真的需要这样的功能。Win32 将路径(在 CreateFile 等意义上)传递给 NT;NT 不会将路径传递到 Win32。所以ntdll.dll 真的不需要从NT 路径转到Win32 路径。在某些 NT 查询函数返回完整路径的罕见情况下,任何转换函数都可能是 Win32 dll 的内部函数(例如,未导出)。我什至不知道他们是否打扰了,因为像 GetModuleFileName() 这样的东西只会返回用于加载图像的任何路径。我想这只是一个有漏洞的抽象。
回答by Praetorian
Here's something you could try. First use NtCreateFileto open the file, volume etc. for reading. Then use the returned HANDLE to get the full path as described here.
这是你可以尝试的东西。首先使用NtCreateFile打开文件、卷等进行读取。然后使用返回的 HANDLE 获取此处所述的完整路径。
回答by user541686
See my answer to this question.
请参阅我对这个问题的回答。
You'd need to first get a handle to the file at that path, and then get the Win32 path for the handle.
您需要首先获取该路径中文件的句柄,然后获取该句柄的 Win32 路径。
回答by miked
Check this out for getting the canonical pathname in Win32. It may be helpful for you:
检查这个以获取 Win32 中的规范路径名。它可能对您有帮助:
http://pdh11.blogspot.com/2009/05/pathcanonicalize-versus-what-it-says-on.html
http://pdh11.blogspot.com/2009/05/pathcanonicalize-versus-what-it-says-on.html
回答by Elmue
I wrote a function that converts different types of NT device names (filenames, COM ports, network paths, etc.) into a DOS path.
我编写了一个函数,可以将不同类型的 NT 设备名称(文件名、COM 端口、网络路径等)转换为 DOS 路径。
There are two functions. One converts a handle into an NT path and the other one converts this NT path into a DOS path.
有两个功能。一个将句柄转换为 NT 路径,另一个将这个 NT 路径转换为 DOS 路径。
Have a look here: How to get name associated with open HANDLE
在这里查看: 如何获取与打开的 HANDLE 关联的名称
// "\Device\HarddiskVolume3" (Harddisk Drive)
// "\Device\HarddiskVolume3\Temp" (Harddisk Directory)
// "\Device\HarddiskVolume3\Temp\transparent.jpeg" (Harddisk File)
// "\Device\Harddisk1\DP(1)0-0+6\foto.jpg" (USB stick)
// "\Device\TrueCryptVolumeP\Data\Passwords.txt" (Truecrypt Volume)
// "\Device\Floppy0\Autoexec.bat" (Floppy disk)
// "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB" (DVD drive)
// "\Device\Serial1" (real COM port)
// "\Device\USBSER000" (virtual COM port)
// "\Device\Mup\ComputerName\C$\Boot.ini" (network drive share, Windows 7)
// "\Device\LanmanRedirector\ComputerName\C$\Boot.ini" (network drive share, Windwos XP)
// "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP)
// "\Device\Afd" (internet socket)
// "\Device\Console000F" (unique name for any Console handle)
// "\Device\NamedPipe\Pipename" (named pipe)
// "\BaseNamedObjects\Objectname" (named mutex, named event, named semaphore)
// "\REGISTRY\MACHINE\SOFTWARE\Classes\.txt" (HKEY_CLASSES_ROOT\.txt)
回答by Norbert Boros
This is a bit late, but I will still post my answer since even today this is a very good question!
这有点晚了,但我仍然会发布我的答案,因为即使在今天,这是一个非常好的问题!
I will share one of my functions tested and used for converting NT to DOS path. In my case, I also had to convert from ANSI to UNICODE so this is a small bonus for you to see and understand how this can be done.
我将分享我测试并用于将 NT 转换为 DOS 路径的功能之一。就我而言,我还必须从 ANSI 转换为 UNICODE,所以这是一个小小的奖励,让您看到并理解如何做到这一点。
All this code can be used in User Mode, so we need to first prepare some things.
所有这些代码都可以在用户模式下使用,所以我们需要先准备一些东西。
Definitions & Structures:
定义和结构:
typedef NTSTATUS(WINAPI* pRtlAnsiStringToUnicodeString)(PUNICODE_STRING, PANSI_STRING, BOOL);
typedef struct _RTL_BUFFER {
PUCHAR Buffer;
PUCHAR StaticBuffer;
SIZE_T Size;
SIZE_T StaticSize;
SIZE_T ReservedForAllocatedSize; // for future doubling
PVOID ReservedForIMalloc; // for future pluggable growth
} RTL_BUFFER, * PRTL_BUFFER;
typedef struct _RTL_UNICODE_STRING_BUFFER {
UNICODE_STRING String;
RTL_BUFFER ByteBuffer;
UCHAR MinimumStaticBufferForTerminalNul[sizeof(WCHAR)];
} RTL_UNICODE_STRING_BUFFER, * PRTL_UNICODE_STRING_BUFFER;
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_AMBIGUOUS (0x00000001)
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_UNC (0x00000002)
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_DRIVE (0x00000003)
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_ALREADY_DOS (0x00000004)
typedef NTSTATUS(WINAPI* pRtlNtPathNameToDosPathName)(__in ULONG Flags, __inout PRTL_UNICODE_STRING_BUFFER Path, __out_opt PULONG Disposition, __inout_opt PWSTR* FilePart);
#define RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE (0x00000001)
#define RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING (0x00000002)
#define RTL_DUPSTR_ADD_NULL RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
#define RTL_DUPSTR_ALLOC_NULL RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
typedef NTSTATUS(WINAPI* pRtlDuplicateUnicodeString)(_In_ ULONG Flags, _In_ PUNICODE_STRING StringIn, _Out_ PUNICODE_STRING StringOut);
Importing functions:
导入功能:
pRtlAnsiStringToUnicodeString MyRtlAnsiStringToUnicodeString;
pRtlNtPathNameToDosPathName MyRtlNtPathNameToDosPathName;
pRtlDuplicateUnicodeString MyRtlDuplicateUnicodeString;
MyRtlAnsiStringToUnicodeString = (pRtlAnsiStringToUnicodeString)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAnsiStringToUnicodeString");
MyRtlNtPathNameToDosPathName = (pRtlNtPathNameToDosPathName)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlNtPathNameToDosPathName");
MyRtlDuplicateUnicodeString = (pRtlDuplicateUnicodeString)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlDuplicateUnicodeString");
Helper function:
辅助功能:
NTSTATUS DriverScanner::NtPathNameToDosPathName(PUNICODE_STRING DosPath, PUNICODE_STRING NtPath)
{
NTSTATUS Status;
ULONG_PTR BufferSize;
PWSTR Buffer;
RTL_UNICODE_STRING_BUFFER UnicodeBuffer;
BufferSize = NtPath->MaximumLength + MAX_PATH * sizeof(WCHAR);
Buffer = (PWSTR)_alloca(BufferSize);
ZeroMemory(&UnicodeBuffer, sizeof(UnicodeBuffer));
UnicodeBuffer.String = *NtPath;
UnicodeBuffer.String.Buffer = Buffer;
UnicodeBuffer.String.MaximumLength = (USHORT)BufferSize;
UnicodeBuffer.ByteBuffer.Buffer = (PUCHAR)Buffer;
UnicodeBuffer.ByteBuffer.Size = BufferSize;
CopyMemory(Buffer, NtPath->Buffer, NtPath->Length);
Status = MyRtlNtPathNameToDosPathName(0, &UnicodeBuffer, NULL, NULL);
return MyRtlDuplicateUnicodeString(RTL_DUPSTR_ADD_NULL, &UnicodeBuffer.String, DosPath);
}
Function usage:
函数用法:
UNICODE_STRING us;
UNICODE_STRING DosPath;
ANSI_STRING as;
as.Buffer = (char*)malloc(strlen(NT_PATH_FILE_OR_DIR) + 1);
strcpy(as.Buffer, NT_PATH_FILE_OR_DIR);
as.Length = as.MaximumLength = us.MaximumLength = us.Length = strlen(NT_PATH_FILE_OR_DIR);
MyRtlAnsiStringToUnicodeString(&us, &as, TRUE);
NtPathNameToDosPathName(&DosPath, &us);
As mentioned, in my case I needed to convert from ANSI to UNICODE and this might not apply for your case, thus you can remove it.
如前所述,在我的情况下,我需要从 ANSI 转换为 UNICODE,这可能不适用于您的情况,因此您可以将其删除。
Same as above can be used to create custom functions and convert paths as needed.
同上可用于创建自定义函数并根据需要转换路径。