ArtÃculo cedido por El rincón del programador
Introducción
Con la aparición de Windows 95 surgió el formato largo en los nombres de archivos. Hay aplicaciones, sin embargo, que por una u otra razón necesitan trabajar con nombres de archivo en formato corto, es decir, con un nombre de archivo limitado a 8 caracteres más 3 de extensión. Por suerte se añadió en el API de Windows la función GetShortPathName, la cual nos permite obtener un nombre de archivo en formato largo a partir de su formato corto.
Solución
Sin embargo, en Windows 95 no existe ninguna función que nos permita realizar el proceso contrario. Recientemente se ha incluido la función GetLongPathName en el API, pero se requiere Windows 98.
Podemos olvidarnos de utilizar la función GetFullPathName. A pesar de su nombre, no se obtiene un nombre de archivo en formato largo a partir de uno corto. Su cometido es el de generar un nombre completo de archivo a partir de la unidad y directorio actuales. Si le pasamos como primer parámetro la ruta completa de un archivo en formato corto, nos devolverá lo mismo en su tercer parámetro como se muestra en el ejemplo 1.
char lpszShortPath[_MAX_PATH]; char lpszLongPath[_MAX_PATH]; char* filepart; lstrcpy(lpszShortPath, "C:ARCHIV~1ACCESO~1MSPAINT.EXE"); GetFullPathName(lpszShortPath, _MAX_PATH, lpszLongPath, &filepart); // lpszLongPath contiene "C:ARCHIV~1ACCESO~1MSPAINT.EXE"
Por otro lado, si sólo le pasamos un nombre de archivo sin especificar la ruta completa, GetFullPathName generará una ruta a partir de la unidad y directorio en el que nos encontremos actualmente como se muestra en el ejemplo 2.
lstrcpy(lpszShortPath, "MSPAINT.EXE"); // cambiamos de directorio SetCurrentDirectory("C:WINDOWSESCRIT~1"); GetFullPathName(lpszShortPath, _MAX_PATH, lpszLongPath, &filepart); // lpszLongPath contiene "C:WINDOWSESCRIT~1MSPAINT.EXE" // cambiamos de nuevo de directorio SetCurrentDirectory("C:WINDOWS"); GetFullPathName(lpszShortPath, _MAX_PATH, lpszLongPath, &filepart); // ahora lpszLongPath contiene "C:WINDOWSMSPAINT.EXE"
Hay sin embargo una manera de obtener el nombre de un archivo en formato largo y es utilizando la función del shell SHGetFileInfo. Para ello hay que especificar SHGFI_DISPLAYNAME en su quinto parámetro. Pero hay un pequeño problema, sólo convierte la última parte de la ruta completa, es decir, en el caso de tener por ejemplo la ruta C:WINDOWSESCRIT~1MIPRIM~1.EXE únicamente podrÃamos obtener MiPrimerPrograma.exe correspondiente a MIPRIM~1.EXE como se muestra en el ejemplo 3.
SHFILEINFO sfi; lstrcpy(lpszShortPath, "C:WINDOWSESCRIT~1MIPRIM~1.EXE"); SHGetFileInfo(lpszShortPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME); strcat(lpszLongPath, sfi.szDisplayName); // lpszLongPath contiene "MiPrimerPrograma.exe"
Debido a esto es necesario llamar a la función SHGetFileInfo para cada subdirectorio especificado en la ruta del nombre completo empezando desde el primer nivel de subdirectorio. Seguidamente se muestra la función definitiva:
DWORD GetLongPathName2 (LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer) { DWORD ret; char shortPath[_MAX_PATH]; char longPath[_MAX_PATH]; char tempPath[_MAX_PATH]; char* backslash = ""; // carácter donde debemos detenernos cada vez char* token; SHFILEINFO sfi; ret = 0; // comprobamos que se trata de un nombre de archivo o ruta existente if (GetFileAttributes(lpszShortPath) != -1) { lstrcpy(shortPath, lpszShortPath); token = strtok(shortPath, backslash); ZeroMemory(tempPath, sizeof(tempPath)); strcat(tempPath, token); // ej. "C:" strcat(tempPath, backslash); // ej. "C:" // empezamos a generar el nombre en formato largo lstrcpy(longPath, token); // leemos el primer directorio o nombre de archivo token = strtok(NULL, backslash); while (token != NULL) { // añadimos el siguiente subdirectorio o nombre de archivo strcat(tempPath, token); // añadimos la barra "" al final, // no importa si se añade al final de un nombre de archivo strcat(tempPath, backslash); // obtenemos el nombre en formato largo en el // campo sfi.szDisplayName SHGetFileInfo(tempPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME); // vamos añadiendo lo último convertido // a la cadena en formato largo strcat(longPath, backslash); strcat(longPath, sfi.szDisplayName); // leemos el siguiente directorio o nombre de archivo, // si ya se han leÃdo todos, devolverá un puntero nulo token = strtok(NULL, backslash); } // obtenemos el número de caracteres que forman el nombre completo ret = strlen(longPath); if (cchBuffer >= ret) { // copiamos el nombre obtenido en el primer parámetro de la función lstrcpy(lpszLongPath, longPath); } } return ret; }