Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > API de Windows
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #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
Poder: 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
  #2  
Antiguo 26-10-2023
javier14 javier14 is offline
Miembro
 
Registrado: ago 2023
Posts: 12
Poder: 0
javier14 Va por buen camino
Conseguiste solucionarlo???
Responder Con Cita
  #3  
Antiguo 26-10-2023
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola a todos,

Sí; utilizando la siguiente función, si bien, probándola, he visto que todo parece ir bien excepto el "FileVersion"... parece que esa "clave" en particular no se cambia y no sé bien porqué ahora mismo... en fin... espero que te pueda servir.

Código Delphi [-]
(*
  Important about this method:

  This method can update the executable version information WHICH IS ALREADY
  SET FROM THE EXECUTABLE'S PROJECT'S OPTIONS!!!!

  What we do is to set a dummy 255 empties characters in every version
  information key, so, we can update it here up to 255 characters that keys.

  This is the only way in which we get this working!!
*)
function UpdateExeInfo(const ExePath, CompanyName, FileDescription,
     FileVersion, InternalName, LegalCopyright, LegalTrademarks, OriginalFileName,
      ProgramID, ProductName, ProductVersion, Comments: string): Boolean;
type
  PLangAndCodePage = ^TLangAndCodePage;
  TLangAndCodePage = packed record
    wLanguage: Word;
    wCodePage: Word;
  end;
var
  Size, Unused: DWORD;
  VerData: PByte;
  Value: Pointer;
  Len, VerLen, I: UINT;
  Translate: PLangAndCodePage;
  KeyName: WideString;
  AFileVersion: LPWSTR;
  hUpdate: THandle;
  Updated: BOOL;
begin
  Result := False;
  if not FileExists(ExePath) then
    Exit;

  Size := GetFileVersionInfoSize(PChar(ExePath), Unused);
  if Size <> 0 then
  begin
    GetMem(VerData, Size);
    try
      if GetFileVersionInfo(PChar(ExePath), 0, Size, VerData) then
      begin
        Value := nil;
        Len := 0;
        VerQueryValue(VerData, '\', Value, Len);

        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) + '\' + 'CompanyName';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(CompanyName));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'FileDescription';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(FileDescription));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'FileVersion';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(FileVersion));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'InternalName';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(InternalName));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'LegalCopyright';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(LegalCopyright));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'LegalTrademarks';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(LegalTrademarks));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'OriginalFileName';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(OriginalFileName));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'ProgramID';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(ProgramID));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'ProductName';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(ProductName));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'ProductVersion';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(ProductVersion));
          end;

          KeyName := '\StringFileInfo\' + IntToHex(Translate^.wLanguage, 4) +
            IntToHex(Translate^.wCodePage, 4) + '\' + 'Comments';
          Value := nil;
          VerLen := 0;
          if VerQueryValueW(VerData, PWideChar(KeyName), Value, VerLen) then
          begin
            AFileVersion := PWideChar(Value);
            ZeroMemory(AFileVersion, VerLen * SizeOf(WideChar));
            wsprintfW(AFileVersion, PWideChar(Comments));
          end;

          Inc(Translate);
        end;

        hUpdate := BeginUpdateResource(PChar(ExePath), 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;
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #4  
Antiguo 26-10-2023
javier14 javier14 is offline
Miembro
 
Registrado: ago 2023
Posts: 12
Poder: 0
javier14 Va por buen camino
Solo quería cambiar el FileVersion, pero gracias
Responder Con Cita
  #5  
Antiguo 26-10-2023
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola a todos,

Pues... como te he comentado... he visto que la función, precisamente, no cambia la clave "FileVersion"... sí todo lo demás... pero, precisamente, "FileVersion", no... cosa que no llego a entender ahora mismo.

Si puedes probarlo... y comentar aquí si a ti te cambia "FileVersion"... o sino lo consigues tampoco...
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Obtener la versión del ejecutable de una aplicación dec Trucos 1 20-02-2009 09:30:31
cambiar configuracion de datos en report manager en runtime fcobanda Impresión 0 20-09-2008 01:29:52
Como obtener de la información de versión del ejecutable Alcolea Varios 1 23-11-2006 23:50:32
como puedo hacer para cambiar un archivo de excel con versión 2.1 a versión 8.0 RONPABLO Servers 4 23-01-2006 06:02:38
Leer versión de un archivo ejecutable FerPetrei Windows 2 16-01-2004 20:41:42


La franja horaria es GMT +2. Ahora son las 20:58:19.


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
Copyright 1996-2007 Club Delphi