2010-12-14 3 views
5

Ich arbeite daran, einige Informationen aus nativen System-APIs zu melden. (Ich weiß, das ist schlecht .... aber ich bekomme Informationen, die ich sonst nicht bekommen kann, und ich habe wenig Problem mit meiner App zu aktualisieren, wenn/wann diese Zeit kommt.)Wie kann ich einen nativen (NT) Pfadnamen in einen Win32 Pfadnamen konvertieren?

Die native API gibt native Pfadnamen zurück, wie aus ob, dh \SystemRoot\System32\Ntoskrnl.exe, oder \??\C:\Program Files\VMWare Workstation\vstor-ws60.sys ersichtlich ist.

ich gemeinsame Präfixe ersetzen kann, das heißt

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")); 
} 

aber ich stark wäre überrascht, wenn es nicht einige API ist, nativ oder anders, die diese in Win32-Pfadnamen umwandeln. Existiert eine solche API?

+0

Ist die Shell-API-Funktion 'PathCanonicalize' den Trick? http://msdn.microsoft.com/en-us/library/bb773569%28v=vs.85%29.aspx – Praetorian

+0

@ Praetorian: Nein, PathCanonicalize akzeptiert Win32-Pfade. Ich versuche einen Win32 Pfad zu bekommen. –

+1

Ich kenne keine solche Funktion, und es ist nicht immer möglich: NT kann Pfade verwenden, die Win32 überhaupt nicht kann. Viel Glück trotzdem ... – ephemient

Antwort

6

Wir tun dies in Produktionscode: Es kann hilfreich sein für Sie. Soweit ich weiß, gibt es keine API (öffentlich oder privat), die das handhabt. Wir machen nur einige String-Vergleiche mit ein paar Präfixen und es funktioniert für uns.

Offenbar gibt es eine Funktion namens RtlNtPathNameToDosPathName() in Ntdll.dll (mit XP eingeführt?), Aber ich habe keine Ahnung, was es tut; Ich denke, es hat mehr mit Sachen wie \ Device \ Harddisk0 zu tun.

Ich bin mir nicht sicher, ob es wirklich eine Notwendigkeit für eine solche Funktion gibt. Win32 übergibt Pfade (im Sinne von CreateFile usw.) an NT; NT übergibt Pfade an Win32 nicht. Daher muss ntdll.dll nicht wirklich von NT-Pfaden zu Win32-Pfaden wechseln. In dem seltenen Fall, in dem eine NT-Abfragefunktion einen vollständigen Pfad zurückgibt, könnte jede Umwandlungsfunktion intern in der Win32-DLL sein (z. B. nicht exportiert). Ich weiß nicht einmal, ob sie stören, da Sachen wie GetModuleFileName() nur den Pfad zurückgeben, der zum Laden des Bildes verwendet wurde. Ich denke, das ist nur eine undichte Abstraktion.

+0

+1. Bearbeitete meine Frage - dass etwas wie das, was du tust? –

+0

Ziemlich viel. Die einzigen, die ich auf jeden regelmäßig gesehen habe sind \\ ?? \\ und \\ SystemRoot und sogar dann ist das ziemlich selten (in der Regel mit Low-Level-Prozesse früh in der Startsequenz gestartet. Manchmal auch in der Registrierung, normalerweise mit diesen Prozessen in Verbindung stehend – Luke

+0

Ich bin mit undokumentiertem Zeug herum und all diese Präfixe scheinen hier üblich zu sein.Es gibt einen Grund, warum sie nicht dokumentiert sind: P –

4

Hier ist etwas, was Sie versuchen könnten. Verwenden Sie zuerst NtCreateFile, um die Datei, das Volume usw. zum Lesen zu öffnen. Verwenden Sie dann den zurückgegebenen HANDLE, um den vollständigen Pfad wie beschrieben here zu erhalten.

+1

+1 :) Beachten Sie, dass der Dateizuordnungsschritt wahrscheinlich übersprungen werden kann, indem 'NtQueryFileInformation' aufgerufen wird und nach der Informationsklasse' FileNameInformation' gefragt wird. (Obwohl ich das noch nicht getestet habe, und natürlich geht das in den undokumentierten Zeug ...) –

+0

GetFinalPathNameByHandle könnte helfen, dies aufzuräumen! – Gbps

1

Siehe my answer to this question.

Sie müssten zuerst ein Handle für die Datei an diesem Pfad abrufen und dann den Win32-Pfad für das Handle abrufen.

+0

Das funktioniert - aber das Problem ist, dass Sie Zugriff auf den Speicherort der Datei benötigen, um es auszuführen (weil Sie in der Lage sein müssen, ein Handle zu öffnen) - das habe ich oft nicht. –

+0

@Billy: Alles, was Sie brauchen, ist 'FILE_READ_ATTRIBUTES' Zugang, die man fast immer bekommen. Wenn Sie es nicht erhalten, versuchen Sie es im übergeordneten Verzeichnis und verketten Sie den Dateinamen am Ende. (Sie können nicht ohne ein Handle konvertieren, da es nicht immer ein Eins-zu-eins-Mapping ist.) – Mehrdad

+0

@Mehrdad: Es muss möglich sein, ohne einen Handle zu konvertieren. FindFirstFile/FindNextFile/FindClose öffnen keine Handles. Sie können sie verwenden, um eine Verzeichnisstruktur aufzulisten, auch wenn Sie keine Attribute in der Datei lesen können. Diese Lösung funktioniert, also +1, aber es hilft mir wirklich nicht :( –

0

Ich schrieb eine Funktion, die verschiedene Arten von NT-Gerätenamen (Dateinamen, COM-Ports, Netzwerkpfade usw.) in einen DOS-Pfad konvertiert.

Es gibt zwei Funktionen. Einer konvertiert ein Handle in einen NT-Pfad und der andere wandelt diesen NT-Pfad in einen DOS-Pfad um.

Werfen Sie einen Blick hier: How to get name associated with open 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) 
Verwandte Themen