1. Introduction

Ce document se propose :

  • de décrire le plus complètement possible les informations de version que l'on peut trouver dans un fichier binaire ;
  • de décrire l'API de gestion de ces informations de version ;
  • de décrire l'usage du programme "PatchVer".

Ce document s'intéresse uniquement aux informations de version des binaires dans les environnements Microsoft et il s'adresse plus particulièrement aux développeurs d'applications Microsoft.

1.1. Les informations de version

Il y a deux approches différentes pour inscrire les informations de version dans un binaire :

  • par l'environnement de développement ;
  • en modifiant de manière externe le binaire généré. Dans la littérature anglaise, on parle aussi de patch.

Ces deux approches ont chacune leurs avantages et leurs inconvénients :

  • la méthode intégrée par l'environnement de développement possède l'avantage d'être simple et immédiate. Toutefois, il n'est pas possible de tout faire. Ainsi, le changement et l'incrémentation du numéro de version du binaire généré sont rarement pris en compte. Il est possible de "jouer" avec les macros pour obtenir ce résultat mais cela restera une solution liée à l'environnement de développement considéré ;
  • la méthode de patch a l'avantage de ne pas dépendre de l'environnement de développement. Par contre, elle possède deux inconvénients. Tout d'abord, comme il s'agit d'un patch, on ne peut pas agrandir ou diminuer la zone de mémoire, on ne peut qu'écrire dedans en faisant attention à ne pas déborder. L'autre inconvénient, c'est que cette méthode va modifier le binaire extérieurement et peut donc invalider un checksum ou une signature mis en place par l'environnement de développement.

1.2. Pourquoi redévelopper un nouvel utilitaire ?

Il existe d'excellents programmes qui permettent de modifier les informations de version des binaires, celui que j'utilisais était le programme stampver.exe écrit par "Elphin". Il est simple et il rend le service.

Il souffre toutefois d'un défaut, il ne sait pas travailler avec des binaires en 64 bits. C'est une chose que j'ai découverte en développant ce programme, seul un binaire 32 bits peut modifier les informations de version d'un binaire 32 bits et seul un binaire 64 bits peut modifier les informations de version d'un binaire 64 bits.

Cela tient au fait que pour lire ou modifier une ressource, il faut utiliser la fonction LoadLibrary() de l'API Microsoft et que celle-ci ne permet pour un binaire 32 bits de charger un binaire autre que 32 bits.

Comme je développe en 64 bits, l'utilisation du logiciel "stampver.exe" n'était plus possible et je n'ai pas trouvé sur Internet de programme 32 bits et 64 bits fournissant le même service, j'ai donc été obligé d'en développer un.

2. Organisation d'une ressource version

Une ressource, de manière générale, est une information qui est ajoutée au binaire. Cela permet de livrer les ressources sans les fichiers annexes. Parmi ces ressources, on peut trouver des icones, des chaînes de caractères, des dialogues, des curseurs, des menus, des sons et beaucoup d'autres choses encore.

Les informations de version sont aussi des ressources inscrites dans le fichier.

Les fichiers binaires capables de "porter" des ressources sont les exécutables (.exe), les DLL (.dll), les drivers (.sys) enfin en règle générale, tous les binaires contenant du code et générés par un compilateur.

Les informations de version peuvent être affichées par l'explorateur de fichiers. Sous Windows Seven, cela donne l'aperçu suivant :

Affichage de la version d'un binaire par l'explorateur de fichiers
Affichage de la version d'un binaire par l'explorateur de fichiers

2.1. Rappel sur la compilation des ressources

La construction d'un binaire par un environnement de développement suit la procédure que voici :

  • les fichiers sources sont compilés par le compilateur du langage des fichiers sources, les résultats générés sont les fichiers objets ;
  • les fichiers de ressources sont compilés par le compilateur de ressources, le résultat généré est un fichier de ressources compilées ;
  • les fichiers objets ainsi que le fichier de ressources compilées sont ensuite liés ensemble lors de la phase d'édition de liens.

Le schéma suivant synthétise cette procédure :

La chaîne de génération d'un binaire
La chaîne de génération d'un binaire

2.2. Le contenu d'une ressource "version"

Les informations que l'on peut retrouver dans une ressource "version" sont les suivantes :

  • la version du fichier sous la forme de deux nombres de 32 bits. En général, cette version est affichée sous la forme aaa.bbb.ccc.ddd ;
  • la version du produit sous la forme de deux nombres de 32 bits. En général, cette version est affichée sous la forme aaa.bbb.ccc.ddd ;
  • une date sous la forme de deux nombres de 32 bits. La documentation MSDN ne précise pas quelle est la représentation utilisée pour ces deux nombres ;
  • un ensemble de flags qui permet de décrire un peu plus précisément l'emploi de ce binaire (application, DLL, driver, ...).

Une liste plus ou moins longue de chaînes de caractères. Ces chaînes de caractères sont "localisées", c'est-à-dire écrites pour plusieurs langues. C'est au développeur de décider quelles localisations il supportera dans la version. Toutes ces chaînes de caractères sont facultatives. Le contenu et l'usage de ces chaînes de caractères ne sont pas décrits dans la documentation MSDN, a priori, il est possible de les utiliser comme on le veut. Les chaînes de caractères connues à ce jour sont :

Identifiant Utilisation
ProductVersion Permet de spécifier la version du produit. Le contenu de cette chaîne peut être différent des valeurs binaires du champ ProductVersion vu ci-dessus (bien que cela ne soit pas très cohérent).
FileVersion Permet de spécifier la version du fichier. Le contenu de cette chaîne peut être différent des valeurs binaires du champ ProductVersion vu ci-dessus (bien que cela ne soit pas très cohérent).
Comments Permet d'introduire un commentaire dans la version.
CompanyName Permet de spécifier le nom de l'éditeur.
FileDescription Permet de décrire le fichier.
InternalName Permet de donner le nom interne du produit ou du fichier.
LegalCopyright Permet de spécifier les droits d'auteur.
LegalTrademarks Permet de spécifier les marques déposées.
OriginalFilename Permet de spécifier le nom d'origine du fichier (probablement en cas de réorganisation du projet et de changement de nom).
PrivateBuild Permet d'introduire un commentaire pour les compilations "privées".
ProductName Permet de spécifier le nom du produit.
SpecialBuild Permet d'introduire un commentaire pour les compilations "spéciales".

2.3. L'organisation de la structure "VS_VERSIONINFO"

La structure "VS_VERSIONINFO" est une structure hiérarchisée dont la représentation est la suivante :

L'organisation de la structure VS_VERSIONINFO
L'organisation de la structure VS_VERSIONINFO

Cette structure est décrite en détail dans le paragraphe suivant.

3. La structure "VS_VERSIONINFO" en détail

Les informations de version sont inscrites dans une structure du type "VS_VERSIONINFO". Autant vous prévenir tout de suite, cette structure est une horreur à analyser.

3.1. La structure "VS_VERSIONINFO"

La structure "VS_VERSIONINFO" est décrite dans le MSDN. Comme on peut le voir, il s'agit en fait d'une pseudostructure car certains champs ont une taille variable et peuvent commencer à des endroits différents suivant leur alignement. La taille de cette structure n'est donc pas connue à l'avance.

Définition de la structure VS_VERSIONINFO
Sélectionnez

typedef struct {
WORD             wLength;
WORD             wValueLength;
WORD             wType;
WCHAR            szKey;
WORD             Padding1;
VS_FIXEDFILEINFO Value;
WORD             Padding2;
WORD             Children;
} VS_VERSIONINFO;

Le champ "Value" de type "VS_FIXEDFILEINFO" commence à une adresse multiple de 4. Cette adresse - et donc son décalage par rapport au début de la structure - est fonction du membre "szKey" qui en fait est une chaîne de caractères et pas un simple caractère. Il y a donc 0 à 3 octets de padding à rajouter. De plus, la présence de la structure "VS_FIXEDFILEINFO" est facultative. Si le champ "wValueLength" vaut 0, il n'y a pas de structure "VS_FIXEDFILEINFO" dans la structure "VS_VERSIONINFO".

Pour la même raison que précédemment, il y a aussi un nombre variable d'octets de padding à rajouter (entre 0 et 3) à la suite de cette structure pour aligner correctement le membre "Children".

Le membre "Children" qui en fait n'est pas un WORD est décrit dans la documentation comme une table de 0 ou 1 membre de type "StringFileInfo" et 0 ou 1 membre de type "VarFileInfo". Si la structure "VS_VERSIONINFO" contient un champ "StringFileInfo" alors il doit contenir un champ "VarFileInfo".

Les autres structures ("StringFileInfo", "VarFileInfo"...) comportent aussi ce genre de particularité ce qui explique qu'il n'est pas simple d'analyser le contenu de cette structure.

3.2. La structure "VS_FIXEDFILEINFO"

La structure "VS_FIXEDFILEINFO" est décrite dans le MSDN. Comme on peut le voir, il s'agit d'une structure dont la taille est connue à l'avance qui ne contient que des informations sous forme de nombres.

Définition de la structure VS_FIXEDFILEINFO
Sélectionnez

typedef struct tagVS_FIXEDFILEINFO {
DWORD dwSignature;
DWORD dwStrucVersion;
DWORD dwFileVersionMS;
DWORD dwFileVersionLS;
DWORD dwProductVersionMS;
DWORD dwProductVersionLS;
DWORD dwFileFlagsMask;
DWORD dwFileFlags;
DWORD dwFileOS;
DWORD dwFileType;
DWORD dwFileSubtype;
DWORD dwFileDateMS;
DWORD dwFileDateLS;
} VS_FIXEDFILEINFO;

Les champs que l'on trouve dans cette structure sont :

Champs Utilisation Informations supplémentaires
dwSignature La valeur de ce champ est toujours "0xFEEF04BD". Cette signature permet d'identifier la structure.
dwStrucVersion La valeur de ce champ permet d'identifier la version de la structure (pour le cas où de nouveaux champs apparaîtraient). Actuellement la seule valeur supportée est "0x00010000" (version 1.0).
dwFileVersionMS et dwFileVersionLS Deux nombres de 32 bits qui permettent de définir la version du fichier. En général, cette version est affichée sous la forme aaa.bbb.ccc.ddd.
dwProductVersionMS et dwProductVersionLS Deux nombres de 32 bits qui permettent de définir la version du produit. En général, cette version est affichée sous la forme aaa.bbb.ccc.ddd.
dwFileFlagsMask Ce champ contient un masque de bits qui spécifie les bits valides du champ "dwFileFlags".
dwFileFlags Ce champ contient différents bits permettant de définir certains attributs du fichier. - DEBUG (0x01) : ce fichier contient des informations de débogage.
- PRERELEASE (0x02) : ce fichier est une version de développement, pas une version commerciale.
- PATCHED (0x04) : ce fichier a été modifié et n'est pas identique à la version officielle correspondant à ce numéro de version.
- PRIVATEBUILD (0x08) : ce fichier n'a pas été construit en utilisant les procédures de génération standard. Si ce bit est positionné, un commentaire devrait être introduit avec une chaîne de caractères "PrivateBuild".
- INFOINFERRED (0x10) : les informations de version ont été créées dynamiquement, en conséquence certaines de ces informations peuvent être incorrectes. Ce bit ne devrait jamais être positionné.
- SPECIALBUILD (0x20) : ce fichier a été construit en utilisant les procédures de génération standard mais c'est une variation par rapport à la version officielle correspondant à ce numéro de version. Si ce bit est positionné, un commentaire devrait être introduit avec une chaîne de caractères "SpecialBuild".
dwFileOS Ce champ contient différents bits permettant de définir le système d'exploitation pour lequel il est destiné. Ce champ est composé en deux parties, l'OS et les particularités de cet OS. - Pour l'OS on trouve les valeurs suivantes : MS-DOS (0x01), OS/2 16 bits (0x02), OS/2 32 bits (0x03), Windows NT (0x04), Windows CE (0x0x5).
- Pour les particularités de l'OS on trouve les valeurs suivantes : Windows 16 bits (0x01), Presentation Manager 16 bits (0x02), Presentation Manager 32 bits (0x03), Windows 32 bits (0x04). A signaler qu'il n'existe pas encore de valeur dans le MSDN pour les versions 64 bits de Windows.
dwFileType Ce champ permet de décrire le rôle du fichier. - APP (0x01) : ce bit indique que le fichier est une application.
- DLL (0x02) : ce bit indique que le fichier est une DLL.
- DRV (0x03) : ce bit indique que le fichier est un driver. Si ce bit est positionné, le champ "dwFileSubtype" contient d'autres informations au sujet de ce driver.
- FONT (0x04) : ce bit indique que le fichier est une fonte de caractères. Si ce bit est positionné, le champ "dwFileSubtype" contient d'autres informations au sujet de cette fonte.
- VXD (0x05) : ce bit indique que le fichier est un driver virtuel. Si ce bit est positionné, le champ "dwFileSubtype" contient l'identifiant du driver virtuel.
- STATIC_LIB (0x07) : ce bit indique que le fichier est une librairie statique.
dwFileSubtype Ce champ permet de compléter les informations du champ "dwFileType". - Si le champ "dwFileType" vaut DRV : COMM, DISPLAY, INSTALLABLE, KEYBOARD, LANGUAGE, MOUSE, NETWORK, PRINTER, SOUND, SYSTEM, VERSIONNED_PRINTER.
- Si le champ "dwFileType" vaut FONT : RASTER, TRUETYPE, VECTOR.
dwFileDateMS et dwFileDateMS Deux nombres de 32 bits qui permettent de définir la date de création du fichier. La documentation ne définit pas le format de cette date.

3.3. La structure "StringFileInfo"

La structure "StringFileInfo" est décrite dans le MSDN. Comme on peut le voir, il s'agit en fait d'une pseudostructure car certains champs ont une taille variable et peuvent commencer à des endroits différents suivant leur alignement. La taille de cette structure n'est donc pas connue à l'avance.

Définition de la structure StringFileInfo
Sélectionnez

typedef struct {
WORD        wLength;
WORD        wValueLength;
WORD        wType;
WCHAR       szKey;
WORD        Padding;
StringTable Children;
} StringFileInfo;

Le membre "Children" doit être aligné sur une frontière de 4 octets, il y a donc un nombre variable d'octets de padding à rajouter (entre 0 et 3) dans cette structure pour aligner correctement le membre "Children".

Le membre "Children" est une table de 1 ou plusieurs membres de type "StringTable". Il existe une entrée "StringTable" pour chacune des localisations des ressources chaîne de caractères prévues par le développeur.

3.4. La structure "StringTable"

La structure "StringTable" est décrite dans le MSDN. Comme on peut le voir, il s'agit en fait d'une pseudostructure car certains champs ont une taille variable et peuvent commencer à des endroits différents suivant leur alignement. La taille de cette structure n'est donc pas connue à l'avance.

Définition de la structure StringTable
Sélectionnez

typedef struct {
WORD   wLength;
WORD   wValueLength;
WORD   wType;
WCHAR  szKey;
WORD   Padding;
String Children;
} StringTable;

Le champ "szKey" contient une chaîne de caractères permettant de représenter la langue (le language identifier) et la page de code (la codepage) à utiliser pour représenter les chaînes de caractères de cette table.

Le membre "Children" doit être aligné sur une frontière de 4 octets, il y a donc un nombre variable d'octets de padding à rajouter (entre 0 et 3) dans cette structure pour aligner correctement le membre "Children".

Le membre "Children" est une table de 1 ou plusieurs membres de type "String". Il existe une entrée "String" pour chacune des chaînes de caractères définies dans la structure "version".

3.5. La structure "String"

La structure "String" est décrite dans le MSDN. Comme on peut le voir, il s'agit en fait d'une pseudostructure car certains champs ont une taille variable et peuvent commencer à des endroits différents suivant leur alignement. La taille de cette structure n'est donc pas connue à l'avance.

Définition de la structure String
Sélectionnez

typedef struct {
WORD  wLength;
WORD  wValueLength;
WORD  wType;
WCHAR szKey;
WORD  Padding;
WORD  Value;
} String;

Le champ "szKey" contient la chaîne de caractères permettant d'identifier la ressource.

Le membre "Children" doit être aligné sur une frontière de 4 octets, il y a donc un nombre variable d'octets de padding à rajouter (entre 0 et 3) dans cette structure pour aligner correctement le membre "Children".

Le membre "Children" est la valeur de cette chaîne de caractères.

3.6. La structure "VarFileInfo"

La structure "VarFileInfo" est décrite dans le MSDN. Comme on peut le voir, il s'agit en fait d'une pseudostructure car certains champs ont une taille variable et peuvent commencer à des endroits différents suivant leur alignement. La taille de cette structure n'est donc pas connue à l'avance.

Définition de la structure VarFileInfo
Sélectionnez

typedef struct {
WORD  wLength;
WORD  wValueLength;
WORD  wType;
WCHAR szKey;
WORD  Padding;
Var   Children;
} VarFileInfo;

Le rôle de cette structure semble être de définir le langage et la page de code à utiliser pour afficher les différentes ressources chaîne de caractères "version".

Le membre "Children" doit être aligné sur une frontière de 4 octets, il y a donc un nombre variable d'octets de padding à rajouter (entre 0 et 3) dans cette structure pour aligner correctement le membre "Children".

Le membre "Children" est une table de 1 ou plusieurs membres de type "Var". Il existe une entrée "Var" pour chacune des entrées "StringTable" définies dans la structure "version".

3.7. La structure "Var"

La structure "Var" est décrite dans le MSDN. Comme on peut le voir, il s'agit en fait d'une pseudostructure car certains champs ont une taille variable et peuvent commencer à des endroits différents suivant leur alignement. La taille de cette structure n'est donc pas connue à l'avance.

Définition de la structure Var
Sélectionnez

typedef struct {
WORD  wLength;
WORD  wValueLength;
WORD  wType;
WCHAR szKey;
WORD  Padding;
DWORD Value;
} Var;

Le membre "Children" doit être aligné sur une frontière de 4 octets, il y a donc un nombre variable d'octets de padding à rajouter (entre 0 et 3) dans cette structure pour aligner correctement le membre "Children".

Le membre "Children" est un tableau de DWORD contenant un identifiant de langage et une page de code (codepage) à utiliser pour afficher les ressources chaînes de caractères de la table "StringTable" correspondante. La partie haute de la valeur correspond à la page de code, la partie basse de la valeur correspond à l'identifiant du langage.

4. L'API de gestion des ressources "version"

4.1. Identification des ressources "version"

Rappel, une ressource est identifiée par deux choses :

  • son identifiant du type de ressource. Il existe plusieurs types de ressource différents parmi lesquels on trouve les dialogues, les menus, les versions, les icones...
  • l'identifiant de la ressource : il s'agit d'un nombre ou d'une chaîne de caractères qui permet d'identifier la ressource parmi toutes celles du même type.

Une ressource version est identifiée par l'identifiant de ressource dont le type est "RT_VERSION", sa valeur est 16.

Il peut y avoir plusieurs ressources "version" dans un fichier (même si cela n'a pas trop de sens), de toute façon, l'explorateur de fichiers n'en affiche qu'une seule. L'identifiant de la ressource "version" de référence est "VS_VERSION_INFO", sa valeur est 1.

4.2. Lecture des informations

Les fonctions suivantes sont utilisées pour lire les ressources et plus spécifiquement les ressources "version" :

Fonction Rôle
LoadLibrary() Cette fonction permet de charger un fichier binaire (binaire au sens large du terme) dans l'espace mémoire du processus courant. Cette fonction échoue si le processus courant est un processus 32 bits et que le fichier à charger est un binaire 64 bits et inversement. Ceci explique pourquoi le programme "PatchVer" est livré en version 32 bits et en version 64 bits.
FindResource() Cette fonction recherche une ressource d'un type donné (version, dialogue, menu...) dont son identifiant est fourni.
SizeofResource() Cette fonction permet de connaître l'espace (en nombre d'octets) occupé par une ressource particulière.
LoadResource() Cette fonction permet d'obtenir un handle logique sur une ressource quelconque.
LockResource() Cette fonction permet de transformer un handle logique sur une ressource en un "vrai" pointeur mémoire.
FreeLibrary() Cette fonction permet de décharger de l'espace mémoire du processus courant un fichier binaire préalablement chargé par LoadLibrary().

4.3. Mise à jour des informations

Les fonctions suivantes sont utilisées pour modifier les ressources et plus spécifiquement les ressources "version" :

Fonction Rôle
BeginUpdateResource() Cette fonction permet d'indiquer au système que l'on initialise une session de modification des ressources d'un binaire.
UpdateResource() Cette fonction permet de modifier une ressource d'un type donné (version, dialogue, menu...) dont l'identifiant est fourni.
EndUpdateResource() Cette fonction indique au système que l'on termine la session de modification des ressources d'un binaire.

4.4. Pourquoi ne pas utiliser cette API ?

La version 1.0 de "PatchVer" utilisait les API décrites dans les deux paragraphes précédents mais je me suis rendu compte que, dans certains cas et sans pouvoir en expliquer les raisons, cela corrompait le binaire modifié.

Il a donc fallu trouver une nouvelle méthode. Cette méthode consiste à analyser la structure COFF (Common Object File Format) et PE (Personal Executable) du fichier binaire, à parcourir les différents champs et à patcher directement le binaire.

Cette méthode est plus délicate car elle demande la compréhension détaillée des structures sous-jacentes par contre, elle offre un avantage indéniable, maintenant, le binaire 32 bits de PatchVer peut modifier les informations de version d'un binaire 32 ou 64 bits (de même pour le binaire 64 bits de PatchVer).

La description des différentes structures COFF et PE sort largement du cadre de ce document, cela fera l'objet d'un nouveau document.

5. Le programme "PatchVer"

Le programme "PatchVer" est un programme développé par moi-même qui permet de visualiser et aussi de modifier les informations de version d'un binaire. Il s'agit d'un utilitaire en lignes de commande.

Sur un OS 32 bits, vous ne pouvez utiliser que la version 32 bits. Sur un OS 64 bits, vous pouvez utiliser la version 32 ou 64 bits du programme.

Lors du lancement du programme (par un double clic dans l'explorateur de fichiers), si le message suivant s'affiche, cela signifie que les redistribuables Visual Studio ne sont pas installés.

Redistribuables Visual Studio non installés
Redistribuables Visual Studio non installés

Le projet complet et les sources peuvent être téléchargés ici. C'est un projet Visual Studio 2005 qui ne nécessite aucune autre bibliothèque mis à part les bibliothèques standard du système et les redistribuables Visual Studio.

5.1. Principales fonctionnalités

Les principales fonctionnalités de "PatchVer" sont les suivantes :

  • il permet l'affichage des informations de version. Cet affichage peut se faire sous une forme "humaine" et compréhensible ou bien sous la forme d'un dump en hexadécimal ;
  • il permet la mise à jour des informations de version en utilisant un fichier dit "fichier modèle" ;
  • il permet de générer un fichier modèle vierge.

Le programme "PatchVer" a été testé dans les environnements suivants :

  • Windows 2000 32 bits ;
  • Windows XP 32 bits ;
  • Windows Seven 64 bits ;
  • Windows 2003 32 bits ;
  • Windows 2003 64 bits ;
  • Windows 2008 64 bits.

Il n'a pas été testé dans les environnements suivants :

  • Windows Vista 32 bits ;
  • Windows Vista 64 bits ;
  • Windows Seven 32 bits ;
  • Windows 2008 32 bits.

Il ne fonctionne pas (et ne fonctionnera jamais) dans les environnements suivants :

  • Windows NT 4.0, Windows NT 3.51, Windows NT 3.5 ;
  • Windows Me, 98, 95 ;
  • Windows 3.11, 3.1, 3.0.

5.2. Les paramètres d'appel

Les paramètres d'appel à "PatchVer" sont les suivants :

Paramètre Rôle
-D Provoque l'affichage en mode "dump hexadécimal" de la ressource "version" du binaire.
-d Provoque l'affichage en mode "humain" de la ressource "version" du binaire.
-h ou /? ou pas de paramètre Provoque l'affiche de l'usage du programme.
-u Indique que le programme "PatchVer" va mettre à jour la date dans la ressource "version" du binaire.
-U Indique que le programme "PatchVer" va mettre à jour toutes les autres chaînes de caractères dans la ressource "version" du binaire.
-g Indique au programme "PatchVer" de générer un fichier modèle standard.
-r Permet de spécifier au programme "PatchVer" le nom du fichier binaire (ressource) dont on veut lire et éventuellement modifier la ressource "version". Le paramètre qui suit "-r" est le nom du fichier binaire.
-t Permet de spécifier au programme "PatchVer" le nom du fichier modèle (template) que l'on veut utiliser pour modifier la ressource "version". Le paramètre qui suit "-t" est le nom du fichier modèle.
-f Indique au programme "PatchVer" que l'on veut modifier le numéro de version FileVersion de la ressource "version". Le paramètre qui suit "-f" est le numéro de champ dans la version que l'on veut incrémenter. Sa valeur peut varier entre 0 et 4. Si le numéro de champ vaut 0, la valeur lue dans le fichier modèle est réécrite dans le binaire sans incrémenter le numéro de version.
-p Indique au programme "PatchVer" que l'on veut modifier le numéro de version ProductVersion de la ressource "version". Le paramètre qui suit "-p" est le numéro de champ dans la version que l'on veut incrémenter. Sa valeur peut varier entre 0 et 4. Si le numéro de champ vaut 0, la valeur lue dans le fichier modèle est réécrite dans le binaire sans incrémenter le numéro de version.
-F Indique au programme "PatchVer" que l'on veut modifier tous les numéros de version FileVersion (aussi bien binaires que chaînes de caractères) de la ressource "version". Le paramètre qui suit "-F" est le numéro de champ dans la version que l'on veut incrémenter. Sa valeur peut varier entre 0 et 4. Si le numéro de champ vaut 0, la valeur lue dans le fichier modèle est réécrite dans le binaire sans incrémenter le numéro de version.
-P Indique au programme "PatchVer" que l'on veut modifier tous les numéros de version ProductVersion (aussi bien binaires que chaînes de caractères) de la ressource "version". Le paramètre qui suit "-P" est le numéro de champ dans la version que l'on veut incrémenter. Sa valeur peut varier entre 0 et 4. Si le numéro de champ vaut 0, la valeur lue dans le fichier modèle est réécrite dans le binaire sans incrémenter le numéro de version.

5.3. L'affichage généré

En mode "humain", l'affichage est le suivant :

Affichage en mode humain
Sélectionnez

VS_VERSION_INFO
{
   FIXEDFILEINFO
   {
      FileVersion = 1.0.0.0
      ProductVersion = 1.0.0.0
      FileFlagsMask = DEBUG, PRERELEASE, PATCHED, PRIVATEBUILD, INFOINFERRED, SPECIALBUILD
      FileFlags = PRIVATEBUILD, SPECIALBUILD
      FileOS = NT, WINDOWS32
      FileType = APP
      FileSubtype = 0
      FileDate = 09/01/2011 17:45:35 UTC
   }
   StringFileInfo
   {
      StringTable "040904b0"
      {
         String "FileVersion" = "1.0.0.0"
         String "LegalCopyright" = "Copyright ® 2007-2011 Phoenix Team"
         String "ProductName" = "PatchVer"
         String "ProductVersion" = "1.0.0.0"
      }
   }
   VarFileInfo
   {
      Translation
      {
         Language=0x0409, Codepage=0x04b0
      }
   }
}

En mode "hexadécimal", l'affichage est le suivant :

Affichage en mode hexadécimal
Sélectionnez

e0 01 34 00 00 00 56 00 53 00 5f 00 56 00 45 00 ..4...V.S._.V.E.
52 00 53 00 49 00 4f 00 4e 00 5f 00 49 00 4e 00 R.S.I.O.N._.I.N.
46 00 4f 00 00 00 00 00 bd 04 ef fe 00 00 01 00 F.O.............
00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 ................
3f 00 00 00 28 00 00 00 04 00 04 00 01 00 00 00 ?...(...........
00 00 00 00 00 00 00 00 00 00 00 00 40 01 00 00 ............@...
01 00 53 00 74 00 72 00 69 00 6e 00 67 00 46 00 ..S.t.r.i.n.g.F.
69 00 6c 00 65 00 49 00 6e 00 66 00 6f 00 00 00 i.l.e.I.n.f.o...
1c 01 00 00 01 00 30 00 34 00 30 00 39 00 30 00 ......0.4.0.9.0.
34 00 62 00 30 00 00 00 30 00 08 00 01 00 46 00 4.b.0...0.....F.
69 00 6c 00 65 00 56 00 65 00 72 00 73 00 69 00 i.l.e.V.e.r.s.i.
6f 00 6e 00 00 00 00 00 31 00 2e 00 30 00 2e 00 o.n.....1...0...
30 00 2e 00 30 00 00 00 6a 00 23 00 01 00 4c 00 0...0...j.#...L.
65 00 67 00 61 00 6c 00 43 00 6f 00 70 00 79 00 e.g.a.l.C.o.p.y.
72 00 69 00 67 00 68 00 74 00 00 00 43 00 6f 00 r.i.g.h.t...C.o.
70 00 79 00 72 00 69 00 67 00 68 00 74 00 20 00 p.y.r.i.g.h.t. .
a9 00 20 00 32 00 30 00 30 00 37 00 2d 00 32 00 .. .2.0.0.7.-.2.
30 00 31 00 31 00 20 00 50 00 68 00 6f 00 65 00 0.1.1. .P.h.o.e.
6e 00 69 00 78 00 20 00 54 00 65 00 61 00 6d 00 n.i.x. .T.e.a.m.
00 00 00 00 32 00 09 00 01 00 50 00 72 00 6f 00 ....2.....P.r.o.
64 00 75 00 63 00 74 00 4e 00 61 00 6d 00 65 00 d.u.c.t.N.a.m.e.
00 00 00 00 50 00 61 00 74 00 63 00 68 00 56 00 ....P.a.t.c.h.V.
65 00 72 00 00 00 00 00 34 00 08 00 01 00 50 00 e.r.....4.....P.
72 00 6f 00 64 00 75 00 63 00 74 00 56 00 65 00 r.o.d.u.c.t.V.e.
72 00 73 00 69 00 6f 00 6e 00 00 00 31 00 2e 00 r.s.i.o.n...1...
30 00 2e 00 30 00 2e 00 30 00 00 00 44 00 00 00 0...0...0...D...
01 00 56 00 61 00 72 00 46 00 69 00 6c 00 65 00 ..V.a.r.F.i.l.e.
49 00 6e 00 66 00 6f 00 00 00 00 00 24 00 04 00 I.n.f.o.....$...
00 00 54 00 72 00 61 00 6e 00 73 00 6c 00 61 00 ..T.r.a.n.s.l.a.
74 00 69 00 6f 00 6e 00 00 00 00 00 09 04 b0 04 t.i.o.n.........

5.4. Le fichier de "modèle"

Le fichier modèle est un fichier supplémentaire dans lequel le programme "PatchVer" va lire les informations à inscrire dans la ressource "version" du binaire. Ce fichier est aussi modifié par le programme "PatchVer" pour enregistrer le dernier numéro de version utilisé (pour les entrées ProductVersion ou FileVersion).

Le format de ce fichier est le suivant :

Format du fichier modèle
Sélectionnez

ProductVersion=1.0.0.0
FileVersion=1.0.0.0
Comments=
CompanyName=
FileDescription=
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
PrivateBuild=
ProductName=
SpecialBuild=

La syntaxe de ce fichier est la suivante :

  • les lignes vides sont ignorées ;
  • les lignes débutant par le caractère "#" sont ignorées ;
  • les espaces et tabulations en début et en fin de ligne sont ignorés ;
  • une ligne valide est du type "identifiant" = "valeur" ;
  • les espaces et tabulations au début et à la fin des identifiants sont ignorés ;
  • les espaces et tabulations au début et à la fin des identifiants des valeurs sont ignorés ;
  • si une valeur est vide, aucune modification ne sera faite dans les informations de version correspondantes.

5.5. Déroulement du programme

Lors de l'exécution, le programme suit le déroulement suivant :

  • si le paramètre "-g" est spécifié, le fichier modèle est généré et le programme s'arrête ;
  • si le paramètre "-d" ou "-D" est spécifié, l'information présentée est l'information avant les éventuelles modifications ;
  • les modifications des informations de version sont effectuées en dernier et le fichier binaire modifié.

La gestion des erreurs est assez simpliste, dès qu'une condition d'erreur est détectée, le programme s'arrête en affichant un message d'erreur. Il n'y a aucune tentative de reprise sur une quelconque erreur.

Lors de la mise à jour des informations de version, s'il n'y a pas assez de place en mémoire pour écrire la nouvelle information, le message est affiché, il n'y a pas de modification de l'information de version correspondante mais le programme continue :

Pas assez de place en mémoire pour patcher
Sélectionnez

WARNING : Unable to patch 'Comments' string resource, not enougth room to add value 'A comment'

Pour modifier les chaînes de caractères de la structure, les conditions suivantes doivent être réunies :

  • le paramètre '-U' doit être spécifié lors de l'appel au programme ;
  • une chaîne de caractères doit exister dans la ressource "version", rappelez-vous, c'est un programme de patch, on ne peut modifier que ce qui existe ;
  • une chaîne de caractères non vide doit être spécifiée dans le fichier modèle ;
  • la taille de la chaîne de caractères existante doit être suffisamment grande pour permettre d'écrire la nouvelle chaîne de caractères.

Si l'une de ces conditions n'est pas vraie, la chaîne de caractères présente dans le binaire ne sera pas modifiée.

5.6. Exemples d'utilisation

Pour afficher les informations de version d'un binaire :

Afficher les informations de version
Sélectionnez

PatchVer -d -r <fichier à analyser>
 
ou
 
PatchVer -D -r <fichier à analyser>
 
ou encore
 
PatchVer -d -D -r <fichier à analyser>

Pour générer un fichier modèle standard :

Générer un fichier modèle
Sélectionnez

PatchVer -g -t <fichier modèle à générer>

Pour augmenter le numéro de version d'un binaire :

Augmenter le numéro de version
Sélectionnez

PatchVer -P 4 -t <fichier modèle à utiliser> -r <fichier à patcher>
 
ou
 
PatchVer -F 4 -t <fichier modèle à utiliser> -r <fichier à patcher>
 
ou
 
PatchVer -F 4 -P 4 -t <fichier modèle à utiliser> -r <fichier à patcher>
 
ou
 
...

5.7. Choix de développement

Certains choix ont été faits lors du développement du programme "PatchVer". Ces choix ont été pris parce que la documentation MSDN ne donne pas suffisamment d'informations pour connaître ou comprendre ce qu'a voulu Microsoft. Ces choix sont :

  • les informations concernant les identifiants de langage ainsi que les pages de code n'ont pas été prises en compte lors du traitement des différentes chaînes de caractères des ressources "version" ;
  • les champs dwFileDateMS et dwFileDateLS sont traités comme le poids fort et le poids faible d'une structure FILETIME. Cette structure permet de traiter des dates comprises entre le 01/01/1601 00:00:00 au 31/12/30827 23:59:59. La date affichée et enregistrée est la date UTC.

Si vous avez plus de précisions à ce sujet, n'hésitez pas à apporter votre commentaire dans la discussion dédiée : 3 commentaires.

5.8. Copyright

Sauf mention contraire, la documentation et les binaires inclus dans le logiciel PatchVer sont protégés par Phoenix Team.

Copyright © 2007-2011 Phoenix Team. Tous droits réservés.

Ce logiciel est fourni "en l'état", sans aucune garantie ni implicite ni explicite. En aucune manière, les auteurs ne pourraient être tenus pour responsables des dommages causés par l'usage de ce logiciel.

Tout le monde a la permission d'utiliser ce logiciel pour quelque usage que ce soit même commercial, de le modifier et de le redistribuer pourvu que les conditions suivantes soient remplies :

  • toute redistribution des codes sources doit conserver, sans modification, la mention de copyright présente ;
  • toute redistribution sous forme binaire doit conserver, sans modification, la mention de copyright actuelle ainsi que les adresses de sites Web déjà en place (dans la boîte de dialogue " À propos de... ", par exemple) ;
  • l'origine de ce logiciel ne doit pas être cachée ; vous ne pouvez pas dire que vous avez écrit ce logiciel. Si vous utilisez ce logiciel pour distribuer un produit, un remerciement dans la documentation du produit serait apprécié mais n'est pas obligatoire ;
  • toute version modifiée des sources ou des binaires doit être clairement identifiée et ne doit pas être présentée comme étant le logiciel original.

6. Conclusions

Voilà, cette présentation est maintenant terminée et j'espère que cet article aura permis de démystifier le rôle et l'utilisation des ressources "version". Usez et abusez sans modération du programme "PatchVer" et n'hésitez pas à apporter votre pierre à l'édifice en apportant vos remarques et commentaires dans la discussion prévue à cet effet : 3 commentaires.

6.1. Historique des versions

Version 1.1 (16 janvier 2001)

Bogues corrigés

  • Ajout de UTC lors de l'affichage de l'heure.
  • Intégration de PatchVer pour gérer les versions de PatchVer.
  • Corruption de certains binaires par PatchVer. Les fonction BeginUpdateResource(), UpdateResource() et EndUpdateResource() ne sont plus utilisées. PatchVer fait maintenant une analyse du format COFF pour pouvoir patcher le binaire.

Nouvelles fonctionnalités

  • Le level 0 est maintenant autorisé, le numéro de version du fichier modèle n'est alors pas incrémenté mais simplement mis à jour.
  • Le nom par défaut du fichier modèle est fixé à "PatchVer.inf".
  • Le dump hexa affiche la taille de la ressource.
  • Possibilité de patcher un fichier 32 ou 64 bits depuis un binaire 32 ou 64 bits.

Version 1.0 (9 janvier 2001)

Nouvelles fonctionnalités

  • C'est la première version donc tout est nouveau.

6.2. Remerciements

Je tiens à remercier ClaudeLELOUP et Djug pour l'aide qu'ils m'ont apportée lors de la relecture ce document.