una que programacion principales otro lenguaje incluir hacer crear como cabeceras cabecera archivos archivo c++ c windows winapi

c++ - que - Obteniendo el nombre real del archivo(con la carcasa adecuada) en Windows



incluir un archivo c en otro (9)

Por lo que yo sé, la propiedad Nombre de la clase System.IO.FileInfo le devolverá el nombre real de Windows.

El sistema de archivos de Windows no distingue entre mayúsculas y minúsculas. ¿Cómo, dado el nombre de un archivo / carpeta (por ejemplo, "somefile"), obtengo el nombre real de ese archivo / carpeta (por ejemplo, debería devolver "SomeFile" si Explorer lo muestra así)?

Algunas formas que conozco, todas parecen bastante al revés:

  1. Dada la ruta completa, busque cada carpeta en la ruta (a través de FindFirstFile). Esto proporciona los resultados adecuados de cada carpeta. En el último paso, busca el archivo en sí.
  2. Obtenga el nombre de archivo desde el controlador (como en el ejemplo de MSDN ). Esto requiere abrir un archivo, crear una asignación de archivos, obtener su nombre, analizar los nombres de los dispositivos, etc. Muy complicado. Y no funciona para carpetas o archivos de tamaño cero.

¿Me estoy perdiendo alguna llamada WinAPI obvia? Los más simples, como GetActualPathName () o GetFullPathName (), devuelven el nombre usando la cubierta que se pasó (por ejemplo, devuelve "archivos de programa" si se pasó, incluso si debe ser "Archivos de programa").

Estoy buscando una solución nativa (no .NET uno).



De acuerdo, esto es VBScript, pero aún así sugeriría usar el objeto Scripting.FileSystemObject

Dim fso Set fso = CreateObject("Scripting.FileSystemObject") Dim f Set f = fso.GetFile("C:/testfile.dat") ''actually named "testFILE.dAt" wscript.echo f.Name

La respuesta que obtengo de este fragmento es

testFILE.dAt

Espero que al menos te dirija en la dirección correcta.



Esto hace el truco:

win32file.FindFilesW(''somefile'')[0][-2]

devuelve ''SomeFile''.

EDITAR: estúpido, yo estaba buscando lo mismo en Python. Así que ignora esto para C / C ++ ...


Hay otra solución Primero llame a GetShortPathName () y luego a GetLongPathName (). Adivina qué personaje se usará entonces? ;-)


FindFirstFileNameW funcionará con algunos inconvenientes:

  • no funciona en las rutas UNC
  • quita la letra de la unidad, por lo que debe volver a agregarla
  • si hay más de un enlace fijo a su archivo, necesita identificar el correcto

Y por la presente respondo mi propia pregunta, basada en la respuesta original de cspirz .

Aquí hay una función que, dada la ruta absoluta, relativa o de red, devolverá la ruta con mayúsculas / minúsculas tal como se mostraría en Windows. Si algún componente de la ruta no existe, devolverá la ruta pasada en ese punto.

Es bastante complicado porque trata de manejar rutas de red y otros casos extremos. Opera en cadenas de caracteres anchas y usa std :: wstring. Sí, en teoría, Unicode TCHAR podría no ser lo mismo que wchar_t; eso es un ejercicio para el lector :)

std::wstring GetActualPathName( const wchar_t* path ) { // This is quite involved, but the meat is SHGetFileInfo const wchar_t kSeparator = L''//'; // copy input string because we''ll be temporary modifying it in place size_t length = wcslen(path); wchar_t buffer[MAX_PATH]; memcpy( buffer, path, (length+1) * sizeof(path[0]) ); size_t i = 0; std::wstring result; // for network paths (//server/share/RestOfPath), getting the display // name mangles it into unusable form (e.g. "//server/share" turns // into "share on server (server)"). So detect this case and just skip // up to two path components if( length >= 2 && buffer[0] == kSeparator && buffer[1] == kSeparator ) { int skippedCount = 0; i = 2; // start after ''//' while( i < length && skippedCount < 2 ) { if( buffer[i] == kSeparator ) ++skippedCount; ++i; } result.append( buffer, i ); } // for drive names, just add it uppercased else if( length >= 2 && buffer[1] == L'':'' ) { result += towupper(buffer[0]); result += L'':''; if( length >= 3 && buffer[2] == kSeparator ) { result += kSeparator; i = 3; // start after drive, colon and separator } else { i = 2; // start after drive and colon } } size_t lastComponentStart = i; bool addSeparator = false; while( i < length ) { // skip until path separator while( i < length && buffer[i] != kSeparator ) ++i; if( addSeparator ) result += kSeparator; // if we found path separator, get real filename of this // last path name component bool foundSeparator = (i < length); buffer[i] = 0; SHFILEINFOW info; // nuke the path separator so that we get real name of current path component info.szDisplayName[0] = 0; if( SHGetFileInfoW( buffer, 0, &info, sizeof(info), SHGFI_DISPLAYNAME ) ) { result += info.szDisplayName; } else { // most likely file does not exist. // So just append original path name component. result.append( buffer + lastComponentStart, i - lastComponentStart ); } // restore path separator that we might have nuked before if( foundSeparator ) buffer[i] = kSeparator; ++i; lastComponentStart = i; addSeparator = true; } return result; }

De nuevo, gracias a cspirz por señalarme a SHGetFileInfo.


EDITAR: Ahora que volví a leer la pregunta, parece que OP es consciente de esta solución y busca otra solución.

Encontré que FindFirstFile() devolverá el nombre de archivo de la cubierta adecuada (última parte de la ruta) en fd.cFileName . Si pasamos c:/winDOWs/exPLORER.exe como primer parámetro a FindFirstFile() , el fd.cFileName sería explorer.exe como este:

Si reemplazamos la última parte de la ruta con fd.cFileName , obtendremos la última parte correcta; el camino se convertiría en c:/winDOWs/explorer.exe .

Suponiendo que la ruta sea siempre absoluta (sin cambios en la longitud del texto), podemos aplicar este ''algoritmo'' a cada parte de la ruta (excepto la parte de la letra de la unidad).

Hablar es barato, aquí está el código:

#include <windows.h> #include <stdio.h> /* c:/windows/windowsupdate.log --> c:/windows/WindowsUpdate.log */ static HRESULT MyProcessLastPart(LPTSTR szPath) { HRESULT hr = 0; HANDLE hFind = NULL; WIN32_FIND_DATA fd = {0}; TCHAR *p = NULL, *q = NULL; /* thePart = GetCorrectCasingFileName(thePath); */ hFind = FindFirstFile(szPath, &fd); if (hFind == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); hFind = NULL; goto eof; } /* thePath = thePath.ReplaceLast(thePart); */ for (p = szPath; *p; ++p); for (q = fd.cFileName; *q; ++q, --p); for (q = fd.cFileName; *p = *q; ++p, ++q); eof: if (hFind) { FindClose(hFind); } return hr; } /* Important! ''szPath'' should be absolute path only. MUST NOT SPECIFY relative path or UNC or short file name. */ EXTERN_C HRESULT __stdcall CorrectPathCasing( LPTSTR szPath) { HRESULT hr = 0; TCHAR *p = NULL; if (GetFileAttributes(szPath) == -1) { hr = HRESULT_FROM_WIN32(GetLastError()); goto eof; } for (p = szPath; *p; ++p) { if (*p == ''//' || *p == ''/'') { TCHAR slashChar = *p; if (p[-1] == '':'') /* p[-2] is drive letter */ { p[-2] = toupper(p[-2]); continue; } *p = ''/0''; hr = MyProcessLastPart(szPath); *p = slashChar; if (FAILED(hr)) goto eof; } } hr = MyProcessLastPart(szPath); eof: return hr; } int main() { TCHAR szPath[] = TEXT("c://windows//EXPLORER.exe"); HRESULT hr = CorrectPathCasing(szPath); if (SUCCEEDED(hr)) { MessageBox(NULL, szPath, TEXT("Test"), MB_ICONINFORMATION); } return 0; }

Ventajas:

  • El código funciona en todas las versiones de Windows desde Windows 95.
  • Manejo básico de errores
  • El mejor rendimiento posible. FindFirstFile() es muy rápido, la manipulación directa del búfer lo hace aún más rápido.
  • Just C y WinAPI puro. Pequeño tamaño ejecutable.

Desventajas:

  • Solo se admite la ruta absoluta, otros son comportamientos no definidos.
  • No estoy seguro de si se basa en un comportamiento no documentado.
  • El código puede ser demasiado bricolaje y demasiado bricolaje para algunas personas. Podría hacerte flamear.

Motivo detrás del estilo de código:

Utilizo goto para el manejo de errores porque estaba acostumbrado ( goto es muy útil para el manejo de errores en C). Utilizo for loop para realizar funciones como strcpy y strchr sobre la marcha porque quiero estar seguro de lo que realmente se ejecutó.