EDIT: 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 correcto del archivo de la carcasa (última parte de la ruta) en fd.cFileName
. Si pasamos c:\winDOWs\exPLORER.exe
como primer parámetro a FindFirstFile()
, la fd.cFileName
habría explorer.exe
así:
Si sustituimos la última parte del camino con fd.cFileName
, obtendremos la última parte de la derecha; la ruta se convertiría en c:\winDOWs\explorer.exe
.
Suponiendo que la ruta sea siempre una ruta absoluta (sin cambios en la longitud del texto), podemos aplicar este 'algoritmo' a cada parte de la ruta (excepto la parte de letra de unidad).
Hablar es fácil, 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.
- de error básico -manejo.
- Mayor rendimiento posible.
FindFirstFile()
es muy rápido, la manipulación directa del buffer lo hace aún más rápido.
- Just C y WinAPI puro. Pequeño tamaño ejecutable.
Desventajas: se apoya
- Sólo ruta absoluta, otros son un comportamiento indefinido.
- No estoy seguro de si se basa en un comportamiento no documentado.
- Es posible que el código sea demasiado crudo para muchas personas. Podría hacerte flamear.
razón detrás del estilo de código:
lo uso goto
para control de errores, ya que estaba acostumbrado a ella (goto
es muy útil para el manejo de errores en C).Utilizo el bucle for
para realizar funciones como strcpy
y strchr
sobre la marcha porque quiero estar seguro de lo que realmente se ejecutó.
[SHGetFileInfo] (https://msdn.microsoft.com/en-us/library/bb762179.aspx): * "** SHGFI_DISPLAYNAME: ** Recuperar el nombre para mostrar del archivo, que es el nombre tal como aparece en Windows Explorer. [...] ** Tenga en cuenta que el nombre para mostrar puede verse afectado por la configuración, como si se muestran extensiones. ** "* ¿Está seguro de que esto es lo que está buscando? – IInspectable
Esto ** NO FUNCIONARÁ ** para la carpeta 'C: \ Users \ YourAccountName \ Documents' en Windows 8: devolverá' C: \ Users \ YourAccountName \ My Documents' en su lugar ya que la carpeta "Documentos" se muestra como "Mi Documentos "en el Explorador de Windows. – izogfif