|
|
|
|
Programmieren mit C++Borland C++32-Bit-ProgrammierungErweiterte Laufwerkserkennung
|
Warum liefert die API-Funktion GetDriveType() auf Windows 95 und Windows NT für manche Input-Strings unterschiedliche Ergebnisse und wie läßt sich dies abstellen?
| Frage | |
Die API-Funktion GetDriveType() bringt drei Probleme mit sich:
- Enthält der Pfadname einen Dateinamen, so resultiert der Fehlercode DRIVE_NO_ROOT_DIR
- Enthält der Pfad einen Name der Form „\\.\d\“, erkennt die Funktion das lokale Laufwerk nicht
- Die Funktion arbeitet unterschiedlich auf Windows NT und Windows 95
Die nachfolgend vorgestellte Funktion beseitigt diese Probleme, indem der Name des Pfads verkürzt wird, bis nur noch entweder ein Laufwerksbuchstabe wie beispielsweise „C:“ oder ein Netzwerkpfad mit „\\“-Präfix übrig bleibt. Dateinamensanteile werden abgeschnitten. Zusätzlich berücksichtigt die neue Funktion getDriveType() Pfade, die keine Laufwerksangaben bzw. UNC-Namen haben.
Letztlich wird auch kompensiert, daß _splitpath() unter Windows 95 und Windows NT unterschiedlich parst. Dies ist letztendlich auch dafür verantwortlich, daß die API-Funktion GetDriveType() unterschiedliche Ergebnisse liefert.
So ergibt sich zum Beispiel die folgende Abweichung, wenn der Blackslash vorhanden oder nicht vorhanden ist.
|
Input
|
Win 95
|
Win NT
|
|
C:
|
DRIVE_NO_ROOT_DIR
|
DRIVE_FIXED
|
|
C:\
|
DRIVE_FIXED
|
DRIVE_FIXED
|
Die Funktion getDriveType(), die sich von der API-Funktion nur durch die Schreibweise des ersten Buchstabens unterscheidet, übernimmt als Parameter den vollständigen Pfadnamen und returniert als Funktionsergebnis eine der DRIVE_-Konstanten, die auch GetDriveType() liefert.
Als erstes spaltet die Funktion den gelieferten Pfadnamen in die einzelnen Bestandteile auf.
| Lösung |
UINT getDriveType(LPCTSTR fullpath)
{
TCHAR drv[_MAX_PATH];
TCHAR path[_MAX_PATH];
TCHAR filename[_MAX_PATH];
TCHAR ext[_MAX_PATH];
_splitpath(fullpath, drv, path,
filename, ext);
Liegt ein Laufwerksbuchstabe vor, wird zunächst ein Backslash angehängt, um Windows 95 davon abzuhalten, den Fehlercode DRIVE_NO_ROOT_DIR zu returnieren.
| Funktion getDriveType |
if(lstrlen(drv) != 0)
{
lstrcat(drv, _T("\\"));
return GetDriveType(drv);
}
else {
Liegt kein Laufwerksbuchstabe vor und startet der Pfad nicht mit „\“, so handelt es sich um einen relativen Pfad. In diesem Fall wird das aktuelle Verzeichnis verwendet.
Beginnt der Pfad mit einem Backslash, auf den jedoch kein weiterer Backslash folgt, handelt es sich um einen Pfad, der von der Wurzel des aktuellen Laufwerks ausgeht. In beiden Fällen kann die API-Funktion GetDriveType() direkt aufgerufen werden.
| Backslash an Laufwerksbuch-staben anhängen |
if (path[0] != _T('\\') ||
(lstrlen(path) > 2 &&
path[0] == _T('\\') &&
path[1] != _T('\\')))
return GetDriveType(NULL);
Ansonsten verwendet die Funktion einen kleinen Trick, indem zunächst erst einmal GetDriveType() aufgerufen wird, wenn der Pfad mit „\\“ beginnt.
Lautet das Ergebnis DRIVE_NO_ROOT_DIR, wird ein neuer Name erzeugt, bei dem das „\\“ unterdrückt wird. Desweiteren wird dann auch der Spezialfall „\\.\“ behandelt.
| Korrekter Pfad liegt vor |
UINT result = GetDriveType(path);
if(result == DRIVE_NO_ROOT_DIR &&
lstrlen(path) >= 4 &&
path[0] == _T('\\') &&
path[1] == _T('\\') &&
path[2] == _T('.') &&
path[3] == _T('\\'))
{
if (lstrlen(path) == 4)
lstrcat(path, filename);
LPTSTR p = &path[4];
LPTSTR b = strchr(p, _T('\\'));
if(b != NULL)
{
*b++ = _T(':');
*b++ = _T('\\');
*b = _T('\0');
}
else lstrcat(p, _T(":\\"));
Dieser neu erzeugte Pfadname wird nun an GetDriveType() übergeben.
| Neuen Namen erzeugen |
return GetDriveType(p);
}
Beginnt der Pfad nicht mit „\\“, wird das zuvor ermittelte Funktionsresultat von GetDriveType() direkt returniert.
if (lstrlen(path) < 2 ||
path[0] != _T('\\') ||
path[1] != _T('\\'))
return result;
Für alle übrigen Fälle wird das Ergebnis von GetDriveType() für den Ausgangsparameter path returniert.
return GetDriveType(path);
}
}
| Laufwerkstyp ermitteln | |
Die so modifizierte Funktion umgeht die Klippen der API-Funktion GetDriveType() und liefert in nahezu allen Fällen ein korrektes Ergebnis zurück. Kommt es dennoch einmal zu Fehlinterpretationen, sollte sich der Entwickler fragen, ob er nicht vielleicht doch den Pfadnamen etwas besser aufbereitet an die Funktion hätte übergeben können.
| Resume
|
|
|