Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   API de Windows (https://www.clubdelphi.com/foros/forumdisplay.php?f=7)
-   -   ¿Cómo obtener nombres Ficheros MS-DOS? (https://www.clubdelphi.com/foros/showthread.php?t=54561)

jhonalone 23-03-2008 20:50:47

¿Cómo obtener nombres Ficheros MS-DOS?
 
Necesito un método fiable, para obtener los nombres de fichero abreviados, es decir (8.3).
He desarrollado una utilidad con FindFirst que lo consigue, pero (siempre tiene que haber algun pero) aunque, aparentemente funciona bien, la he probado en mi antiguo sistema Windows ME, cuyo MS-DOS todavía los edita en este formato y en general muy bien.
El "pero" es el siguiente: cuando existen más de un fichero que tienen el comienzo del nombre igual, por ejemplo: si tenemos dos directorios tales como "Pepito Perez" y "Pepito Perez Lopez" los listaria de este modo
  • PEPITO~1 (correspondería a "Pepito Perez Lopez" P.Ej)
  • PEPITO~2 (Correspondería a "Pepito Perez" P.Ej)
Pues cuando los edito con mi utilidad, pueden no corresponder, es decir
    • PEPITO~2 (correspondería a "Pepito Perez Lopez" P.Ej)
    • PEPITO~1 (Correspondería a "Pepito Perez" P.Ej)
Pensaba que tendría que ver con el orden de creación, pero he comprobado que ficheros que se crearon con fecha posterior tienen una numeración más baja.

Estoy un poquito, mejor un MUCHITO, liado y no sé como resolverlo.

Pensaba que lo había hecho bien, pero al no coincidirme los ficheros, me he quedado muy desilusionado.

Espero que alguien me eche una mano. No me vale GetShortPathName, pues empecé por ahí y me da problemas cuando hay mas de 4 directorios o ficheros que comienzan con las mismas letras. Hasta el cuarto fichero funciona, pero si le pides el path desde el quinto se descontrola. Curioso, pero verdad.

Si consigo resolverlo lo pondré como truco por si le interesa a alguien.

Perdonad la parrafada, pero quería dejar claro el problema.

Espero vuestra ayuda.

Un saludo.

cHackAll 24-03-2008 15:09:09

Justamente te iba a responder que utilices la API GetShortPathName, (que a proposito yo no le encuentro fallas), pero dadas las circunstancias creo que te aconsejaré que utilices la API misma utilizada en FindFirst y FindNext; las APIs son FindFirstFile, FindNextFile, y FindClose; las cuales utilizan la estructura TWIN32FindData que tiene dos cadenas en su definición; la primera es cFileName que utiliza los 260 caracteres de Güindos; y la segunda cAlternateFileName que contiene los nombres de los archivos en formato 8.3

Saludos

jhonalone 24-03-2008 20:29:42

ChakAll, gracias por tu interés, lo primero.
La situación está así con GetShortPathName:
en XP Pro y en Vista64 da error cuando le pides la ruta desde un subdirectorio que hace el número 5 ó más con las mismas 9 ó más letras iniciales iguales.
en ME no da ningún problema, he comprobado hasta con 12 subdirectorios, uno a uno.

Para mi caso particular está resuelto el problema desde el principio, pues en la instalación del programa, no permito cambiar la ruta y no es muy probable que haya 5 subdirectorios parecidos al mío, pero no me deja satisfecho el "gusanillo" ése que nos obliga a ser perfeccionistas...

Aunque pierda un poco de mi tiempo, intentaré con FindFirstFile del API y ya te conteré.

Te pego a continuación la función que utilizo en un proyecto de prueba para que la revises o la pruebes con otro sistema para ver lo de los 5 directorios.

Function Ruta:string;
var
RutaCorta:String;
DirActual:String;
corto:array [0..MAX_PATH] of char;
longitud:Cardinal;
begin
GetDir(0,DirActual);
Longitud:= Sizeof(Corto) -1;
GetShortPathName(PChar(DirActual),@corto,Longitud);
RutaCorta:=String(Pchar(@corto));
if Length(RutaCorta)>3 then Ruta:=RutaCorta+'\'
else Ruta:=RutaCorta; // si es el Dir Raiz C:\ ó A:\ la barra la pone sola
end;


y después la llamo desde un botón y lo escribo en un Edit

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.text:=Ruta;
end;

jhonalone 25-03-2008 01:43:40

Lo siento. Me rindo. Creo que Microsoft nos toma el pelo con el API. Son casi las 2 de la mañana y no puedo más. Llevo toda la tarde con esto y estoy bloqueado. Me devuelve vacia la cadena RegFich.cAlternateFilename, y sin embargo me devuelve correcta la de RegFich.cFilename.

Que alquien me lo explique. Yo desisto. A lo mejor tengo un error en el código y no me doy cuenta...

De todas formas creo que el tema no interesa mucho (Solo 27 visitas en dos dias)

function RutaDOS(NomFich:String): String;
label Salir;
var
RegFich: TWin32FindData;
Control: String;
DirActual: String;
RutaLarga: string;
NombreCorto: String;
RutaCorta: String;
xx: integer;
ControlBusqueda:THandle;
AlgoFalla:Boolean;
begin

//////////////////////////////////////////////////////////////////////////////
// Primero Transformamos la ruta de Directorios hasta el Actual a nombres cortos
// 1.- Obtenemos la ruta en que estamos
AlgoFalla:=False; //Control del resultado
GetDir(0,RutaLarga);
RutaLarga:=RutaLarga+'\'+NomFich;
//RutaCorta empieza vacía para ir añadiendo en while Length(Rutalarga) > 3
RutaCorta:='';

while Length(RutaLarga) > 2 // Si no es el directorio Raiz (Unidad:\)
do begin
//Buscamos el directorio que investigaremos actualmente
xx:=Length(RutaLarga);
while RutaLarga[xx]<>'\' do xx:=xx-1;
DirActual:=Copy(RutaLarga,xx+1,Length(RutaLarga)-xx);
Delete(Rutalarga,xx,Length(RutaLarga)-xx+1); // eliminamos el directorio que estamos comprobando
SetCurrentDirectory(PChar(RutaLarga+'\')); //Fijamos el directorio de búsqueda


ControlBusqueda:=FindFirstFile(PChar(RutaLarga+'\'+DirActual), RegFich);
if ControlBusqueda=INVALID_HANDLE_VALUE // Algo Falla
then begin
AlgoFalla:=True;
Goto Salir;
end
else begin // ControlBusqueda<>INVALID_HANDLE_VALUE No hay fallo
if RegFich.cFileName=DirActual
then NombreCorto:=String(RegFich.cAlternateFilename)
else while FindNextFile(ControlBusqueda,RegFich)
do if RegFich.cFileName=DirActual
then NombreCorto:=String(RegFich.cAlternateFilename);
end;// ControlBusqueda<>INVALID_HANDLE_VALUE

RutaCorta:=NombreCorto+'\'+RutaCorta;
end; //while Length(RutaLarga) > 2

RutaCorta:=RutaLarga+'\'+RutaCorta; // en DirActual debe quedar "Unidad\:"
// Aquí termina la ruta de los directorios
//////////////////////////////////////////////////////////////////////////////
Salir:
if AlgoFalla then RutaCorta:='';
RutaDOS:=RutaCorta;

// Terminamos uso de FindFirst/FindNext
Windows.FindClose(ControlBusqueda);
end;

cHackAll 25-03-2008 16:33:58

Cita:

Empezado por jhonalone (Mensaje 275022)
...Me rindo. Creo que Microsoft nos toma el pelo con el API...

No, la razón de la "ineficiencia" de la API no es algo casual;

Cita:

Empezado por GetShortPathName
Remarks

When an application calls this function and specifies a path on a volume that does not support 8.3 aliases, the function fails with ERROR_INVALID_PARAMETER if the path is longer than 67 bytes.


Cita:

Empezado por jhonalone (Mensaje 275022)
Que alquien me lo explique. Yo desisto. A lo mejor tengo un error en el código y no me doy cuenta...

Es probable, para futuras ocaciones por favor... utiliza las etiquetas para enmarcar tu código. Así como lo dejaste nadie lo analizará.

Cita:

Empezado por jhonalone (Mensaje 275022)
De todas formas creo que el tema no interesa mucho (Solo 27 visitas en dos dias)

No es un tema que interese o no a los miembros; la poca concurrencia en un hilo puede deberse a la dificultad de la pregunta, a la repetición, a que es un tema demasiado común, a las faltas a la guia de estilos o por cualquier otra causa.

Al grano;

Código Delphi [-]
function GetShortName(FileName: string): string;
var
 Actually: string;
 FindData: TWin32FindData;
 Pos, Count: Integer;
begin
 Count := 3;
 Result := Copy(FileName, 1, 2);
 while Count < Length(FileName) do
  begin
   Inc(Count);
   Pos := System.Pos('\', Copy(FileName, Count, MAX_PATH)) - 1;
   if Pos <> -1 then Inc(Count, Pos) else Count := MAX_PATH;
   Windows.FindClose(FindFirstFile(PChar(Copy(FileName, 1, Count - 1)), FindData));
   Result := Result + '\' + FindData.cAlternateFileName;
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 ShowMessage(GetShortName('C:\Documents and Settings\Administrator\Start Menu\Internet Explorer.lnk'));
end;

Animos!

jhonalone 25-03-2008 22:52:22

Otra vez Gracias cHakAll.
¡Qué mas quisiera yo que poder poner el código tan bonito como lo tengo en el editor de Delphi, pero no tengo ni idea cómo se hace.
Conste que he buscado en el foro, pero no sé cómo lo hacéis. Comprenderás que no soy muy experto en el foro, llevo sólo 19 ó 20 posts. Pero prometo enterarme para la próxima vez que tenga que poner código.
Bueno al grano, como dices tu.
Siento informarte que el resultado obtenido con la función GetShortName que me has puesto, es exactamente el mismo que el que he obtenido con la RutaDOS, que yo te puse, es decir este es el resultado: "C:\\\\", el número de barrras es el mismo que los subdirectorios que hay hasta llegar al raiz. Mi SO es WXP Professional.
Probado en el de mi hijo, que es Vista64, el resultado es idéntico, en el antiguo ME si funciona GetShortPathName, el RutaDOS y el GetShortName no los he probado.
Vuelvo a darte las gracias y te pido que no pierdas más tiempo con este tema, no lo merece.

Saludos Juan

cHackAll 25-03-2008 23:44:51

Código Delphi [-]
function GetShortName(FileName: string): string;
var
 Actually: string;
 FindData: TWin32FindData;
 Pos, Count: Integer;
begin
 Count := 3;
 Result := UpCase(FileName[1]) + ':';
 while Count < Length(FileName) do
  begin
   Inc(Count);
   Pos := System.Pos('\', Copy(FileName, Count, MAX_PATH));
   if LongBool(Pos) then Inc(Count, Pos - 1) else Count := MAX_PATH;
   Windows.FindClose(FindFirstFile(PChar(Copy(FileName, 1, Count - 1)), FindData));
   if FindData.cAlternateFileName[0] <> #0 then
    Result := Result + '\' + FindData.cAlternateFileName
   else
    Result := Result + '\' + StrUpper(@FindData.cFileName);
  end;
end;

El problema ocurria cuando el nombre dado era un 8.3 válido, ahora debería funcionar. Las etiquetas son [delphi] tu codigo aquí [/delph¡] ó el único boton cafe de la parte superior del editor.

Saludos

jhonalone 26-03-2008 00:27:55

Gracias cHackAll (Ahora lo he escrito bien eh!)
No te esfuerces. Esl fallo es de Microsoft. Ahora funciona (?) si no es en el quinto subdirectorio con 9 o más caracteres iguales. Como GetShortPathName. En el quinto subdirectorio pone las dos primeras letras del directorio mas 4 caracteres en base 16 más el caracter 126 (~) mas un 1 y la barra \:
mira es exactamente esto: C:\DATA\MISPRO~1\SUPERPAD\ES273A~1\RUTAW32.EXE
la ruta larga es esta:C:\DATA\Mis Programas y mis licencias\SuperPad\Estoesimposible5\
RutaW32.exe
Falla en el mismo sitio que GetShortPathName.
Esta es la primera función que hice:
[delphi]

Function Ruta:string;
var
RutaCorta:String;
DirActual:String;
corto:array [0..MAX_PATH] of char;
longitud:Cardinal;
begin
GetDir(0,DirActual);
Longitud:= Sizeof(Corto) -1;
GetShortPathName(PChar(DirActual),@corto,Longitud);
RutaCorta:=String(Pchar(@corto));
if Length(RutaCorta)>3 then Ruta:=RutaCorta+'\'
else Ruta:=RutaCorta; // si es el Dir Raiz C:\ ó A:\ la barra la pone sola
end;
[delphi/]

A ver si he aprendido lo del código.

El Resultado es el mismo. Ruego que lo compruebes moviendo el programita de prueba a un subdirectorio que sea el quinto con 9 o más caracteres iguales.

Siempre gracias por tu tiempo y tu esfuerzo.

Un saludo.

jhonalone 26-03-2008 00:31:14

Gracias cHackAll (Ahora lo he escrito bien eh!)
No te esfuerces. Esl fallo es de Microsoft. Ahora funciona (?) si no es en el quinto subdirectorio con 9 o más caracteres iguales. Como GetShortPathName. En el quinto subdirectorio pone las dos primeras letras del directorio mas 4 caracteres en base 16 más el caracter 126 (~) mas un 1 y la barra \:
mira es exactamente esto: C:\DATA\MISPRO~1\SUPERPAD\ES273A~1\RUTAW32.EXE
la ruta larga es esta:C:\DATA\Mis Programas y mis licencias\SuperPad\Estoesimposible5\
RutaW32.exe
Falla en el mismo sitio que GetShortPathName.
Esta es la primera función que hice:
Código Delphi [-]

Function Ruta:string;
var
   RutaCorta:String;
   DirActual:String;
   corto:array [0..MAX_PATH] of char;
   longitud:Cardinal;
begin
GetDir(0,DirActual);
Longitud:= Sizeof(Corto) -1;
GetShortPathName(PChar(DirActual),@corto,Longitud);
RutaCorta:=String(Pchar(@corto));
if Length(RutaCorta)>3 then Ruta:=RutaCorta+'\'
                       else Ruta:=RutaCorta; // si es el Dir Raiz C:\ ó A:\ la barra la pone sola
end;

A ver si he aprendido lo del código.

El Resultado es el mismo. Ruego que lo compruebes moviendo el programita de prueba a un subdirectorio que sea el quinto con 9 o más caracteres iguales.

Siempre gracias por tu tiempo y tu esfuerzo.

Un saludo.

P.D. No te rías, he puesto la raya descolocada...

jhonalone 26-03-2008 00:35:24

Gracias cHackAll:
Por todo lo que me has enseñado a mí y a todos en general. Por la labor de maestro que estás haciendo en el Foro.

Un saludo.

Juan.


La franja horaria es GMT +2. Ahora son las 12:34:44.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi