Modifier une ressource string d'un executable compilé (editeur de ressource)

Description

Ce code sert à modifier une ressource String d'apres son ID dans une dll ou tout executable win32.

les chaines de caracteres sont stockées par groupes de 16 chaines correspondant à 16 IDs
la structure est la suivante
Textlenght as integer
textUnicode as string
et ainsi de suite jusqu'a avoir 16 * 2 octets + la longueur des textes

NOUVELLE VERSION : avec possibilité de lister les chaines, d'en ajouter,d'en supprimer et d'en modifer :))

Source / Exemple :


'met à jour des ressources d'un executable compilé
Private Declare Function BeginUpdateResource Lib "kernel32" Alias "BeginUpdateResourceA" (ByVal pstrFileName As String, ByVal bDeleteExistingResources As Long) As Long
'met à jour une ressource d'un executable compilé
Private Declare Function UpdateResource Lib "kernel32" Alias "UpdateResourceA" (ByVal hUpdate As Long, ByVal lpType As Long, ByVal lpName As Long, ByVal wLanguage As Integer, lpData As Any, ByVal cbData As Long) As Long
'fini la mise à jour des ressources d'un executable compilé
Private Declare Function EndUpdateResource Lib "kernel32" Alias "EndUpdateResourceA" (ByVal hUpdate As Long, ByVal fDiscard As Long) As Long

'charge un executable ou dll
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibstrFileName As String) As Long
'trouve le handle de la ressource demandée
Private Declare Function FindResourceEx Lib "kernel32" Alias "FindResourceExA" (ByVal hModule As Long, ByVal lpType As Long, ByVal lpName As Long, ByVal wLanguage As Long) As Long
'charge la ressource en mémoire
Private Declare Function LoadResource Lib "kernel32" (ByVal hInstance As Long, ByVal hResourceInfo As Long) As Long
'renvoie un pointeur vers la ressource en mémoire
Private Declare Function LockResource Lib "kernel32" (ByVal hResourceData As Long) As Long
'renvoie la taille de la ressource en mémoire
Private Declare Function SizeofResource Lib "kernel32" (ByVal hInstance As Long, ByVal hResourceInfo As Long) As Long
'libère une dll ou un exe chargé
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long

'copie une zone de mémoire dans une autre
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

'une entrée d'une table de chaînes
Public Type StringTable
    ID As Long
    Texte As String
End Type

'===============================================================================
'les resource string d'un exe sont groupés par 16. ainsi par exemple le groupe 7
'contiendra les ID de 96 à 111
'pour trouver le groupe on utilise la formule :
'groupe = int(ID / 16) + 1 (le groupe 0 n'existe pas)
'===============================================================================
'strFileName = nom du fichier à modifier
'ID = identifiant de la ressource string (ex:101)
'strTexte = Texte à mettre à cet ID
'LangID = identifiant de la langue de l'ID (FR=1036)
Public Sub StringResourceModify(strFileName As String, ID As Integer, ByVal strTexte As String, LangID As Long)
    Dim ret As Long 'valeur renvoyée
    Dim hResource As Long 'handle du fichier en écriture
    Dim X As Long 'compteur
    Dim iGroup As Integer 'groupe
    Dim hObject As Long 'handle de l'objet ressource
    Dim hResourceData As Long
    Dim lpResourceData As Long
    Dim cbResource As Long 'taille de la ressource
    Dim hModule As Long 'handle du fichier en lecture
    Dim lpData() As Byte 'buffer de donnée
    Dim lpReadData() As Byte 'buffer de lecture
    Dim cbTexte As Integer
    
    If ID < 1 Then Exit Sub
    
    'on calcule le groupe de strings
    iGroup = Int(ID / 16&) + 1
    'on ouvre le fichier
    hModule = LoadLibrary(strFileName)
    'on cherche s'il y a deja des données dans le groupe iGroup
    hObject = FindResourceEx(hModule, 6&, iGroup, LangID)
    'on charge les éventuelles données
    hResourceData = LoadResource(hModule, hObject)
    'on vérouille la mémoire qui contient l'éventuelle groupe iGroup
    lpResourceData = LockResource(hResourceData)
    'on cherche la taille de la ressource iGroup
    cbResource = SizeofResource(hModule, hObject)
    
    If cbResource <= 32 Or hObject = 0 Then
        'pas de ressource ayant ce nom (numéro de groupe)
        ' vu que l'on enregistre q'un seul strTexte sur 16
        'il y a 15 * 2 octets pour les tailles des 15 chaines vides
        '+ 2 octets pour la taille du strTexte que l'on enregistre
        '+ longueur du strTexte * 2 octets pour le strTexte Unicode (un caractère suivi d'un chr(0))
        cbResource = 32& + Len(strTexte) * 2&
        'on redimensionne le tableau qui va contenir les données
        ReDim lpData(cbResource - 1)
        'on copie la longueur du strTexte à l'emplacement 2 * le nombre d'enregistrements avants l'ID
        cbTexte = Len(strTexte)
        CopyMemory lpData(2& * (ID - (iGroup - 1) * 16&)), cbTexte, 2&
        'si le strTexte est different de ""
        If Len(strTexte) Then
            'on le copie 2 octets plus loin que l'emplacement précédent
            CopyMemory lpData(2& + 2& * (ID - (iGroup - 1) * 16&)), ByVal StrPtr(strTexte), Len(strTexte) * 2
        End If
    Else
        'une ressource iGroup est contenu dans le fichier
        'nous n'allons modifier que le strTexte qui nous intéresse
        'on prépare pour cela un buffer qui va contenir les données déjà présentes
        ReDim lpReadData(cbResource - 1)
        'on copie les donnée de l'emplacement mémoire que l'on a vérouillé avant
        CopyMemory lpReadData(0), ByVal lpResourceData, cbResource
        
        Dim countX As Long 'un compteur
        Dim CHECKLNG As Integer 'la longueur des strings
        'on copie toutes les données contenues dans les ids < à notre ID
        For X = 0 To (ID - (iGroup - 1) * 16&) - 1
            CopyMemory CHECKLNG, lpReadData(countX), 2&
            countX = countX + 2 + CHECKLNG * 2
        Next
        'on copie la longueur du strTexte à remplacer
        CopyMemory CHECKLNG, lpReadData(countX), 2&
        'on redimensionne le tableau qui va contenir les données modifiées
        ReDim lpData(countX + 2 + Len(strTexte) * 2 + (cbResource - (countX + 2 + CHECKLNG * 2)) - 1)
        'on copie les données qui précédent notre ID
        CopyMemory lpData(0), lpReadData(0), countX
        'on copie la longueur de notre strTexte
        cbTexte = Len(strTexte)
        CopyMemory lpData(countX), cbTexte, 2&
        'si notre strTexte <> ""
        If Len(strTexte) Then
            'on le copie 2 octets + loin
            CopyMemory lpData(countX + 2), ByVal StrPtr(strTexte), Len(strTexte) * 2
        End If
        'on copie le reste des données lues
        If (cbResource - (countX + 2 + CHECKLNG * 2)) > 0 Then
            CopyMemory lpData(countX + 2 + Len(strTexte) * 2), lpReadData(countX + 2 + CHECKLNG * 2), (cbResource - (countX + 2 + CHECKLNG * 2))
        End If
    End If
    'on ferme le fichier
    FreeLibrary hModule
    
    'on ouvre le fichier en écriture dans lequel on va modifier un strTexte
    hResource = BeginUpdateResource(strFileName, ByVal 0&)  'byval 0& : on ne supprime pas les resources du fichier
    'on modifie la ressource iGroup
    ret = UpdateResource(hResource, 6&, CLng(iGroup), CInt(LangID), lpData(0), UBound(lpData) + 1)
    'on modifie le fichier
    ret = EndUpdateResource(hResource, ByVal 0&)
End Sub

'===============================================================================
'les resource string d'un exe sont groupés par 16. ainsi par exemple le groupe 7
'contiendra les ID de 96 à 111
'pour trouver le groupe on utilise la formule :
'groupe = int(ID / 16) + 1 (le groupe 0 n'existe pas)
'===============================================================================
'strFileName = nom du fichier à modifier
'LangID = identifiant de la langue de l'ID (FR=1036)
Public Function StringResourceList(strFileName As String, LangID As Long) As StringTable()
    Dim ret As Long 'valeur renvoyée
    Dim hResource As Long 'handle du fichier en écriture
    Dim X As Long 'compteur
    Dim iGroup As Integer 'groupe
    Dim hObject As Long 'handle de l'objet ressource
    Dim hResourceData As Long
    Dim lpResourceData As Long
    Dim cbResource As Long 'taille de la ressource
    Dim hModule As Long 'handle du fichier en lecture
    Dim lpData() As Byte 'buffer de donnée
    Dim lpReadData() As Byte 'buffer de lecture
    Dim Out() As StringTable
    Dim countX As Long 'un compteur
    Dim CHECKLNG As Integer 'la longueur des strings
    Dim temp As String 'un buffer
    
    ReDim Out(0)
    'on ouvre le fichier
    hModule = LoadLibrary(strFileName)
    'on parcours le 4096 groupes (ID 1 à 65535) possibles
    For iGroup = 1 To 4096
        'on cherche s'il y a des données dans le groupe iGroup
        hObject = FindResourceEx(hModule, 6&, iGroup, LangID)
        'on charge les éventuelles données
        hResourceData = LoadResource(hModule, hObject)
        'on vérouille la mémoire qui contient l'éventuelle groupe iGroup
        lpResourceData = LockResource(hResourceData)
        'on cherche la taille de la ressource iGroup
        cbResource = SizeofResource(hModule, hObject)
        'on vérifie si la taille est correcte
        If cbResource >= 31 And hObject <> 0 Then
            'une ressource iGroup est contenu dans le fichier
            'on prépare un buffer qui va contenir les données présentes
            ReDim lpReadData(cbResource - 1)
            'on copie les donnée de l'emplacement mémoire que l'on a vérouillé avant
            CopyMemory lpReadData(0), ByVal lpResourceData, cbResource
            
            'on mets les variables à zéros
            countX = 0
            X = 0
            'on lit les données
            Do While countX < UBound(lpReadData)
                'on copie la taille de la chaine qui suit
                CopyMemory CHECKLNG, lpReadData(countX), 2&
                'on ajoute 2 à la position actuelle pour etre soit au début de la chaine soit à la taille suivante
                countX = countX + 2
                'si la chaine n'est pas nulle
                If CHECKLNG Then
                    'on ajoute un item au tableau
                    ReDim Preserve Out(UBound(Out) + 1)
                    'on mets l'ID dans ID
                    Out(UBound(Out)).ID = (iGroup - 1) * 16& + X
                    'on prépare un buffer pour la chaine
                    temp = Space(CHECKLNG * 2)
                    'on copie la chaine
                    CopyMemory ByVal StrPtr(temp), lpReadData(countX), CHECKLNG * 2
                    'on enregistre la chaine dans le tableau
                    Out(UBound(Out)).Texte = temp
                    'on se place au début de la chaine suivante
                    countX = countX + CHECKLNG * 2
                End If
                'on passe à la chaine suivante
                X = X + 1
            Loop
        End If
    Next
    'on ferme le fichier
    FreeLibrary hModule
    'on renvoie le tableau
    StringResourceList = Out
End Function

Conclusion :


n'hésitez pas à mettre des commentaires :)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.