Ver Mensaje Individual
  #1  
Antiguo 17-09-2013
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Reputación: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Cambiar datos (en runtime) de la versión de un ejecutable

Hola a todos,

A ver si alguien que, sin duda, sepa más que yo de estos menesteres, es capaz de echarme una mano. Quisiera cambiar los datos de la versión de un ejecutable en tiempo de ejecución. No se trata de cambiar los datos del mismo ejecutable en ejecución sino de otro que utilizo a modo de "plantilla".

He buscado por internet bastante, y, al cabo he encontrado hasta tres posibles implementaciones, pero, por distintos motivos, ninguna de ellas me sirve. Y, como no entiendo muy bien los intríngulis del asunto, pues tampoco soy capaz de adaptar ninguna de estas implementaciones para lograr lo que quiero.

El código fuente que mejor parece funcionarme, por diversas razones, es el que puede encontrarse en este mensaje del Borland Newsgroup Archive:

Código:
type
  PLangAndCodePage = ^TLangAndCodePage;

  TLangAndCodePage = packed record
    wLanguage: Word;
    wCodePage: Word;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  FileName: String;
  Size, Unused: DWORD;
  VerData: PByte;
  Value: Pointer;
  Len, VerLen, I: UINT;
  Translate: PLangAndCodePage;
  KeyName: WideString;
  FileVersion: LPWSTR;
  hUpdate: THandle;
  Updated: BOOL;
begin
  FileName := 'C:\program\myprog.exe';
  Size := GetFileVersionInfoSize(PChar(FileName), Unused);
  if Size <> 0 then
  begin
    GetMem(VerData, Size);
    try
      if GetFileVersionInfo(PChar(FileName), 0, Size, VerData) then
      begin
        Value := nil;
        Len := 0;
        VerQueryValue(VerData, '\', Value, Len);

        with PVSFixedFileInfo(Value)^ do
        begin
          dwFileVersionMS := MAKELONG(1, 1);
          dwFileVersionLS := MAKELONG(1, 1);
        end;

        Value := nil;
        Len := 0;
        VerQueryValue(VerData, '\VarFileInfo\Translation', Value, Len);

        Translate := PLangAndCodePage(Value);
        for I := 0 to (Len div SizeOf(TLangAndCodePage)) - 1 do
        begin
          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\FileVersion';

          Value := nil;
          VerLen := 0;

          // calling VerQueryValueW() directly so that the returned pointer is
          // pointing at the original Unicode data and not an Ansi copy...
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            FileVersion := PWideChar(Value);
            ZeroMemory(FileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(FileVersion, '1.1');

            // I'll leave it as an exercise for you to figure out what to do when your
            // new string value is larger than VerLen says is available. You will have
            // to reallocate VerData to make room for the extra characters, and
            // reassign various length fields to account for new offsets and such ...
          end;

          Inc(Translate);
        end;

        hUpdate := BeginUpdateResource(PChar(FileName), FALSE);
        if hUpdate <> 0 then
        begin
          Updated := UpdateResource(hUpdate, RT_VERSION,
            MAKEINTRESOURCE(VS_VERSION_INFO), MAKELANGID(LANG_NEUTRAL,
            SUBLANG_NEUTRAL), VerData, Size);
          EndUpdateResource(hUpdate, not Updated);
        end;
      end;
    finally
      FreeMem(VerData);
    end;
  end;
end;
Como se ve, ahí se trata de cambiar el campo "FileVersion" de la "tabla" con información de la versión. De hecho el código funciona estupendamente, empero, al tratar de cambiar otro campo como "ProductName", comienzan los problemas. El propio autor del código lo dice en un comentario:

Cita:
I'll leave it as an exercise for you to figure out what to do when your
new string value is larger than VerLen says is available. You will have
to reallocate VerData to make room for the extra characters, and
reassign various length fields to account for new offsets and such ...
En efecto, si uno trata de cambiar el campo "ProductName", mal que bien, el código sigue funcionando, pero, ya entramos en lo que no llego a comprender, y, por lo tanto, a poco que la cadena que trate de poner en "ProductName" sea más larga que la existente, todo se va al garete, pues la tabla con información de la versión se "sobreescribe", llegando a quedar completamente inválida.

Claro está que eso es justamente lo que el autor del código fuente dice que pasará si se trata de asignar una cadena mayor a la existente, pero, ¿cómo hacer para conseguirlo? El autor explica más o menos lo que hay que hacer: "You will have to reallocate VerData to make room for the extra characters, and reassign various length fields to account for new offsets and such..."... pero yo no logro entender qué tengo que hacer, exactamente, ni dónde ni cómo hacerlo.

¿Alguien tiene alguna idea? Yo, de forma chapucera, he intentado asignar, en tiempo de diseño, cadenas de caracteres "largas" a todo los campos de la información de la versión. Sin embargo, no he conseguido que esto funcione. Tal vez tenga que ver con que se trate de cadenas "variables", es decir, igual hay que "recolocar la memoria" siempre que se trate de cadenas variables, porque, al fin y al cabo el ejemplo de arriba cambia un campo de "longitud fija" (creo).

¿Alguien tiene alguna idea y quiere compartirla aquí?

P.D. Digo que la de arriba es la implementación que más me ha convencido porque es la más autocontenida. Las otras dos (código fuente de InnoSetup y las "utilidades para recursos" de Colin Wilson) no he podido hacerlas funcionar, por no decir que su código está más repartido en diferentes unidades, etc. Sin embargo todo esto es debido a mi desconocimiento, sin duda, puesto que tanto InnoSetup como XN Resource Editor (de Colin Wilson) son capaces de cambiar la información de la versión de un ejecutable...
__________________
David Esperalta
www.decsoftutils.com

Última edición por dec fecha: 17-09-2013 a las 22:05:14.
Responder Con Cita