Recueil de recettes quasi-magiques utilisant le "Mix-Scripting"       (site non-furmeur)

 

       Menu 

 

 

 

 

 

 

  

 

 


Lorsque la consultation est terminée, vous pouvez revenir ici en cliquant sur le bouton "précédent" de votre navigateur, ou avec [Alt]-[flèche_gauche]

 

 



 

 

 



 

 


  Compiler du VBScript, en passant par le compilateur JScript.Net (jsc.exe)  


Jsc.exe, le compilateur JScript.Net est fourni avec le Framework.Net ; chez moi, il se situe dans le dossier 
           C:\Windows\Microsoft.NET\Framework\v2.0.50727
(la version peut changer, selon les machines).

Ce compilateur produit des exécutables très petits. Il a également deux autres avantages : 

  • il s'utilise en invite de commande
  • il peut gérer les objets/serveur COM ; y compris les objets COM dynamiques (dans TLB) ; y compris "ScriptControl".


ScriptControl est un objet très intéressant, qui permet d'exécuter du VBScript (ou du JScript). L'astuce va donc consister à embarquer le code-source VBscript dans une variable chaîne de JScript.Net, pour le faire exécuter par ScriptControl.

Ensuite, il nous suffira de compiler ce script, avec jsc.exe, pour obtenir un exécutable du code VBscript.

Certes, il ne s'agit pas d'une vrai compilation. Mais la différence est plus abstraite que pragmatique.

 

 1er exemple, pour montrer comment faire :

Commençons avec le magnifique code VBScript suivant : 
           msgbox "Bonjour, Monde ! "

Inutile de vous expliquer, car je pense que  vous aurez deviné tout seul ce que fait ce code.  (sinon, fermez cette page, et allez boire un coup à ma  santé).

Nous allons maintenant inclure ce code dans un script JScript.Net :

var vbs = new ActiveXObject("ScriptControl");
vbs.language="vbscript";

var code='msgbox "Bonjour, Monde ! "';

vbs.addcode(code);

Explications :

  - on ouvre l'objet  ScriptControl ;
  - on met le code en VBscript dans une variable (dans l'exemple, "code") ;
  - on lance le code.

Enregistrez ce fichier avec le nom  ex01.js 
Déjà, ce code fonctionne. Vous pouvez vérifier en invite de commande.

Pour compiler, toujours en invite de commande, tapez :

   C:\Windows\Microsoft.NET\Framework\v2.0.50727\jsc.exe ex01.js

(Attention : le chemin de jsc.exe est à adapter à votre cas (à votre ordinateur), selon la version de .Net installée)
Avant même que vous ayez eu le temps de dire "Ouaaiiiiiiisssssss !", la main vous est rendue. Le fichier ex01.exe a été créé.
Et, vous pouvez vérifier qu'il marche correctement.

Vous avez réalisé votre première compilation !

 

 2ème exemple, multi-lignes 

Voici le code-source VBscript de notre exemple multi-lignes : 

Set ws=CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts://./root/cimv2")
strWQL= "SELECT * " & _
 "FROM __InstanceCreationEvent " & _
 "WITHIN 2 " & _
 "WHERE TargetInstance ISA 'Win32_Process' " & _
 "AND   TargetInstance.Name = 'notepad.exe'"

Set objEventSource = objWMIService.ExecNotificationQuery(strWQL)
Set objEventObject = objEventSource.NextEvent()
ws.sendkeys("Azerty et Cie"& VBCRLF)

Ce script attend que Notepad (le bloc-notes) soit lancé, puis il envoie Azerty et Cie, en émulant le clavier. Le script contient des appels à des ActiveX et à WMI.
Vous noterez que le code-source contient des instructions multi-lignes (avec "_" finaux), pour corser le truc.

Voici le code-source JScript qui embarque (contient) le code VBscript :

var vbs = new ActiveXObject("ScriptControl");
vbs.language="vbscript";
var code="";

code = code+"Set ws=CreateObject("+'"'+"WScript.Shell"+'"'+")\n";
code = code+"Set objWMIService = GetObject("+'"'+"winmgmts://./root/cimv2"+'"'+")\n";
code = code+"strWQL= "+'"'+"SELECT * "+'"'+" & _\n";
code = code+" "+'"'+"FROM __InstanceCreationEvent "+'"'+" & _\n";
code = code+" "+'"'+"WITHIN 2 "+'"'+" & _\n";
code = code+" "+'"'+"WHERE TargetInstance ISA 'Win32_Process' "+'"'+" & _\n";
code = code+" "+'"'+"AND   TargetInstance.Name = 'notepad.exe'"+'"'+"\n";
code = code+"\n";
code = code+"Set objEventSource = objWMIService.ExecNotificationQuery(strWQL)\n";
code = code+"Set objEventObject = objEventSource.NextEvent()\n";
code = code+"ws.sendkeys("+'"'+"Azerty et Cie"+'"'+"& VBCRLF)\n";
code = code+"\n";

vbs.addcode(code);

Remarquez que les guillemets doubles ont été encadrés par des guillemets simples. Et aussi que chaque ligne se termine par \n 
Ce source JScript.Net se compile tout aussi bien, en un exécutable de moins de 6 ko.

Vous avez maintenant une idée du travail en multi-lignes, et du traitement nécessaire des guillemets.

 

 Limitations

Il y en a deux, importantes :

  • L'objet Wscript n'existe pas avec  ScriptControl  ; vous ne devrez donc pas utiliser ses méthodes ou propriétés. J'ai bien deux ou trois idées pour contourner ça, mais c'est dans le gros sac des "choses pour quand j'aurai du temps"...
  • dotNET doit être installé. Le Framework pour la compilation, et seulement le redistribuable pour l'exécution. Ceci dit, c'est maintenant presque toujours le cas.

 

 Un outil pour faciliter les choses

Je vous ai créé un petit utilitaire, qui :

  • prend un fichier .vbs (dont on indique le nom en paramètre)
  • transcode les lignes (pour traiter les guillemets)
  • ajoute le code JScript nécessaire (préfixe et le suffixe)
  • crée un fichier .js  (même nom que le fichier donné, mais avec l'extension  .js

Ensuite, il ne vous reste plus qu'à compiler ce fichier  .js  pour obtenir l'exécutable de vos rêves.

Pour télécharger l'utilitaire :   pvbs-compile.exe    

Exemple d'utilisation :
          pvbs-compile  ex01.js

Note :  j'ai fait cela très rapidement. Il faudrait que je le re-écrire en JScript.Net (ou en VBscript), pour diminuer sa taille.

 

 Retour d'infos, ou, si vous avez des choses à dire sur le sujet

Pour cela, je vous demande d'utiliser :

Merci d'avance.

 

 Et Ponx ?

Ce n'est pas vraiment l'objet du présent article. Mais, avec la même démarche, on peut créer de petits exécutables qui utilisent Ponx. De quoi de créer une librairie d'utilitaires assez facilement.

  

 



 PRINTDIR  et menu contextuel (clic-droit) dans l'explorateur  

Cet article va aborder deux choses différentes, mais complémentaires : 
  - imprimer un DIR, avec un batch
  - définir et utiliser une nouvelle entrée du menu contextuel de l'explorateur.


 PRINTDIR   -   DIR

Il est facile de voir le contenu d'un directory (dossier / répertoire / etc.), avec l'instruction DIR.  Il faut noter que DIR est une commande interne de Windows (il n'y a pas de fichier DIR.EXE), et s'utilie en invite de commande. Au passage, DIR est très rapide. Nettement plus que les développements réalisés avec des langages plus (ou moins) évolués. 
DIR possède de nombreuses options, pour sélectionner les éléments à visualiser, leur présentation, ou l'ordre d'affichage. Pour connaitre les différentes options,  il suffit de taper : 
          DIR  /?  {Entrée} 

Seulement, si DIR affiche le résultat, en vue de l'imprimer, nous avons besoin de l'enregistrer quelque part.  Chose très facile, en invite de commande, grâce à la redirection  avec le caractère  >  
La redirection va détourner (rediriger) l'affichage vers un fichier. Exemple : 
        DIR  *.jpg > mondir.txt
va créer le fichier "mondir.txt", qui contiendra le résultat. Petite astuce magique  : le préfixe %TEMP% pointe un répertoire temporaire. Cela permet d'éviter d'encombrer les directories de travail, avec de nombreux fichiers temporaires. Exemple d'utilisation : 
        DIR  *.jpg > %TEMP%\mondir.txt
Les répertoires temporaires étant vidés lors des opérations de nettoyage des disques, on n'a plus à se soucier de leur suppression, une fois leur nécessité obsolète.

Une autre petite astuce démoniaque  :  DIR accepte plusieurs spécifications de fichiers. Exemple : 
        DIR *.jpg *.jpeg *.gif *.bmp *.png 
va visualiser, d'un seul coup, tous les fichiers d'images que vous avez demandés.


 PRINTDIR   -   Imprimer 

Grâce à la redirection, nous avons un fichier "texte" contenant les données voulues. Pour l'imprimer automatiquement, il existe de nombreuses possibilités. Nous allons voir le Bloc-notes (notepad), et Wordpad (= write), qui sont fournis avec tous les windows (même si on peut les enlever de l'installation).
Voici la formule magique :    notepad /P nomdufichier     
Le paramètre  /P  indique à notepad d'imprimer le fichier, puis de terminer.  A noter que, à la place du Bloc-notes, il est possible d'utiliser Wordpad. Le paramètre ( /P ) est le même, et fonctionne de manière identique.  Mais, Wordpad est un peu plus gros, et très légèrement plus lent à se lancer. Cependant, Wordpad présente un autre intérêt, que nous verron plus loin.

Et voilà !  nous avons ce qu'il faut pour réaliser notre premier batch : 
        DIR *.* > %TEMP%\mondir.txt
        notepad /P %TEMP%\mondir.txt
Enregistrez ces lignes dans un fichier batch, se trouvant dans le PATH, et vous pourrez l'utiliser pour imprimer le directory courant.


 PRINTDIR   -   Imprimer les accents 

Si on sait mantenant imprimer un directory, on se rend vite compte que les noms de fichiers avec des accents sont mal imprimés. Pas de panique, c'est simplement dû à un conflit entre le code-page de l'invite de commande, et Windows. Pour y remédier, il existe, dans Windows, la commande CHCP.  Il suffit donc d'ajouter la ligne   CHCP 1252   à notre batch, pour indiquer à l'invite de commande que l'on veut travailler dans ce mode.
Notre batch capable d'imprimer les noms de fichiers accentués est donc devenu : 
        CHCP 1252
        DIR *.* > %TEMP%\mondir.txt
        notepad /P %TEMP%\mondir.txt



 PRINTDIR   -   Imprimer les caractères Unicode 

Maintenant que l'on est tout content de pouvoir imprimer les directories, même pour les fichiers contenant des accents, on tombe des nues, lorsqu'on s'aperçoit que les noms de fichiers contenant des caractères Unicode sont très mal imprimés. Et, les caractères Unicode, ça se répand de plus en plus. A commencer par le caractère (euro). 
Ne vous suicidez pas tout de suite !  Comme je suis déjà tombé sur le problème, j'ai cherché une solution, et j'ai trouvé un philtre magique qui convient. D'ailleurs, il s'agit plutôt d'un filtre, qui va transformer le fichier_texte/grenouille  en fichier_rtf_unicode/princesse.  Et, il n'est même pas nécessaire de faire un bisou à la grenouille !   
Cet utilitaire s'appelle Unirtf.exe ; pour l'obtenir, cliquez là :  télécharger_Unirtf.exe 

Autre élément à prendre en compte : comme on passe par un fichier RTF, il faut abandonner le Bloc-notes, et passer à Wordpad  (je vous avez dit, qu'il servirait).
Et aussi, pour que les caractères Unicode soient bien traités, il faut le préciser à l'invite de commande. Cela se fait avec l'option  /U  . Notre batch devient : 
        cmd /U /cdir *.* > "%TEMP%\listdir.txt"
        c:\unirtf.exe "%TEMP%\listdir.txt" "%TEMP%\Listdir.rtf"
        write /p "%TEMP%\Listdir.rtf"

Remarquez que j'ai jeté un sort particulier, pour troubler les esprits : j'ai utilisé  write  au lieu de Wordpad. En fait, sous Vista (ou XP),  write.exe  lance Wordpad.  L'avantage, c'est qu'il est dans le PATH  (en fait, dans C:\Windows), ce qui rend inutile d'indiquer le chemin. Mais, il est parfaitement possible d'utiliser  C:\Program Files\Windows NT\Accessories\wordpad.exe  (sous Vista ou XP).
On va compléter le batch avec deux lignes d'introduction.  Notre dernièe version devient alors : 
        :: PRINTDIR avec gestion des caractères Unicode
        @echo off
        cmd /U /cdir *.* > "%TEMP%\listdir.txt"
        c:\unirtf.exe "%TEMP%\listdir.txt" "%TEMP%\Listdir.rtf"
        write /p "%TEMP%\Listdir.rtf"







 Menu contextuel (clic-droit) dans l'explorateur  

Il est finalement assez simple d'ajouter une entrée (une ligne) dans le menu contextuel de l'explorateur. Il s'agit simplement de créer une clef du registre. Le nom de la clef détermine le texte dui apparaîtra dans le menu contextuel. Et la valeur par défaut de la sous-clef "command" doit contenir la commande qui sera exécutée ; en indiquant le paramètre %L windows enverra le directory sélectionné, comme paramètre de la commande (si plusieurs directories sont sélectionnés, windows enverra plusieurs paramètres).
Voici la formule magique du registre (ici, on a utilisé le texte PrintDir  pour le menu) : 
     HKEY_CLASSES_ROOT\Folder\shell\PrintDir\command
Et, dans la valeur par défaut : 
     C:\printdir.bat %L
On suppose que le batch s'appelle printdir.bat, et qu'il se trouve à la racine du C:  (C:\)
Comme baguette magique, le plus simple est d'utiliser REGEDIT. Toutefois, avec lui, vous devrez créer les sous-clefs les unes après les autres.

 


 Conclusion  

Vous avez maintenant un magnifique PRINTDIR, accessible avec un clic-droit, dans l'explorateur de Windows. Toute le monde est content, y compris Laurel & Hardy :

              

 

 

 

          

 MiniEdit - Un tout petit éditeur de texte, en .HTA              

Voici le recette d'un éditeur de texte de 885 octets. Et, pourtant, assez complet pour remplacer Notepad ! 

    


 Ingrédients                

Pour cette recette, nous allons utiliser les ingrédients suivants : 

  • un .HTA  (HTA = HTml Application), qui va nous apporter l'interface graphique (en HTML).
  • WSH (Windows Scripting Host), qui est une librairie existant en standard dans Windows.
  • un peu de JScript, pour lier tout ça.



 Source 
                         (comme le code est petit, le source tient dans une goutte)

Commençons par le code source intégral de notre projet. Les commentaires suivront. 

<HTA:APPLICATION SCROLL="no">
<html>
<script language='jscript'>
function init(){
  self.resizeTo(900,700);
  fso=new ActiveXObject("Scripting.FileSystemObject");
  hname=document.getElementById("BTfn");
  hedit=document.getElementById("EDIT");
}

function BTo(){
  hfile = fso.OpenTextFile(hname.value, 1, false, 0);
  hedit.innerText = hfile.ReadAll();
  hfile.Close();
}

function BTs(data){
  hfile = fso.OpenTextFile(hname.value, 2, false, 0);  
  hfile.Write(hedit.innerText);
  hfile.Close();
}
</script>

<body onload="init();" bgColor=#ddeeee>
<input id='BTfn' type=file />
<input id='BTo' onclick='BTo();' type=button value='Ouvrir' />
<input id='BTs' onclick='BTs();' type=button value="Sauver" /> &nbsp; MiniEdit, par Michel Claveau Informatique<br>
<textarea id="EDIT" rows="38" cols="105" name="EDIT" wrap="hard"></textarea>
</body></html>

Sauvegardez ce code dans un fichier nommé miniedit.hta (l'extension .hta est importante).

Notez, aussi, que l'on n'a même pas cherché à économiser les lignes, à "tasser" le code. Miniedit est un éditeur de 885 octets, mais qui a quand même sa dignité : il reste lisible, et a fière allure.

Ceux qui n'auraient pas envie de retaper le code, ou n'arriveraient pas à le copier / coller, pourront le télécharger, en cliquant sur ce lien :             miniedit.hta   

 


 Explications                                     
Le principe de miniedit est assez simple :         

  • Utilisation d'un élément HTML de type TextArea, pour la saisie/modification du texte.
  • Lecture / écriture du fichier avec Scripting.FileSystemObject, qui est un composant de WSH
  • Pour choisir un fichier, utilisation (détournée) de l'élément HTML  <input type=file/>, qui est souvent utilisé dans le but de sélectionner un fichier à envoyer sur le Web.

La zone de saisie est :
    <textarea id="EDIT" rows="38" cols="105" name="EDIT" wrap="hard"></textarea>

La fonction qui ouvre un fichier, et copie son contenu dans la zone de saisie est :
    function BTo()

La fonction qui lit le contenu saisi, et le sauve dans un fichier :
    function BTs()

Le champ qui détermine le nom du fichier est :
    <input id='BTfn' type=file />
il est repéré par la ligne hname=document.getElementById("BTfn");  il suffit ensuite d'utiliser sa propriété .value pour récupérer son contenu (le nom du fichier).

 


 Utilisation

Il faut lancer le fichier miniedit.hta. Ensuite, il est important de saisir un nom de fichier (ou d'ouvrir un fichier déjà existant).
Vous avez à votre disposition les mêmes possibilités que lors d'une saisie sur Internet : raccourcis-clavier, utilisation de la souris, pour sélectionner, utilisation du clic-droit, etc.