Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   ¿GetFileVersionInfo modifica su primer parámetro? (FileName, la ruta de archivo dada) (https://www.clubdelphi.com/foros/showthread.php?t=81232)

roman 25-10-2012 03:26:26

Oye Al, y las clases de terceros que has visto, ¿hacen lo mismo o algo similar? Porque buscando código en internet he visto algunos ejemplos que parece que se limitaron a copiar y pegar el código de Delphi, así que no sé hasta que punto realmente refuerzan la idea de que hay algo de cierto o sólo copian lo que vieron.

// Saludos

Al González 25-10-2012 19:26:08

En efecto, Román, varias clases de terceros reproducen la misma leyenda, haciendo lo mismo con la cadena de la ruta de archivo. Dan toda la impresión de que simplemente se basaron en el código de la función de Delphi. Y claro, eso contribuye a "meter miedo". Cabe decir que no he encontrado algo que vaya en la misma dirección bajo código escrito en otros lenguajes.

Algo que certidumbre se obtiene al ver otros ejemplos en Delphi que se olvidan de la susodicha precaución, como esta clase de David Simpson con más de 1400 descargas desde la página de Embarcadero, creada en 1999 y actualizada hasta el año 2003:

http://cc.embarcadero.com/Item/13836

Esta otra del proyecto JEDI, actualizada hasta el año 2009:

http://upload.infosae.com.br/APLICAT...lFileUtils.pas

Y hasta de los propios compañeros del club:

http://www.clubdelphi.com/foros/show...232#post394232

En principio crearé mi clase sin esa desechada previsión (dejando sólo una breve nota alusiva al tema). Mientras tanto, veremos si hay oportunidad y tiempo de probar con versiones antiguas de Delphi y Windows, o de contactar a los creadores de las funciones GetFileVersionInfo (Microsoft) y GetComCtlVersion / GetFileVersion (Borland / Embarcadero).

Cualquier dato para sumar al tema es bienvenido.

Saludos.

roman 25-10-2012 19:36:18

Algo que no me queda claro es en qué afectaría que la rutina de la API escribiera sobre el argumento. No recuerdo cómo funciona el paso de parámetros de tipo string, o cómo afecta el modificador const. Porque si el parámetro pasa a la pila, como otros parámetros, no tendría porque haber problemas, aunque quizá fuera necesario no usar const, tal como, por cierto, hace el código de rastafarey.

// Saludos

Al González 25-10-2012 21:05:40

Cita:

Empezado por roman (Mensaje 447956)
Algo que no me queda claro es en qué afectaría que la rutina de la API escribiera sobre el argumento. No recuerdo cómo funciona el paso de parámetros de tipo string, o cómo afecta el modificador const. Porque si el parámetro pasa a la pila, como otros parámetros, no tendría porque haber problemas, aunque quizá fuera necesario no usar const [...]

Con valores que tienen contadores de referencias, usar Const es más eficiente, se reduce en varias instrucciones el código máquina de la función que declara el parámetro. De lo contrario se añade una referencia más a la cuenta. Prescindir del Const sólo tiene sentido si el parámetro ha de usarse también como variable de trabajo (modificable) dentro de la función que declara el parámetro. Esta es una buena convención que vino a inculcar Borland, y en lo personal (y saliéndome un poco del tema) he de decir que la extiendo más allá de los parámetros que usan contadores de referencias, es decir, hasta con parámetros simples como los de tipo Integer suelo usar Const si la rutina no ha de modificar su valor (ahí no hay impacto en el código máquina generado, pero lo hago porque puede ser informativo para el programador que lea el código).

Respecto a la primera parte de tu duda, hice este ejemplo para ayudar a esclarecerla:

Código Delphi [-]
Procedure Modificar (C :PChar);
Begin
  StrCopy (C, '¡X!');
End;

Procedure Proc1 (S :String);
Begin
  Modificar (PChar (S));
End;

Procedure Proc2 (Const S :String);
Begin
  Modificar (PChar (S));
End;

procedure TForm1.Button1Click(Sender: TObject);
Var
  Nombre :String;
begin
  Nombre := Self.Name;

  // Antes de ser modificado el nombre
  ShowMessage ('El nombre del formulario es: ' + Nombre);
  ShowMessage ('El nombre del formulario es: ' + Self.Name);

  Proc1 (Nombre);  // O bien "Proc2 (Nombre);"

  // Después de ser modificado el nombre
  ShowMessage ('El nombre del formulario es: ' + Nombre);
  ShowMessage ('El nombre del formulario es: ' + Self.Name);
  
  Close;
end;

En pantalla aparecerán los resultados:

Cita:

El nombre del formulario es: Form1

El nombre del formulario es: Form1

El nombre del formulario es: ¡X!

El nombre del formulario es: ¡X!
Todo reside en el hecho, como habrás de recordar, de que las variables y parámetros de tipo String no guardan el valor de la cadena, sino un puntero hacia dicho valor.

Para quienes inicien en el tema de los punteros-cadena, lo siguiente puede ayudar a entenderlo:

-- Memoria RAM --
...
Byte 3400: 'F'
Byte 3401: 'o'
Byte 3402: 'r'
Byte 3403: 'm'
Byte 3404: '1'
Byte 3405: #0 (fin de la cadena)
...

Al comienzo Self.Name es igual a 'Form1', porque la propiedad Name del formulario es un puntero de valor 3400. Al procedimiento Modificar le termina llegando ese valor (3400) como parámetro puntero (PChar) y, en esa ubicación de memoria, cambia la 'F' por '¡', la 'o' por 'X', la 'r' por '!' y la 'm' por #0 (nuevo fin de la cadena).

Espero haberme explicado. :)

Casimiro Noteví 25-10-2012 21:17:31

Estas cosas se entienden muy bien si conoces el lenguaje ese que no te gusta, el C :D

roman 25-10-2012 21:40:58

Cita:

Empezado por Al González (Mensaje 447960)
Espero haberme explicado. :)

Sí, claro. Gracias.

Por un momento pensé que si no se usaba const entonces el parámetro no pasaba como apuntador, pero ya veo que no es así.

Por lo que se ve, esto va a ser más misterioso que el CopyObject :rolleyes:

// Saludos

escafandra 25-10-2012 22:30:15

Hablando de C, la API GetFileVersionInfo se muestra así en MSDN:
Código:

BOOL WINAPI GetFileVersionInfo(LPCTSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
LPCTSTR lptstrFilename es lo mismo que const char* lptstrFilename, es decir que lptstrFilename apunta a una cadena de caracteres, estilo C, constante o lo que es lo mismo, la API GetFileVersionInfo no va a modificar el valor apuntado por lptstrFilename.

De forma que tal y como se declara en este momento GetFileVersionInfo se puede usar sin necesidad de una variable de paso sin temor a que sea modificada.

En mi opinión cualquier comentario encontrado en el código que ponga en duda la integridad del valor de la cadena de caracteres pasada como parámetro no hace otra cosa que intimidar y confundir al que posteriormente lo lea y muy posiblemente se encuentre versión tras versión como temor ancestral que nadie se atreve a combatir. :D


Saludos.

ecfisa 25-10-2012 22:50:36

Hola.

Yo tenía la misma idea que lo que menciona escafandra. Pero para quitarle cualquier resquicio a la duda, estuve haciendo unas pruebas e incluso con estas alteraciones del código no se registra cambio alguno:
Código Delphi [-]
function GetFileVer(var aFileName: string): Cardinal;
var
  InfoSize, Wnd, VerSize: DWORD;
  VerBuf: Pointer;
  FI: PVSFixedFileInfo;
begin
  Result := Cardinal(-1);
  InfoSize := GetFileVersionInfoSize(PChar(aFileName), Wnd);
  if InfoSize <> 0 then
  begin
    GetMem(VerBuf, InfoSize);
    try
      if GetFileVersionInfo(PChar(aFileName), Wnd, InfoSize, VerBuf) then
        if VerQueryValue(VerBuf, '\', Pointer(FI), VerSize) then
          Result:= FI.dwFileVersionMS;
    finally
      FreeMem(VerBuf);
    end;
  end;
end;

Saludos.:)

Al González 26-10-2012 00:13:03

Gracias, escafandra, ecfisa. Creo que desafiaré a la leyenda... :)

Casi, me gusta programar en C, pero como no soy conformista, busco algo que además de potencia posea elegancia y un toque de "humano", de ahí mi predilección por Pascal. ^\||/

Román, ¿creerás que esta gente de Embarcadero ha estado haciéndole cambios a la función _CopyObject? Aunque, según se mira en System.pas, sólo para adaptarla junto con muchas otras a 64 bits. Algún día sabremos cuál es (¿era?) su misterioso propósito. ;)


La franja horaria es GMT +2. Ahora son las 04:48:45.

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