Compiling exe file with Visual Basic
5 Control Creation Edition
Compiler un fichier exe avec Visual Basic 5 Control Creation
Edition
[ 1 ] - Introduction :
Il était une fois un programmeur qui surfait sur l'internet à la recherche de nouveauté dans l'univers en voie de disparition que l'on nomme Visual Basic 6. Quand soudain, il découvrit qu'il existait une version gratuite et fonctionnelle de son compilateur préféré : « Visual Basic 5 Control Création Edition » (voir http://support.microsoft.com/kb/165524/en-us). Parti à la conquête du trésor et désespérant sur les sites de l’éditeur complètement muet à son sujet, il trouve alors par le plus grand des hasards un lien de téléchargement (voir http://www.thevbzone.com/files/VisualBasic/VB5_CCE.zip). Une fois le programme sur son disque fraichement installé, il se lança dans la compilation d’un projet exe. Mais que se passe-t-il ? Il est impossible de compiler un exécutable car c’est très justement une version dédiée aux OCX ! Le programmeur fou de rage n’en resta pas là et décida de se lancer dans la plus grande des aventures jamais vécue dans le royaume du serviteur : « Faire compiler des exécutables fonctionnels à VB5CCE ».
[ 2 ] - Que fait Visual Basic :
Très bien, arrêtons les blagues et passons aux choses sérieuses.
Pourquoi je ne peux pas compiler des exécutable sur VB5CCE. Simple :
il compile uniquement des OCX. Que faire ? Dans un premier temps comprendre
le fonctionnement de VB5CCE. Facile : vb5cce.exe (l’ide) compile des .OBJ
puis passe la main à LINK.EXE pour finaliser l’OCX qui n’est
autre qu’une DLL. A première vue il suffirait de changer la ligne
de commande passée à LINK.EXE pour lui demander de compiler un
EXE (voir http://www.vbfrance.com/codes/PRENEZ-CONTROLE-COMPILATION-VOTRE-PROJET_24249.aspx).
Ok regardons la ligne de commande :
"C:\vb5cce\Project1.OBJ"
/ENTRY:__vbaS
/OUT:"C:\vb5cce\Project1.ocx"
/BASE:0x11000000
/SUBSYSTEM:WINDOWS,4.0
/VERSION:1.0
/DLL
/INCREMENTAL:NO
/OPT:REF
/MERGE:.rdata=.text
/IGNORE:4078
Tu as vu ? Le point d’entrée est « __vbaS » mais c’est
quoi cette fonction ? Personnellement je m’en fout puisque j’ai
décidé de la remplacer par une fonction qui fera ce que je veux.
D’accord mais quoi ? Si je regarde le code originel de l’OCX je
sais qu’il existe plusieurs fonctions invariables :
DllCanUnloadNow :
Renvoi l’état de la table d’objet… inutile dans notre
projet
DllRegisterServer :
Enregistre la dll dans la base de registre… Oula va falloir supprimer
cette fonction sans quoi notre base de registre sera vite saturée.
DllUnregisterServer :
Ouai… pourrait servir pour annihiler l’effet de DllRegisterServer.
DllGetClassObject :
Ah ! Voilà ce que je cherchais, une fonction qui pourrait instancier
le control utilisateur contenu dans mon OCX et exécuter du code.
Ca y est, j’ai trouvé, je vais créer un bout de code en
assembleur qui va instancier un « UserControl » contenu dans mon
OCX sans passer par la base de registre. Pour cela je m’appuierai sur
les principes de COM (voir http://msdn2.microsoft.com/en-us/library/ms680760(VS.85).aspx).
C’est parti !
[ 3 ] - Récuperer la ClassID :
La première chose à faire est de récupérer la classe id de notre user control. Faisons simple et rapide : Je compile une première fois l’OCX puis je récupère la ClasseId depuis la TypLib (voir http://msdn2.microsoft.com/en-us/library/ms694364(VS.85).aspx). Pour cela quelques lignes de codes :
Private Function
GetCLSID(ByRef lpFileName As
String) As
String
Dim Cls As New TLIApplication
Dim Obj As New TypeLibInfo
Dim i As Long
Set Obj = Cls.TypeLibInfoFromFile(lpFileName)
For i = 1 To Obj.CoClasses.Count
GetCLSID = Obj.CoClasses(i).Guid
Exit For
Next
Set Obj = Nothing
End Function
[ 4 ] - Le lanceur :
Maintenant que l’on a la ClassId on peut coder le lanceur. Rien de plus simple, j’ouvre notepad puis je tape quelques lignes d’assembleur (voir http://www.illmob.org/files/text/Accessing%20COM%20Objects%20from%20Assembly.html) :
Premièrement, j’appelle DllGetClassObject pour instancier IClassFactory
:
push offset $This
push offset $IID
push offset $CLSID
call DllGetClassObject
Deuxièmement j’instancie mon « UserControl » le tour
est joué:
push offset $This
push offset $IID
push 0
mov eax,$This
push eax
mov eax,[eax]
call dword ptr [eax+12]
[ 5 ] - Le lieur :
Je compile mon fichier assembleur et j’obtiens un fichier objet prêt à être lié avec le Projet.obj créé par Visual Basic. Il ne me reste plus qu’à les lier pour en faire un exécutable. Pour cela je modifie la ligne de commande de LINK.EXE avant appel :
y = CommandLine
y = Replace(y, "/ENTRY:__vbaS", "/ENTRY:Main")
y = Replace(y, "/DLL", "")
y = """" & TmpPath & "Stub.obj""
" & y
Call ShellAndHold(ExePath & "LINK2.EXE " & y, vbHide)
Et bien voilà j’ai mon fichier exécutable, c’est simple non ? Ah… j’oubliais, il faut absolument qu’on supprime la TypLib du programme sinon VB va nous l’enregistrer dans la base de registre et mettre le bazar. Aller encore quelques lignes de code. Faisons simple je sais qu’une TypLib commence par le mot magique « MSFT » alors on le trouve et on le remplace par des « XXXX » tant pis si VB fait la tronche on fera plus propre un autre jour :
Dim tmp As
String
Open FileName For
Binary As #1
tmp = String(LOF(1), 0)
Get #1, , tmp
tmp = Replace(tmp, "MSFT", "XXXX")
Put #1, 1, tmp
Close #1
Bon et bien on y est. On compile notre fichier Link.exe et on teste.
[ 6 ] - Conclusion :
Finalement ce n’était pas si dure de lui faire compiler des exécutables. On chope la ligne de commande de link.exe on ajoute un petit fichier objet et le tour est joué. On dispose maintenant d’un environnement gratuit, complet pour créer des petits programmes et se familiariser avec Visual Basic. Bien sûr, cela ne vaut pas une version entreprise, mais pour débuter que demander de plus ! Bon nule besoin de vous dire que la quete du programmeur n'est pas fini car moulte problemes restent à regler pour obtenir une version parfaite mais cela est une autre histoire...
Aller les sources à votre disposition ici (voir mylink.zip).
By EBArtSoft
2 février 2008