Utilisation de ces DLL de mesure par des logiciels d'application (MS-Windows)

      (retour au menu programmation 32 bits)
       
      Delphi FreePascal MSW-Logo PureBasic
      StarBasic (pour StarOffice) Lotus Script (Pour Lotus Suite 97) Python C++Builder
      Excel et VisualBasic
      Autres logiciels difficiles à utiliser avec les DLL Scilab SmallBasic et YaBasic PHP
      StarBasic (sans appel direct)
      UBasic QBasic TurboPascal Matlab
  1. Delphi

  2. Les essais de programmation ont été faits en Delphi 5.
    Il y a deux façons de lier les fonctions des DLL au programme principal :
    - la liaison statique, c'est à dire que le programme est prévu pour fonctionner avec une DLL connue dès la compilation. Ce n'est pas très intéressant ici, puisque ce système est conçu pour fonctionner avec différentes DLL, caractéristiques chacune d'un appareil de mesure.
    - la liaison dynamique, où l'on peut choisir la DLL à utiliser au moment de l'exécution (à condition, bien sûr, que cette DLL contienne les bonnes fonctions !). C'est cette méthode qui sera détaillée ici.
var l:thandle; (*type défini dans l'unité wintypes*)
var repchar : array[0..80] of char;
var stdneap : function(n:integer):pchar;stdcall;
    stdneadp :function(n:integer):pchar;stdcall;
var stdeap : function(n:integer):integer;stdcall
    stdeadp:function(n:integer):double;stdcall;
    stdcalibration:function:integer;stdcall;

puis, dans la section exécutable, on donne un contenu à ces fonctions :
  @stdeadp:=nil;
  @stdneadp:=nil;
  @stdcalibration:=nil;
  strpcopy(repchar,filename);
  L:=loadlibrary(repchar);
  @stdneadp:=getprocaddress(L,'stdnead');
  @stdeadp:=getprocaddress(L,'stdead');
  @stdcalibration:=getprocaddress(L,'stdcalibration');

éventuellement, on peut faire des tests pour savoir si la DLL est utilisable :
  if getprocaddress(L,'stdcalibration')<>nil
                   then reglages.enabled:=true
                   else reglages.enabled:=false;
                if (@stdeadp<>nil)and(@stdneadp<>nil) then okpiloteP:=true
                                                else okpiloteP:=false

Ensuite, les fonctions ainsi chargées pourront être utilisées normalement...

En principe, à la fin de l'utilisation de la librairie, par exemple lorsqu'on veut en charger une autre à sa place, il faut libérer la place par l'instruction FreeLibrary(L);

(début de page)
 

  • FreePascal

  • Le principe est exactement le même :
    program testdllfp;
    //mettre les options de compilation à compatibilité Delphi ou TP
    //l'option Mode à normal

    uses windows,sysutils,crt;

    var l:thandle;
    var repchar : array[0..80] of char;
    var stdneap : function(n:integer):pchar;stdcall;
    var stdneadp :function(n:integer):pchar;stdcall;
    var stdeap : function(n:integer):integer;stdcall;
    var stdeadp:function(n:integer):double;stdcall;
        stdcalibration:function:integer;stdcall;
    begin
    clrscr;
     @stdeadp:=nil;
      @stdneadp:=nil;
      @stdcalibration:=nil;
      strpcopy(repchar,'c:\projd5\pourfp\xadesfp.dll');
      L:=loadlibrary(repchar);
      @stdneadp:=getprocaddress(L,'stdnead');
     @stdeadp:=getprocaddress(L,'stdead');
      @stdcalibration:=getprocaddress(L,'stdcalibration');
      writeln(stdneadp(0));
     writeln(stdeadp(0));
     readln;
     end.
    (début de page)

    1. C++Builder
    La technique est assez semblable, mais il faut tenir compte du fait que ce logiciel semble avoir des exigences différentes de Delphi pour la déclaration des fonctions dans la DLL.
    Comme pour Delphi, on commence par déclarer les types, variables et fonctions à utiliser, en se souvenant que la casse des caractères a de l'importance (ne pas confondre minuscules et majuscules) :
       typedef char  *(*stddetailtype) ();
       typedef char *(*stdtitretype) ();
       typedef double (*stdeadtype) (int numvoie);
       typedef char *(*stdneadtype) (int numvoie);

       stddetailtype stddetail;
       stdtitretype stdtitre;
       stdeadtype stdstdead;
       stdneadtype stdstdnead;
    int a;
    HINSTANCE handle=NULL;
    char  repchar[60];
    String machaine;
    puis on charge la librairie :
    StrPCopy(repchar,"c:\\projd5\\xadestar.dll");
    handle=LoadLibrary(repchar);
    stddetail = (stddetailtype)GetProcAddress(handle,"stddetail");
    stdtitre = (stdtitretype)GetProcAddress(handle,"stdtitre");
    stdead = (stdeadtype)GetProcAddress(handle,"stdead");
    stdnead = (stdneadtype)GetProcAddress(handle,"stdnead");
    //Caption=stddetail();         //correct
    Caption=stdtitre();//correct
    //Caption=stdnead(0);     //correct;
    //Caption=String(stdead(0));  //correct;
    et à la fin de l'utilisation, on peut libérer la mémoire :
    FreeLibrary(handle);

    (début de page)

    1. PureBasic
    PureBasic est un langage de type Basic, mais très évolué. Il existe pour divers systèmes d'exploitation, MS-Windows, Linux et Amiga. Il est disponible en téléchargement sur le site www.purebasic.com.
    La version de démonstration (gratuite) est un peu bridée par rapport à la version complète (payante). Dans cette version de démonstration, on ne peut pas compiler de DLL ni faire de programmes exécutables autonomes, mais on peut utiliser les DLL déjà faites, et exécuter un programme PureBasic à partir de l'environnement de développement.

    On peut ajouter quelques points très agréables :
    - La version que je viens d'essayer (PureBasic 3.30) a les menus et l'aide en français (ou en anglais, ou en allemand...)
    - La syntaxe est automatiquement vérifiée et mise en évidence lors de la frappe

    Comme pour beaucoup de langages, il faut d'abord ouvrir la bibliothèque par OpenLibrary.
    Ensuite, on peut tester l'existence d'une fonction dans la bibliothèque par IsFunction, mais ce n'est pas obligatoire.
    Lorsqu'on veut utiliser une fonction, on l'appelle par CallFunction.
    Pour les fonctions avec paramètres, il faut utiliser celles qui sont compilées avec l'option stdcall (donc celles dont le nom commence par std dans ma nomenclature).
    Les fonctions qui renvoient un nombre sont utilisables sans difficultés car CallFunction renvoie directement la valeur numérique correspondante.
    Par contre, l'utilisation des fonctions qui renvoient une chaîne est un peu plus délicate. L'appel de CallFunction renvoie l'adresse de la chaîne en question, et il faut aller lire cette adresse par la fonction PeekS, qui renvoie la valeur de la chaîne se trouvant à l'endroit indiqué.
    A la fin, on ferme la bibliothèque par CloseLibrary.

    DefType .s machaine ; définit machaine comme une variable de type chaîne (.s = "string")
    If OpenLibrary(1,"c:\projd5\mgw32\pilotes\xadestar.dll")
     *F2=IsFunction(1,"ead")
     If *F2
        monresultat=CallFunction(1,"stdead",0)
        MessageRequester("message",Str(monresultat),2)
        *value2=CallFunction(1,"stdnead",0);
        machaine=PeekS(*value2)
        MessageRequester("message",machaine,2)
          EndIf
    EndIf
    CloseLibrary(1)
    L'essentiel est correct : les fonctions travaillant avec des entiers ou des chaînes de caractères sont utilisables, donc les fonctions d'entrée et de sortie analogiques simples, ainsi que les fonctions d'entrée et de sortie logiques et leurs noms sont correctes.
    Tout n'est pas parfait quand même ! PureBasic ne travaille pas avec des nombres réels de type «double», codés sur 8 octets, mais sur des nombres de type «single», codés sur 4 octets. Donc les fonctions stdead, stdsad et stdrsad ne sont pas utilisables, ce qui est bien dommage !.
    Que faire ? Rajouter des fonctions eas, sas, rsas («s» comme «single») serait fastidieux s'il fallait le faire pour les pilotes de tous les appareils, alors qu'apparemment, il n'y a que PureBasic qui n'utilise pas les réels de type «double».
    Une solution de rapport «efficacité/complication» acceptable est la suivante : faire une dll spéciale (nommée par exemple «xdll_double_single.dll») pour PureBasic, qui contient ces fonctions de type «single», qui elle-même appelle une dll normale, avec les valeurs de type «double». Pour que toutes les dll normales soient utilisables, on peut convenir de recopier systématiquement la dll de l'appareil de mesure à utiliser dans un fichier nommé «xdll_purebasic.dll».
    En consultant les développeurs de PureBasic, on m'a assuré que l'utilisation des réels de type "double" était en pour bientôt. Dès que ce sera fait, on pourra faire et utiliser avec PureBasic les mêmes bibliothèques qu'avec les langages Pascal et C++.

    (début de page)

    1. MSW-Logo
    C'est très simple :
    - On charge la DLL par l'instruction dllload :
    dllload "xadestar.dll
    - puis on utilise les fonctions par l'instruction dllcall, à laquelle on passe en paramètre le nom de la fonction (et éventuellement des paramètres) :
    print dllcall[s stddetail]
    print dllcall[f stdead w 0]
    où  f indique le type du résultat renvoyé par la fonction («float», c'est à dire un nombre réel de type double), w le type du paramètre («word», c'est à dire un entier), et 0 est la valeur de ce paramètre
    - enfin, on libère la mémoire de la DLL par
    dllfree

    Symboles des types de paramètres et de résultats :
    v = void (rien)
    w = word (entier)
    l = longword (entier long)
    f = float (réel de type double)
    s = string (spstr = chaîne de caractères à zéro terminal)
    Quelques remarques pour les habitués de Delphi :
    - l'état majuscule/minuscule est important
    - apparemment, pour les fonctions avec paramètres, il faut utiliser les fonctions déclarées avec le mot stdcall, ou à paramètres de type double.
    - apparemment aussi, l'ordre des paramètres est inversé par rapport à la déclaration en Delphi. Pour les fonctions avec deux paramètres, il faut appeler d'abord le deuxième, puis le premier.
    - enfin, il semble qu'une seule DLL est chargeable à la fois. Pour en utiliser une deuxième, il faut d'abord décharger la première..

    En résumé, pour faire une fonction «essai» qui affiche le nom de l'appareil, le nom de l'entrée analogique 0 et la valeur de cette entrée analogique, il suffit de faire dans l'éditeur :

    to essai
    dllload "c:/projd5/mgw32/pilotes/xdllvide.dll
    print [nom_détaillé]
    print dllcall[s detail]
    print [nom de l'entrée analogique 0]
    print dllcall[s stdnead w 0]
    print [valeur ea 0]
    print dllcall[f stdead w 0]
    dllfree
    end
     

    puis de sauvegarder ceci, et de frapper «essai» dans la ligne de commande.

    (début de page)
     
     

    1. Python
    Python est un langage interprété, existant pour Windows comme pour Linux (et d'autres systèmes d'exploitation).
    Les DLL précédemment décrites ne semblent pas pouvoir être directement appelées par Python, car ce logiciel demande des librairies («modules») rédigés avec une syntaxe particulière. Les exemples décrits dans la documentation concernent uniquement des librairies rédigées en langage C++.
    Dans la documentation Python, il est donc impossible de trouver un exemple d'écriture de librairies («dll», «module»...) écrit en Delphi.
    Heureusement, certaines personnes se sont aperçues de l'intérêt des deux langages, Delphi et Python, qui sont complémentaires par bien des aspects.
    C'est l'objet du logiciel «PythonForDelphi», qui fournit les briques nécessaires pour faire travailler ensemble Delphi (ou Kylix pour Linux) et Python. Il est impossible de les décrire simplement, mais en modifiant légèrement le fichier-exemple fourni, nommé «demodll», dans le répertoire «demos\demos09», il est possible d'appeler une DLL du type décrit précédemment, donc de faire des mesures à partir de Python.
    Principe de la librairie «demodll» modifiée
    Dans tout ce qui suit, on suppose que les fichiers sont disponibles dans le répertoire de travail de Python.
    Cette librairie définit 3 fonctions :
    - «add», fournie initialement avec l'exemple, qui additionne deux nombres passés en paramètres
    - «stdnead», qui renvoie le nom de l'entrée analogique dont le numéro est passé en paramètre
    - «stdead» qui renvoie la valeur lue sur l'entrée analogique dont le numéro est passé en paramètres.

    Pour cela, elle charge les fonctions «stdnead» et «stdead» dans la DLL nommée «xdll_python.dll».
    En fait, «xdll_python.dll» peut être n'importe quelle DLL du type décrit précédemment recopiée sous ce nom. L'essai a été fait avec xades101.dll, pour le boitier ADES.

    library demodll;

    {$I Definition.Inc}

    uses
      SysUtils,
      Classes,
      module in 'module.pas';
    exports
      initdemodll;
    {$IFDEF MSWINDOWS}
    {$E pyd}
    {$ENDIF}
    {$IFDEF LINUX}
    {$SOPREFIX ''}
    {$SONAME 'demodll'}
    {$ENDIF}

    begin
    end.

    Lorsqu'on compile demodll.dpr, le fichier compilé est renommé automatiquement demodll.pyd.

    Pour utiliser les autres fonctions de la dll, il suffitde déclarer ces autres fonctions selon la même méthode dans le fichier module.pas.

    Contenu du fichier «module.pas» modifié
    unit module;

    interface
    uses PythonEngine,wintypes,sysutils;

    procedure initdemodll; cdecl;

    var
      gEngine : TPythonEngine;
      gModule : TPythonModule;

    implementation
    var dll_nead:function(n:integer):pchar;
    var dll_ead:function(n:integer):double;

    function Add( Self, Args : PPyObject ) : PPyObject; far; cdecl;
    (*c'est la fonction d'exemple initiale*)
    var
      a, b : double;

    begin
      with GetPythonEngine do
        begin
          //syntaxe : d=double; i=integer ; s=string;
          if PyArg_ParseTuple( args, 'dd:Add', [@a, @b] ) <> 0 then
            begin
              Result := PyFloat_FromDouble( a + b );
            end
          else
            Result := nil;
        end;
    end;

    function stdead( Self, Args : PPyObject ) : PPyObject; far; cdecl;
    var
      a:integer;
    begin
      with GetPythonEngine do
        begin
          if PyArg_ParseTuple( args, 'i:stdead', [@a] ) <> 0 then
            begin
              Result := PyFloat_FromDouble( dll_stdead(a) );
            end
          else
            Result := nil;
        end;
    end;

    function stdnead( Self, Args : PPyObject ) : PPyObject; far; cdecl;
    var
      a:integer;
    begin
      with GetPythonEngine do
        begin
          if PyArg_ParseTuple( args, 'i:stdnead', [@a] ) <> 0 then
            begin
              Result := PyString_fromString(dll_stdnead(a));
            end
          else
            Result := nil;
        end;
    end;

    procedure initdemodll;
    var l:thandle;
    var repchar:array[0..100]of char;

    begin
    @dll_stdnead:=nil; @dll_stdead:=nil;
    strpcopy(repchar,'c:\progra~1\python221\xdll_python.dll');
    l:=loadlibrary(repchar);
    @dll_stdnead:=getprocaddress(l,'stdnead');
    @dll_stdead:=getprocaddress(l,'stdead');
      try
        gEngine := TPythonEngine.Create(nil);
        gEngine.AutoFinalize := False;
        gEngine.LoadDll;
        gModule := TPythonModule.Create(nil);
        gModule.Engine := gEngine;
        gModule.ModuleName := 'demodll';
        gModule.AddMethod( 'add', @Add, 'add(a,b) -> a+b' );
        gModule.AddMethod( 'stdead',@stdead,'stdead(a) -> entrée analogique double');
        gModule.AddMethod('stdnead',@stdnead,'stdnead(a) ->nom de l''entrée analogique');

        gModule.Initialize;
      except
      end;
    end;

    initialization
    finalization
      gEngine.Free;
      gModule.Free;
    end.

    Appel de la librairie «demodll.pyd»par Python
    C'est très simple, il suffit d'entrer les commandes suivantes :
    from demodll import *
    et les fonctions de la librairie deviennent disponibles.
    Si l'on frappe :
    print stdead(0), la valeur de l'entrée analogique 0 est affichée,
    print stdnead(1), le nom de l'entrée analogique 1 est affichée.
    (début de page)
     

    1. StarBasic, pour la suite bureautique StarOffice 5.2
    Cette suite bureautique est gratuite, disponible en plusieurs langues, puissante, et dispose du langage de programmation StarBasic. Tous ces avantages compensent le fait que ce soit un logiciel assez lent, et utilisant de gros fichiers.
    Au début du module, on déclare les fonctions à utiliser dans les DLL :
    Declare function eadouble lib "c:\projd5\mgw32\pilotes\xadestar.dll" alias "eadouble" (byval n as double) as double
    Declare function neadouble lib "c:\projd5\mgw32\pilotes\xadestar.dll" alias "neadouble" (byval n as double) as string

    Ensuite, dans le corps du programme en Basic, on utilise ces fonctions.

    Note pour les habitués de Delphi : comme pour d'autres logiciels, il faut tenir compte de la casse des noms des variables,
    Si les fonctions sont compilées avec stdcall, l'ordre des paramètres est le même que celui dans la déclaration dans Delphi ; par contre, si les fonctions ne sont pas compilées avec stdcall, l'ordre est inversé.
    Le plus simple est de ne pas les déclarer avec stdcall ; si l'on veut, on peut rajouter les fonctions stdeadouble, stdneadouble, etc...

    (début de page)

    1. LotusScript, pour la suite Lotus Smartsuite 97 (et autres ?)
    Le langage LotusScript est un Basic assez proche de StarBasic.
    - il veut que les paramètres soient déclarés byval
    - il veut les paramètres de type double, ou bien déclaration en std;
         - std : ordre normal
         - double non std : ordre inverse
         - std et double : ordre normal

    Declare Function neadouble Lib "C:\projd5\mgw32\pilotes\xadestar.dll" _
    Alias "neadouble" (Byval n As Double) As String

    Declare Function eadouble Lib "c:\projd5\mgw32\pilotes\xadestar.dll" _
    Alias "eadouble" (Byval n As Double) As Double

    Declare Function stdsbdouble Lib "c:\projd5\mgw32\pilotes\xadestar.dll" _
    Alias "stdsbdouble" (Byval voie As Double , Byval valeur As Double ) As Double

    Declare Function stdsb Lib "c:\projd5\mgw32\pilotes\xadestar.dll" _
    Alias "stdsb" (Byval voie As Integer , Byval valeur As Integer) As Integer

    Declare Function sbdouble Lib "c:\projd5\mgw32\pilotes\xadestar.dll" _
    Alias "sbdouble" (Byval voie As Double, Byval valeur As Double) As Double

    Declare Function sb Lib "c:\projd5\mgw32\pilotes\xadestar.dll" _
    Alias "sb" (Byval voie As Integer, Byval valeur As Integer) As Integer

    Sub Click(Source As Buttoncontrol)
     Messagebox Str$(stdsb(1,1)),MB_OK,"Demo"
    End Sub
    (début de page)
     
     

  • Tableur Microsoft-Excel, et langage VisualBasic

  • Le principe de la programmation est assez voisin de StarBasic.

    Sub Module1
    Declare Function stdead Lib "d:\dieumeg\xadestar.dll" (ByVal n As Integer) As Double
    Declare Function stdnead Lib "d:\dieumeg\xadestar.dll" (ByVal n As Integer) As String

    Sub MacroD()
    Rem ' MacroD Macro
    Rem ' Macro enregistrée le 31/01/03 par biologie
    Rem '
    Rem ' Touche de raccourci du clavier: Ctrl+Maj+D

    Rem     'ActiveCell.FormulaR1C1 = "=RC[2]"
    Rem     'Range("A2").Select
    Rem     'ActiveCell.Value = stdnead(1)
    Rem     ActiveCell.Value = 55
    Rem End Sub
    Rem '
    Rem ' MacroE Macro
    Rem ' Macro enregistrée le 31/01/03 par biologie
    Rem '
    Rem ' Touche de raccourci du clavier: Ctrl+Maj+E
    Rem '
    Rem     ActiveCell.Offset(-5, 4).Range("A1").Select
    Rem     ActiveCell.Value = 44
    Rem     ActiveCell.Value = stdnead(0)
    Rem End Sub
    Rem
    End Sub

    (début de page)

    1.  Que faire pour les logiciels qui ne peuvent pas utiliser les librairies à liaison dynamique ?
    Certains logiciels ne semblent pas prévus pour utiliser des fonctions de librairies extérieures. C'est le cas de certains langages de programmation simples tels que SmallBasic, qui est un langage de type Basic pouvant fonctionner sous divers systèmes d'exploitation (Windows, Linux, PalmOS...)
    D'autres peuvent théoriquement le faire, mais la façon de le faire est incompréhensible, ce qui revient au même. C'est le cas en particulier des logiciels mathématiques comme Scilab et Matlab, qui sont très puissants pour traiter les séries de valeurs numériques.
    Heureusement, ces logiciels sont souvent capables de lancer des programmes extérieurs.

    On peut donc imaginer de faire un petit programme (Delphi, C++ ou équivalent) capable d'appeler les DLL et de faire les mesures, puis d'envoyer ces mesures vers le logiciel principal.
    (début de page)

    Pilotes renvoyant directement le résultat au programme principal

    Position du problème
    Tous les  langages de programmation, et normalement tous les logiciels ayant des fonctions de programmation, permettent de lancer un programme extérieur.
    Pour certains de ces logiciels, le programme extérieur fait simplement son travail, puis s'arrête. Aucune information, ou très peu, n'est renvoyée vers le logiciel appelant. Dans ce cas, ce n'est pas très simple de faire un pilote. Il faut que le pilote fasse la mesure, puis qu'il enregistre le résultat dans un fichier, et qu'ensuite le logiciel principal lise le résultat dans le fichier.
    Heureusement, il existe des logiciels qui récupèrent directement dans un tableau de chaînes de caractères tous les caractères qui normalement auraient dû être envoyés vers l'écran par le pilote.
    Par exemple, supposons que le pilote doit écrire la chaîne de caractère «5.555» à l'écran, par l'instruction «writeln» de Pascal, ou «print» de Basic, ou «printf» de C++. Lorsque ce pilote est appelé par le logiciel, celui-ci récupère directement cette chaîne de caractère dans une variable. Il suffira donc ensuite de traiter cette chaîne de caractères par le logiciel, en la transformant en valeur numérique... C'est très pratique.
    Scilab est un logiciel de mathématiques, librement distribuable, et réalisé par l'INRIA.
    En fouillant dans la documentation en anglais, il semble capable d'être lié à des bibliothèques extérieures, mais cette documentation est très confuse.
    En revanche, il peut lancer des logiciels extérieurs, et surtout récupérer facilement le résultat.
    L'instruction la plus intéressante est unix_g.
    x=unix_g(commande)
    lance la commande «commande» du système d'exploitation. Cette commande peut être le nom du fichier à exécuter, suivi éventuellement d'instructions en ligne de commande.
    Le point le plus intéressant est que si cette commande doit écrire à l'écran (du type writeln de Pascal),  ce qui devrait être écrit à l'écran est envoyé vers la variable x.
    Par exemple x= unix_g('dir') exécute la commande «dir» du DOS, qui affiche la liste de tous les fichiers du répertoire en cours ; x contient donc la liste de ces fichiers, que l'on pourra traiter ensuite ...

     Un programme en Delphi pour Scilab, SmallBasic, Yabasic, et autres logiciels pouvant récupérer directement les valeurs
    program pdll32;
    (*programme appelant une bibliothèque dynamique de mesure, et envoyant le résultat
    à l'écran : à utiliser avec les logiciels interceptant les messages pour l'écran*)
    (* conçu initialement pour Scilab*)
    //p pour Print, imPrime...
    {$APPTYPE CONSOLE}
    uses
      sysutils,wintypes;

      var l:thandle;
      var repchar:array[0..80] of char;
      var nead:function(n:integer):pchar;
      var ead:function(n:integer):double;
      var stdead:function(n:integer):double;    stdcall;
      var stdnead:function(n:integer):pchar;    stdcall;
      var detail:function : pchar;
      var chemindll,nomfonction,chparam1,chparam2:string;
      var valparam1:double;
      var valparam2:double;
      var i:integer;

     begin
       chemindll:=paramstr(1);
      nomfonction:=paramstr(2);
      if paramcount>=3 then valparam1:=strtofloat(paramstr(3));
      if paramcount>=4 then valparam2:=strtofloat(paramstr(4));
      strpcopy(repchar,chemindll);
      @nead:=nil; @ead:=nil;@stdead:=nil;@stdnead:=nil;@detail:=nil;
       l:=loadlibrary(repchar);
       @nead:=getprocaddress(L,'nead');
       @ead:=getprocaddress(L,'ead');
       @stdead:=getprocaddress(L,'stdead');
       @stdnead:=getprocaddress(L,'stdnead');
       @detail:=getprocaddress(L,'detail');
       if nomfonction='ead' then writeln(ead(round(valparam1)):10:5);
       if nomfonction='nead' then writeln(nead(round(valparam1)));
       if nomfonction='stdead' then writeln(stdead(round(valparam1)):10:5);
       if nomfonction='stdnead' then writeln(stdnead(round(valparam1)));
       if nomfonction='detail' then writeln(detail);
      freelibrary(L);
    end.

    Utilisation de ce programme par Scilab
    Scilab est un logiciel de mathématiques, librement distribuable, et réalisé par l'INRIA.
    En fouillant dans la documentation en anglais, il semble capable d'être lié à des bibliothèques extérieures, mais cette documentation est très confuse.
    En revanche, il peut lancer des logiciels extérieurs, et surtout récupérer facilement le résultat.
    L'instruction la plus intéressante est unix_g.
    x=unix_g(commande)
    lance la commande «commande» du système d'exploitation. Cette commande peut être le nom du fichier à exécuter, suivi éventuellement d'instructions en ligne de commande.
    Le point le plus intéressant est que si cette commande doit écrire à l'écran (du type writeln de Pascal),  ce qui devrait être écrit à l'écran est envoyé vers la variable x.
    Par exemple x= unix_g('dir') exécute la commande «dir» du DOS, qui affiche la liste de tous les fichiers du répertoire en cours ; x contient donc la liste de ces fichiers, que l'on pourra traiter ensuite ...

    x=unix_g('scidll32.exe xadestar.dll ead 0')
    fait la mesure de l'entrée analogique 0 dans la bibliothèque xadestar, et envoie le résultat de la mesure dans la variable x.
    (début de page)

    Small Basic
    SmallBasic est un langage Basic gratuit, réalisé par Nicholas Christopoulos, et qui existe pour divers systèmes d'exploitation, en particulier Windows et Linux, mais aussi PalmOS et d'autres.
    L'instruction x=run(commande) envoie le résultat affichable de la commande dans la variable x.
    Par exemple, x=run("command.com /C dir *.exe") provoque l'envoi dans la variable x d'un ensemble de chaînes de caractères, résultat de la commande "dir *.exe ".
    On peut donc utiliser cette instruction pour lancer un petit programme de mesure, et récupérer le résultat, comme pour Scilab.
    x=run("c:/mes documents/scilab/scidll32 xadestar.dll nead 1")
    print x
    (début de page)
    Yabasic
    Yabasic est un petit langage Basic sans prétentions, d'origine allemande, et fonctionnant avec divers systèmes d'exploitation : Windows, Linux,... et même la console de jeux PS2, que je n'ai pas essayée...
    Il est téléchargeable en http://www.yabasic.de/yabasic.htm
    L'instruction
    a$=system$("dir *.exe /w ")
    envoie dans la variable a$ l'ensemble de chaînes de caractères correspondant à la commande dir *.exe /w.
    En remplaçant cette commande par l'appel à un programme de mesure, comme pour Scilab, on peut capturer le résultat de ce programme.

    PHP
    Normalement, PHP est un langage de scripts pour les serveurs Web.
    C'est le même principe, grâce à l'instruction system($commande), qui effectue la commande correspondant au contenu de la chaîne de caractère $commande.
     

    Logiciels ne pouvant pas récupérer directement le résultat de la commande)

    Le principe est le même : lancer un programme qui fait la mesure par l'intermédiaire d'une DLL. La différence est qu'il faut que ce programme fasse un fichier contenant le résultat de la fonction appelée dans la DLL. Ensuite, le logiciel principal lit le fichier et traite l'information contenue.
    Cette méthode est utilisable pour de très nombreux langages de programmation, y compris de vieux logiciels sous DOS tels que UBasic, QBasic, TurboPascal...
    Un programme en Delphi pour Matlab et autres logiciels
    program fdll32;
    //f  comme Fichier, File...
    uses
      sysutils,windows;
      var l:thandle;
      var repchar:array[0..80] of char;
      var nead:function(n:integer):pchar;
      var ead:function(n:integer):double;
      var stdead:function(n:integer):double;    stdcall;
      var stdnead:function(n:integer):pchar;    stdcall;
      var detail:function : pchar;
      var chemindll,nomfonction,chparam1,chparam2:string;
      var valparam1:double;
      var valparam2:double;
      var i:integer;
      var monfich:textfile;
      var nomfich:string;
    begin
      chemindll:=paramstr(1);
      nomfonction:=paramstr(2);
      if paramcount>=3 then valparam1:=strtofloat(paramstr(3));
      if paramcount>=4 then valparam2:=strtofloat(paramstr(4));
      strpcopy(repchar,chemindll);
      @nead:=nil; @ead:=nil;@stdead:=nil;@stdnead:=nil;@detail:=nil;
       l:=loadlibrary(repchar);
       @nead:=getprocaddress(L,'nead');
       @ead:=getprocaddress(L,'ead');
       @stdead:=getprocaddress(L,'stdead');
       @stdnead:=getprocaddress(L,'stdnead');
       @detail:=getprocaddress(L,'detail');
     assign(monfich,'fdll32.txt');
       rewrite(monfich);
        if nomfonction='ead' then writeln(monfich,ead(round(valparam1)):10:5);
       if nomfonction='nead' then writeln(monfich,nead(round(valparam1)));
       if nomfonction='stdead' then writeln(monfich,stdead(round(valparam1)):10:5);
       if nomfonction='stdnead' then writeln(monfich,stdnead(round(valparam1)));
       if nomfonction='detail' then writeln(monfich,detail);
       closefile(monfich);
      freelibrary(L);
    end.

    Utilisation par Matlab
    Le lancement du programme se fait en commençant la ligne par le point d'exclamation :
    !fdll32.exe xadestar.dll ead 1

    Ensuite, il faut lire le fichier «fdll32.txt» par Matlab.
    Si celui-ci contient une valeur numérique, par exemple renvoyée par ead, il n'y a pas de problème : a=load('fdll32.txt') envoie cette valeur dans la variable a.

    C'est un peu plus délicat pour les chaînes de caractères, par exemples celles renvoyées par «detail» ou par «nead». Matlab est un logiciel conçu pour traiter les nombre, et beaucoup moins pour traiter les chaînes de caractères.
    Ceci se fait par l'instruction textread, qui a un grand nombre de possibilités, assez confuses dans la documentation.
    On peut proposer :
    machaine=textread('fichres.txt','%c','whitespace','\t')'
    Quelques explications :
    l'instruction %c indique que l'on lit une chaîne de caractères.
    «whitespace» et «\t» indique que le caractère «espace» est la tabulation. Ceci peut paraître idiot, car il n'y a pas de tabulation dans le fichier, et que les espaces sont des vrais espaces entre les mots. Oui, mais si on ne met pas cette instruction, les espaces disparaissent dans la chaîne finale.
    Enfin, le caractère «'» final permet d'avoir une chaîne en ligne, alors que lorsqu'on l'omet, la chaîne est affichée en colonne. Ce n'est pas simple !

    autres logiciels :
    Python : à l'intérieur du module os (il faut donc faire  «from os import *»), il y a les commandes :
    - startfile, qui lance le logiciel qu'on lui passe en paramètre.
    - system, qui lance la commande-système qu'on lui passe en paramètre.
    Dans la pratique, pour Python pour Windows, le mieux est d'utiliser les DLL grâce au système PythonForDelphi, et pour Python pour Linux, d'utiliser les pilotes renvoyant directement le résultat de la mesure.

    StarOffice
    Bien sûr, StarOffice pour Windows permet d'utiliser les DLL. Mais il peut aussi lancer des fichiers extérieurs.
    En frappant le sous-programme ci-dessous dans StarBasic, puis en associant un bouton à ce sous-programme, on déclenche l'affichage d'une fenêtre montrant la valeur de l'entrée analogique 1.

    sub afficheead1
    Dim iNumber As Integer
    Dim aFile As String
    dim sline as string
    dim temps0 as long
    rem dim commande$ as string
    lignecommande$=dirdll$+"\fdll32.exe xdllvide.dll ead 1"
    aFile = "fdll32.txt"
    iNumber=Freefile rem ces trois lignes sont pour détruire le fichier fdll32.txt, s'il existe
    open aFile for output as #inumber
    close #inumber
    temps0=getsystemticks()
    shell(lignecommande$,false)
    while (filelen(afile)<2)and(getsystemticks()-temps0<1000)
     wend rem cette boucle attend que fdll32.exe ait fait son travail, fdll32.txt
    iNumber = Freefile
    Open aFile For input As #iNumber
    Line Input #iNumber, sLine
    close #inumber
    msgbox(val(sline))
    end sub
     

    UBasic
    GW-Basic (alias Basica) ne fonctionne plus sur les ordinateurs modernes. Mais le langage Ubasic, de Mr Yuji KIDA, gagne à être connu pour les nostalgiques : il a la même présentation que le vieux, très vieux GW-Basic, mais a une puissance mathématique époustouflante, et beaucoup plus de puissance générale.
    Le miniprogramme suivant affiche simplement le résultat de «detail» de la dll xdllrobot_com2.dll :
       10   doscmd "fdll32.exe xdllrobot_com2.dll detail"
       20   open "fdll32.txt" for input as #1
       30   input #1,Resultat$
       35   close #1
       40   print Resultat$

    Qbasic
    En un peu plus complexe, par exemple, voici un petit programme en Qbasic, qui commande l'activation et l'extinction, à intervalles réguliers, de la sortie analogique 0 de l'appareil correspondant à la bibliothèque xdllrobot_com2.dll.
    INPUT "Quelle est la durée de l'impulsion ?", dimp
    INPUT "quelle est la durée du cycle ?", dcycl
    tdepart = TIMER
    eteint = 1
    DO
    position = (TIMER - tdepart) MOD dcycl
    IF (eteint = 0) AND (position > dimp) THEN
            SHELL ("fdll32.exe xdllrobot_com2.dll sb 0 0")
            eteint = 1
            OPEN "fdll32.txt" FOR INPUT AS #1
            INPUT #1, reponse$
            PRINT reponse$
            CLOSE #1
            END IF
    IF (eteint = 1) AND (position <= dimp) THEN
            SHELL ("fdll32.exe xdllrobot_com2.dll sb 0 1")
            eteint = 0
            OPEN "fdll32.txt" FOR INPUT AS #1
            INPUT #1, reponse$
            PRINT reponse$
            CLOSE #1
            END IF
    LOOP UNTIL (TIMER - tdepart > 20)

     TurboPascal 7
    Ce programme fait la même opération que le précédent en  QBasic

    program testedll;
    uses dos,crt;
        {$M $4000,0,0 }   { 16K stack, no heap }
    const eteint:boolean=false;
    var fich:text;
        chainelue:string;
        tdepart:real;
        durimp,durcycle,position:longint;
     
    function tsecondes:real;
    var h,m,s,c:word;
    begin
    gettime(h,m,s,c);
    tsecondes:=h*3600+m*60+s+c/100;
    end;
     
     
    begin
      writeln('quelle est la durée d''une impulsion ?');
      readln(durimp);
      writeln('quelle est la durée d''un cycle ?');
      readln(durcycle);
      tdepart:=tsecondes;
        assign(fich,'fdll32.txt');
    repeat
      position:=round((tsecondes-tdepart)) mod durcycle;
      if (eteint and (position<durimp))
      then begin
           exec('fdll32.exe','xdllrobotcom2.dll stdsb 0 1');
           reset(fich);
           read(fich,chainelue);
           writeln(chainelue);
           close(fich);
           eteint:=false;
           end;
      if (not eteint)and(position>=durimp)
         then begin
              exec('fdll32.exe','xdllrobotcom2.dll stdsb 0 0');
              reset(fich);
              read(fich,chainelue);
              writeln(chainelue);
              close(fich);
              eteint:=true;
              end;
    until keypressed;
    end.

    (début de page)