Et pour Linux ?

(retour au menu programmation 32 bits)
Les DLL pour Windows sont peu différentes des objets partagés de Linux. Après quelques modifications, elles peuvent être compilées par Kylix.
 
 
Ecriture d'objets partagés en Kylix Ecriture d'objets partagés en FreePascal Ecriture d'objets partagés en C++
Appel d'objets partagés en Kylix Appel d'objets partagés en C++ Appel en divers langages
Pilotes exécutables dont le logiciel récupère directement le résultat : écriture du pilote exécutable en Kylix appel du pilote exécutable en Scilab Appel du pilote exécutable en SmallBasic et Yabasic
appel du pilote exécutable en Python Que faire pour les autres logiciels ne permettant ni l'appel de bibliothèques dynamiques, ni l'appel direct de pilotes exécutables ?

le problème d'utilisation des ports en Linux

Linux est un système d'exploitation conçu pour être multi-tâches et multi-utilisateurs. Normalement, il y a un super-utilisateur (administrateur du réseau), nommé «root», qui peut commander complètement l'ordinateur, et les autres utilisateurs, qui n'ont que des droits réduits.
Les utilisateurs normaux n'ont pas le droit d'accéder directement aux ports de l'ordinateur, ce qui est dans l'absolu une bonne mesure de sécurité, car l'accès direct à l'électronique permet de faire beaucoup de bêtises. Malheureusement, pour beaucoup d'appareils de mesure, en particulier pour les cartes insérées dans les connecteurs d'extension, il est indispensable de pouvoir écrire et lire des valeurs sur les ports.
Une solution est bien sûr d'utiliser l'ordinateur en tant que super-utilisateur «root». Mais dans ce cas, il n'y a aucune protection contre les erreurs !

Le problème est donc d'autoriser l'utilisateur normal à accéder à certains ports, ceux utiles pour la mesure.

La solution que je propose est la suivante :
- écrire et compiler les bibliothèques dynamiques en tant que «root», qui sera donc le légitime propriétaire et utilisateur de cette bibliothèque dynamique.
- ensuite, toujours en tant que «root», modifier les droits d'accès de cette bibliothèque dynamique, en déclarant que tous les utilisateurs pourront s'en servir, avec les mêmes droits que «root».

Deux méthodes sont possibles pour donner cette autorisation :
- la méthode «ligne de commande» (Merci à Georges Khaznadar): si la bibliothèque à utiliser s'appelle liblxmachine.so, il faut entrer la commande :
chmod 4755 liblxmachine.so
Le nombre mystérieux 4755 signifie que toute personne ayant droit d'exécution a les mêmes droits que le propriétaire initial, et que tout utilisateur aura le droit d'exécution.

- la méthode «cliquage de souris» avec les versions modernes de Linux, comme par exemple Mandrake 8.
En mode graphique, lorsqu'on clique avec le bouton droit de la souris sur l'icône représentant le fichier liblxmachine.so, on peut modifier les propriétés de ce fichier, et donc donner les droits précédents.

Ensuite, après ces opérations faites en tant que «root», les utilisateurs normaux pourront utiliser la bibliothèque liblxmachine.so qui accèdera aux ports de mesure.

Ecriture d'objets partagés

en Kylix

Le fichier ainsi compilé peut être appelé par un logiciel d'application écrit en Kylix, avec à peu près la même syntaxe qu'avec Delphi pour Windows.
Le fichier ci-dessous correspond à une librairie simple, facilement utilisable en Kylix.
Kylix peut utiliser les fonctions avec divers types de passage de paramètres, mais pour pouvoir utiliser les bibliothèques avec d'autres logiciels et langages de programmation, il faut surtout veiller aux fonctions déclarées en "stdcall",  (stdead, stdnead, etc), comme pour les langages de programmation de Windows.

library xadestar_linux;

uses
  SysUtils,uades1,
  Classes;

const NumFuncts = 17;
type array100= array[0..100] of char;
type pdouble=^double;

var memosb:array[0..3]of boolean;
    memosad:double;
function ea(n:integer):integer;
var o:integer;
n1,n2:word;
begin
  o:=n;
  ea:=-777;
  if (n=0)or(n=1)then lit_niveau(n1,n2);
  case o of 0: ea:=n1;
            1: ea:=n2;
            2: ades_off;
            3: ades_on;
            end;
end;
 

function nea(n:integer):pchar;
var chloc:string[20];  tabcarloc:array[0..20] of char;
begin
  str(n,chloc);
  if (n<2) and (n>-1)
    then strpcopy(tabcarloc,'CAN voie '+chloc)
    else if n=2 then strpcopy(tabcarloc,'RAZ pour impression')
       else if n=3 then strpcopy(tabcarloc,'Réinitialisation')
          else strpcopy(tabcarloc,'');
  nea:=tabcarloc;
end;
 

function ead(n:integer):double;
var aux:integer;

begin
  if (n=0) or (n=1)or (n=2) or (n=3)
     then begin
       aux:=ea(n);
       ead:=(5.0*aux)/1024;
          end
     else  ead:=-777;
end;

function nead(n:integer):pchar;
var chloc:string[20];  tabcarloc:array[0..20] of char;
begin
  if (n=0)
    then nead:='E. analogique 0'
      else if n=1 then nead:='E. analogique 1'
      else if n=2 then nead:='RAZ pour impression'
             else if n=3 then nead:='Réinitialisation'
    else nead:='';
end;
 

function sa(n:integer; valeur:integer):integer;
begin
 sa:=-777;
end;
function nsa(n:word):pchar;
  var tabcarloc:array[0..20] of char;
begin
if n=0 then
  nsa:='SA fictive'+chr(0)
  else nsa:=''+chr(0);
end;
 

function sad(n:integer ; valeur:double):double;
begin
MEMOsad:=valeur;
sad:=0;
end;

function nsad(n:integer):pchar;
  var tabcarloc:array[0..20] of char;
begin
   if n=0 then nsad:='SA fictive'+chr(0)
      else nsad:=''+chr(0);
end;

function rsa(n:integer):integer;
begin
if n=0 then rsa:=2 else rsa:=-777;
end;

 function rsad(n:integer):double;
begin
  if n=0 then rsad:=2 else rsad:=-777;
end;
 

function eb(n:integer):integer;
begin
 if n=0 then eb:=0
        else if n=1 then eb:=1
                    else eb:=-777;
end;

function neb(n:integer):pchar;
var  tabcarloc:array[0..20] of char;
begin
 if n=0 then neb:='EB fictive 0'+chr(0)
        else if n=1 then neb:='EB fictive 1'+chr(0)
                    else neb:=chr(0);
end;

Const tabmasque : array[0..7] of byte = (1,2,4,8,16,32,64,128);
   memosl1:byte=0;
 function testebit(nombre:word ; numbit:byte):boolean;
begin    testeBit:=odd(nombre shr numbit);end;

procedure forcebit(var octet :byte ; numbit:byte ; etat:boolean);
begin
  if etat then octet :=octet or tabmasque[numbit]
          else octet :=octet and (not tabmasque[numbit]);
end;

function sb(n:integer; etat:integer):integer;
begin
 case n of
   0..3 : begin relais[n+1]:=(etat=1);
   sb:=n*100+etat;
   pilote_relais(0);
         //forcebit(memosl1,n,(etat=1));
   memosb[n]:=(etat=1);
          end;
   else sb:=-777;
    end;
end;
 
 

function nsb(n:integer):pchar;
var chloc:string[20];  tabcarloc:array[0..20] of char;
begin
result:=chr(0);
if n=0 then result:='relais A'+chr(0);
if n=1 then result:='relais B'+chr(0);
if n=2 then result:='relais C'+ chr(0);
if n=3 then result:='relais D'+chr(0);
end;

function rsb(n:integer):integer;
begin
 (* if n in [0..3]
     then if testebit(memosl1,n)
           then rsb:=1
           else rsb:=0
     else rsb:=-777 ;
     *)
 if n in [0..3] then if memosb[n] then rsb:=1 else rsb:=0
                else rsb:=-777;
end;
 

function titre : pchar;
begin titre:='ADES en LPT1:';end;
function detail : pchar;
begin detail:='DLL (32 bits) pour ADES 10 bits en LPT1:, par P. Dieumegard, le 20 février 2001';end;

(*les deux fonctions qui suivent sont pour EXCEL*)
function peaD(n:integer):pdouble;
var dloc:double;
begin dloc:=eaD(n);pead:=@dloc;end;

function psad(n:integer;valeur:pdouble):pdouble;
var dloc1,dloc2:double;
begin dloc1:=valeur^;dloc2:=SAD(n,dloc1);psad:=@dloc2;end;
 

(*les fonctions " double " qui suivent sont pour StarOffice*)
function eadouble(x:double):double;
var  nloc:word;
begin
  nloc:=round(x);
  eadouble:=ead(nloc);
end;

function neadouble(x:double):pchar;
var nloc:word;
begin
  nloc:=round(x);
  neadouble:=nead(nloc);
end;

function sadouble(x:double;xval:double):double;
begin sadouble:=sad(round(x),xval);end;

function nsadouble(x:double):pchar;
begin nsadouble:=nsad(round(x));end;

function rsadouble(x:double):double;
begin rsadouble:=rsad(round(x));end;

function ebdouble(x:double):double;
begin ebdouble:=eb(round(x));end;

function nebdouble(x:double):pchar;
begin nebdouble:=neb(round(x));end;

function sbdouble(n:double;etat:double):double;
begin sbdouble:=sb(round(n),round(etat));end;

function nsbdouble(n:double):pchar;
begin nsbdouble:=nsb(round(n));end;

function rsbdouble(n:double):double;
begin rsbdouble:=rsb(round(n));end;
 

function ea(n:integer):integer;  begin ea:=stdea(n);end;stdcall;
function stdnea(n:integer):pchar;  begin stdnea:=nea(n);end;stdcall;
function stdead(n:integer):double;  begin stdead:=ead(n);end;stdcall;
function stdnead(n:integer):pchar; begin stdnead:=nead(n);end;stdcall;
function stdsa(n:integer ;valeur:integer):integer;begin stdsa:=sa(n,valeur);end;stdcall;
function stdnsa(n:integer):pchar; begin stdnsa:=nsa(n);end;stdcall;
function stdrsa(n:integer):integer; begin stdrsa:=stdrsa(n);end;stdcall;
function stdsad(n:integer; valeur:double):double; begin stdsad:=sad(n,valeur);end;stdcall;
function stdrsad(n:integer):double; begin stdrsad:=rsad(n);end;stdcall;
function stdeb(n:integer):integer; begin stdeb:=eb(n);end;stdcall;
function stdneb(n:integer):pchar; begin stdneb:=neb(n);end;stdcall;
function stdsb(n:integer;etat:integer):integer; begin stdsb:=sb(n,etat);end;stdcall;
function stdnsb(n:integer):pchar; begin stdnsb:=stdnsb(n);end;stdcall;
function stdrsb(n:integer):integer; begin stdrsb:=stdrsb(n);end;stdcall;
function stdtitre:pchar; begin stdtitre:=titre;end;stdcall;
function stddetail:pchar; begin stddetail:=detail;end;stdcall;
(*stdtitre et stddetail ne sont pas indispensables, car ils  sont sans paramètres*)
(* comme titre et detail*)
exports
  ea ,  nea ,ead ,nead,
  sa ,nsa,sad ,  nsad ,rsa,rsad,
  eb ,  neb ,  sb ,  nsb ,rsb,
  titre , detail,
  pead ,  psad ,
  stdea,stdnea,stdead,stdnead,
  stdsa,stdnsa,stdrsa,stdsad,stdnsad,stdrsad,
  stdeb,stdneb,stdsb,stdnsb,stdrsb,
  eadouble ,  neadouble ,
  sadouble,nsadouble,rsadouble,
  ebdouble,nebdouble,
  sbdouble, nsbdouble,rsbdouble;

var i:word;
begin
 nbitades:=10;
 initialise_ades(888);
 ades_on;
 for i:=0 to 3 do memosb[i]:=false;
end.
(Début de page)
 

Ecriture d'objets partagés en FreePascal

Bien sûr, c'est du Pascal, et la bibliothèque doit être rédigée presque comme en Delphi, mais pas de façon tout à fait identique.
Voici le début et la fin d'une bibliothèque pour ADES.
library lxades1;
//bibliothèque dynamique pour Linux et Ades, à utiliser avec FreePascal

uses
  SysUtils,linux,
  uades1;

type array100= array[0..100] of char;
type pdouble=^double;

var memosb:array[0..3]of boolean;
    memosad:double;
function ea(n:integer):integer; pascal;export;
var o:integer;
n1,n2:word;
begin
  o:=n;
  ea:=-777;
  if (n=0)or(n=1)then lit_niveau(n1,n2);
  case o of 0: ea:=n1;
            1: ea:=n2;
            2: ades_off;
            3: ades_on;
            end;
end;
Les fonctions de la bibliothèque sont identiques à celles de Kylix, mais à la fin, il faut ajouter une ligne pour donner le droit d'accéder aux ports :
var i:word;
begin
 ioperm(888,3,1);
 nbitades:=10;
 initialise_ades(888);
 ades_on;
 for i:=0 to 3 do memosb[i]:=false;
end.

La ligne ioperm(888,3,1) signifie «permettre l'entrée et la sortie d'information à partir de l'adresse de port 888 (qui est l'adresse de base de l'interface parallèle utilisée par ADES), sur 3 octets successifs (l'adresse de lecture et d'écriture d'information sont deux adresses successives)». Cette instruction ioperm sera à utiliser pour tous les appareils de mesure devant accéder aux ports, avec bien sûr des valeurs différentes selon les ports à utiliser.
 
 

Ecriture d'objets partagés en C++

    Comme pour Windows, voici une bibliothèque pour une interface fictive. Pour l'utiliser avec un véritable appareil de mesure, il faut remplacer les valeurs arbitraires des différentes fonctions par la vraie mesure ou la vraie commande.

    Cette bibliothèque a été rendue possible grâce aux renseignements fournis sur le site http://www.wachtler.de/dynamischeBibliotheken.

int memosa;
double memosad;
bool memosb[4];
typedef char * tpchar; //pour avoir la correspondance avec le type pchar de Delphi
static int
//ces deux premières fonctions sont inutiles pour ce qui nous concerne.
// simplement, elles étaient dans le programme-source initial
//voir le site http://www.wachtler.de/dynamischeBibliotheken/dynamischeBibliotheken.html
Wert = 0;
extern "C" int summe( int a, int b )
{
return a + b;
}
extern "C" int immereinsmehr( void )
{
if( Wert>6 )
{
throw( 125 );
} return Wert++;
}

extern "C" int stdea(int n)
{ if (n>-1&&n<3) {return n*3;}else {return -777;}}

extern "C" tpchar stdnea(int n)
{
tpchar chloc;
chloc="\0";
if (n==0) chloc="entrée analogique 0\0";
if (n==1) chloc="EA 1 (volts)\0";
if (n==2) chloc="température °C\0";
return chloc; }

extern "C" double stdead(int n)
{
double varloc;
if (n>-1&&n<3) {varloc= n*3.33;}else{varloc= -777;}
return varloc;
}

extern "C" tpchar stdnead(int n)
{
tpchar chloc;
chloc="\0";
if (n==0) chloc="entrée analogique 0\0";
if (n==1) chloc="EA 1 (volts)\0";
if (n==2) chloc="température °C\0";
return chloc; }
extern "C" int stdsa(int n , int val)
{ if (n==0) {memosa=val ;return val;}else{return -777;}
}

extern "C" tpchar stdnsa(int n)
{ tpchar chloc;
if (n==0) chloc="sortie analogique\0"; else chloc="\0";
return chloc; }

extern "C" double stdsad(int n, double val)
{ if (n==0){memosad=val; return val;} else return -777;
}

extern "C" tpchar stdnsad(int n)
{if (n==0) return "SA 0 (volts)\0"; else return "\0"; }

extern "C" int stdrsa(int n)
{ if (n==0) return memosa; else return -777; }

extern "C" double stdrsad(int n)
{ if(n==0) return memosad; else return -777;}

extern "C" int stdeb(int n)
{
if (n==0)
return 0;
else if (n==1)
return 1;
else return -777;
}

extern "C" tpchar stdneb(int n)
{ if (n==0)
return "EB fictive 0\0";
else if (n==1)
return "EB fictive 1\0";
else return "\0";
}

extern "C" int stdsb(int n, int etat)
{ int varloc;
varloc=-777;
//mettre ici la commande des sorties binaires,
// ainsi que la mémorisation dans le tableau memosb;
if (n==0) varloc=0;
if (n==1) varloc=1;
if (n==2) varloc=1;
if (n==3) varloc=0;
return varloc;
}

extern "C" tpchar stdnsb(int n)
{tpchar varloc;
varloc=="\0";
if (n==0) varloc="Relais 0\0";
if (n==1) varloc="Relais 1\0";
if (n==2) varloc="Relais 2\0";
if (n==3) varloc="Relais 3\0";
return varloc; }

extern "C" int stdrsb(int n)
{int varloc;
varloc=-777;
if (n==0) varloc=memosb[0];
if (n==1) varloc=memosb[1];
if (n==2) varloc=memosb[2];
if (n==3) varloc=memosb[3];
return varloc ;}

extern "C" tpchar stdtitre(void)
{return "Appareil fictif\0";}

extern "C" tpchar stddetail(void)
{return "Appareil fictif, bibliothèque programmée en C++ par P. Dieumegard, le 19 nov 2002\0";
}

(Début de page)

Appel de la librairie (objet partagé) en Kylix et C++

appel en Kylix

Le principe est exactement le même qu'en Delphi pour Windows : on met les instruction de chargement de la bibliothèque :
dialouvrepil.execute;
   //messagedlg(dialouvrepil.filename, mtconfirmation,[mbyes],0);
     if dialouvrepil.filename <>''
      then begin
      nomdll:=changefileext(dialouvrepil.filename,'');
     @detailp:=nil;@calibrationp:=nil; @sad:=nil;
     @nsad:=nil;   @titre:=nil;
     @eadp:=nil;
     @neadp:=nil;
     @sb:=nil;@nsb:=nil;  @rsad:=nil; @rsb:=nil;
     @eb:=nil;@neb:=nil;
            strpcopy(repchar,dialouvrepil.filename);
            L:=loadlibrary(repchar);
                 nompilotep:=dialouvrepil.filename;
                @detailp:=getprocaddress(L,'detail');
                @titre:=getprocaddress(L,'titre');
                @neap:=getprocaddress(L,'NEA');
                @eap:=getprocaddress(L,'EA');
                @neadp:=getprocaddress(L,'NEAD');
                @eadp:=getprocaddress(L,'EAD');
                @sad:=getprocaddress(L,'SAD');
                @nsad:=getprocaddress(L,'NSAD');
                @sb:=getprocaddress(L,'SB');
                @nsb:=getprocaddress(L,'NSB');
                @eb:=getprocaddress(L,'EB');
                @neb:=getprocaddress(L,'NEB');
                @rsad:=getprocaddress(L,'RSAD');
                @rsb:=getprocaddress(L,'RSB');
                @calibrationp:=getprocaddress(L,'calibration');
                if getprocaddress(L,'calibration')<>nil
                   then reglages.enabled:=true
                   else reglages.enabled:=false;
                if (@eadp<>nil)and(@neadp<>nil) then okpiloteP:=true
                                                else okpiloteP:=false;
if @titre<>nil
    then begin form1.caption:=strpas(titre);
         boutonfichiers.enabled:=true;
         end;
(Début de page)

appel en C++

Le langage C est le langage de référence pour Linux.

Voici un petit programme appelant une bibliothèque de mesure, et affichant les fonctions «detail», «stdead(1)» et «stdnead(1)».

//testdll_linux.c : essai de programme en C appelant les bibliothèques .so
//à compiler par
//g++ -rdynamic -ldl -o testdll_linux testdll_linux.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string>

main()
{
typedef char *(*detailtype)();
typedef double (*stdeadtype) (int numvoie);
typedef char *(*stdneadtype) (int numvoie);
void *handle=NULL;
detailtype detail;
stdeadtype stdead;
stdneadtype stdnead;
double mondouble;
char repchar[60];
char * moncar;
int a;
handle=dlopen("./liblxdllvide.so",RTLD_NOW);
detail=(detailtype)dlsym(handle,"detail");
stdead=(stdeadtype)dlsym(handle,"stdead");
stdnead=(stdneadtype)dlsym(handle,"stdnead");
mondouble=stdead(2);
mach2="44.44";
moncar=detail();
printf(moncar);
printf("\n");
machaine="simple essai de chaîne";
gcvt(mondouble,5,repchar);
printf(repchar);
printf(stdnead(1));
return 0;
}

(Début de page)

Appel de la bibliothèque en FreePascal

Le principe est le même que pour Kylix, sauf que les fonctions getprocaddress n'existent pas en standard, non plus que loadlibrary ou freelibrary.
Il faut donc les créer, dans le corps du programme.

function dlopen(afile:pchar;mode:longint):pointer;cdecl;external 'dl';
function LoadLibrary(name:pchar):thandle;
begin
   Result:=LongWord(dlopen(name,$101 {RTLD_GLOBAL or RTLD_LAZY}));
  end;

function dlclose(handle:pointer):longint;external 'dl';
procedure FreeLibrary(handle:thandle);
begin dlclose(pointer(handle));end;

function dlsym(handle:pointer;name:pchar):pointer;external 'dl';
function getprocaddress(handle:thandle;name : pchar):pointer;
//begin result:=dlsym(pointer(handle),name);end;
begin result:=dlsym(pointer(handle),name );end;

(Début de page)

Appel indirect de la librairie (objet partagé) par divers logiciels ou langages de programmation

Normalement, les homologues pour Linux des logiciels pour Windows pouvant utiliser les DLL devraient pouvoir utiliser les objets partagés .so.

Dans la réalité, c'est moins simple...

- StarOffice existe aussi en version Linux, mais la version 5.2 ne semble pas capable d'appeler les fichiers .so

- PureBasic existe aussi pour Linux, mais la version actuelle (décembre 2002) est un prototype, et ne semble pas capable d'utiliser les bibliothèques partagées de Linux.

Comment faire ?

La seule solution pour StarOffice et PureBasic semble d'utiliser les «pilotes enregistrant leurs résultats dans un fichier», tels qu'ils sont décrits pour Windows dans le paragraphe 5.8.2. Ce n'est pas très simple.

- Python sous Windows peut utiliser les DLL, à condition de passer par la méthode de PythonForDelphi. Normalement, d'après la documentation, ce doit être aussi possible pour Python sous Linux. Malheureusement, jusqu'ici, je n'ai pas réussi. Heureusement, Python sous Linux possède un module «commands», qui le rend capable d'utiliser les «pilotes exécutables dont on récupère le résultat» (comme pour Scilab : voir paragraphes suivants).

(Début de page)

Pilotes dont le logiciel récupère directement le résultat

Ecriture du pilote exécutable en Kylix

Plutôt que de faire un pilote exécutable par matériel de mesure, il est préférable d'écrire un seul pilote exécutable, qui lui-même appellera la bibliothèque de l'appareil de mesure.

program pdll32;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  wintypes;

var l:thandle;
  var repchar:array[0..80] of char;
  var ea:function(n:integer):integer;
  var nea:function(n:integer):pchar;
  var stdea:function(n:integer):integer;stdcall;
  var stdnea:function(n:integer):pchar ;stdcall;
  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 sa:function(n:integer;valeur:integer):integer;
  var nsa:function(n:integer):pchar;
  var rsa:function(n:integer):integer;
  var stdsa:function(n:integer;valeur:integer):integer;stdcall;
  var stdnsa:function(n:integer):pchar;stdcall;
  var stdrsa:function(n:integer):integer;stdcall;
  var sad:function(n:integer;valeur:double):double;
  var nsad:function(n:integer):pchar;
  var rsad:function(n:integer):double;
  var stdsad:function(n:integer;valeur:double):double;stdcall;
  var stdnsad:function(n:integer):pchar;stdcall;
  var stdrsad:function(n:integer):double;stdcall;
  var eb:function(n:integer):integer;
  var neb:function(n:integer):pchar;
  var stdeb:function(n:integer):integer;stdcall;
  var stdneb:function(n:integer):pchar;stdcall;
  var sb:function(n:integer;valeur:integer):integer;
  var nsb:function(n:integer):pchar;
  var rsb:function(n:integer):integer;
  var stdsb:function(n:integer;valeur:integer):integer;stdcall;
  var stdnsb:function(n:integer):pchar;stdcall;
  var stdrsb:function(n:integer):integer;stdcall;
  var detail,titre:function : pchar;
  var stddetail,stdtitre:function:pchar;stdcall;
  var chemindll,nomfonction,chparam1,chparam2:string;
  var valparam1:double;
  var valparam2:double;
  var i:integer;
 begin
  // Insérer le code utilisateur ici
  //for i:=0 to paramcount do writeln('paramètre ',i,':',paramstr(i));
  valparam1:=11;valparam2:=22;
  chemindll:=paramstr(1);
//chemindll:='/home/pierre/libxdllpython.so';
  nomfonction:=paramstr(2);
  if paramcount>=3 then valparam1:=strtofloat(paramstr(3));
  if paramcount>=4 then valparam2:=strtofloat(paramstr(4));
  strpcopy(repchar,chemindll);
  @ea:=nil;@nea:=nil;  @nead:=nil; @ead:=nil;
  @sa:=nil;@nsa:=nil;@rsa:=nil;@sad:=nil;@nsad:=nil;@rsad:=nil;
  @eb:=nil;@neb:=nil;@sb:=nil;@nsb:=nil;@rsb:=nil;
  @detail:=nil;@titre:=nil;@stddetail:=nil;@stdtitre:=nil;
  @stdea:=nil;@stdnea:=nil; @stdead:=nil;@stdnead:=nil;
  @stdsa:=nil;@stdnsa:=nil;@stdrsa:=nil;
  @stdsad:=nil;@stdnsad:=nil;@stdrsad:=nil;
  @stdeb:=nil;@stdneb:=nil;@stdsb:=nil;@stdnsb:=nil;@stdrsb:=nil;

//  l:=loadlibrary('home/pierre/libxdllpython.so');
   l:=loadlibrary(repchar);
   @ea:=getprocaddress(L,'ea');
   @nea:=getprocaddress(L,'nea');
   @nead:=getprocaddress(L,'nead');
   @ead:=getprocaddress(L,'ead');
   @sa:=getprocaddress(L,'sa');
   @nsa:=getprocaddress(L,'nsa');
   @rsa:=getprocaddress(L,'rsa');
   @sad:=getprocaddress(L,'sad');
   @nsad:=getprocaddress(L,'nsad');
   @rsad:=getprocaddress(L,'rsad');
   @eb:=getprocaddress(L,'eb');
   @neb:=getprocaddress(L,'neb');
   @sb:=getprocaddress(L,'sb');
   @nsb:=getprocaddress(L,'nsb');
   @rsb:=getprocaddress(L,'rsb');
   @detail:=getprocaddress(L,'detail');
   @titre:=getprocaddress(L,'titre');
   @stddetail:=getprocaddress(L,'stddetail');
   @stdtitre:=getprocaddress(L,'stdtitre');
   @stdea:=getprocaddress(L,'stdea');
   @stdnea:=getprocaddress(L,'stdnea');
   @stdead:=getprocaddress(L,'stdead');
   @stdnead:=getprocaddress(L,'stdnead');
   @stdsa:=getprocaddress(L,'stdsa');
   @stdnsa:=getprocaddress(L,'stdnsa');
   @stdrsa:=getprocaddress(L,'stdrsa');
   @stdsad:=getprocaddress(L,'stdsad');
   @stdnsad:=getprocaddress(L,'stdnsad');
   @stdrsad:=getprocaddress(L,'stdrsad');
   @stdeb:=getprocaddress(L,'stdeb');
   @stdneb:=getprocaddress(L,'stdneb');
   @stdsb:=getprocaddress(L,'stdsb');
   @stdnsb:=getprocaddress(L,'stdnsb');
   @stdrsb:=getprocaddress(L,'stdrsb');

    //writeln('nombre de paramètres :',paramstr(0));
   //writeln('nomdll:',chemindll);
   //writeln('nomfonction:',nomfonction);
   //writeln(valparam1:8:2);
   if nomfonction='ea' then writeln(ea(round(valparam1)));
   if nomfonction='nea' then writeln(nea(round(valparam1)));
   if nomfonction='ead' then writeln(ead(round(valparam1)):10:5);
   if nomfonction='nead' then writeln(nead(round(valparam1)));
   if nomfonction='sa' then writeln(sa(round(valparam1),round(valparam2)));
   if nomfonction='nsa' then writeln(nsa(round(valparam1)));
   if nomfonction='rsa' then writeln(rsa(round(valparam1)));
   if nomfonction='sad' then writeln(sad(round(valparam1),valparam2):10:5);
   if nomfonction='nsad' then writeln(nsad(round(valparam1)));
   if nomfonction='rsad' then writeln(rsad(round(valparam1)):10:5);
   if nomfonction='eb' then writeln(eb(round(valparam1)));
   if nomfonction='neb' then writeln(neb(round(valparam1)));
   if nomfonction='sb' then writeln(sb(round(valparam1),round(valparam2)));
   if nomfonction='nsb' then writeln(nsb(round(valparam1)));
   if nomfonction='rsb' then writeln(rsb(round(valparam1)));
   if nomfonction='titre' then writeln(titre);
   if nomfonction='detail' then writeln(detail);
   if nomfonction='stdea' then writeln(stdea(round(valparam1)));
   if nomfonction='stdnea' then writeln(stdnea(round(valparam1)));
   if nomfonction='stdead' then writeln(stdead(round(valparam1)):10:5);
   if nomfonction='stdnead' then writeln(stdnead(round(valparam1)));
   if nomfonction='stdsa' then writeln(stdsa(round(valparam1),round(valparam2)));
   if nomfonction='stdnsa' then writeln(stdnsa(round(valparam1)));
   if nomfonction='stdrsa' then writeln(stdrsa(round(valparam1)));
   if nomfonction='stdsad' then writeln(stdsad(round(valparam1),valparam2):10:5);
   if nomfonction='stdnsad' then writeln(stdnsad(round(valparam1)));
   if nomfonction='stdrsad' then writeln(stdrsad(round(valparam1)):10:5);
   if nomfonction='stdeb' then writeln(stdeb(round(valparam1)));
   if nomfonction='stdneb' then writeln(stdneb(round(valparam1)));
   if nomfonction='stdsb' then writeln(stdsb(round(valparam1),round(valparam2)));
   if nomfonction='stdnsb' then writeln(stdnsb(round(valparam1)));
   if nomfonction='stdrsb' then writeln(stdrsb(round(valparam1)));
   if nomfonction='stdtitre' then writeln(stdtitre);
   if nomfonction='stddetail' then writeln(stddetail);
   freelibrary(L);
end.
(Début de page)

Appel du pilote en Scilab

Ce logiciel fonctionne sans problème, avec le même protocole que pour Windows.
chdir('/home/utilisateur/travai_dll');
x=unix_g('./scidll32 ./liblxdllvide.so ead 1');
disp(x);

Les commandes précédentes mettent comme répertoire courant «/home/utilisateur/travaildll», puis lancent le pilote «scidll32» qui appelle la bibliothèque «liblxdllvide.so» et lui demande l'entrée analogique réelle 1 («ead(1)»). Le résultat de cet appel est envoyé dans la variable x, qui est finalement affiché.

Appel du pilote en SmallBasic

Pour SmallBasic, les instructions suivantes envoient dans la variable x$ la valeur de l'entrée analogique double 1, puis affichent la valeur :
x$=run("/home/utilisateur/travail_dll/scidll32 /home/utilisateur/travail_dll/liblxdllvide.so ead 1 ")
print(val(x$))

Appel du pilote en Yabasic

Pour Yabasic, si on suppose qu'on est dans le répertoire où sont les fichiers (pilote exécutable et bibliothèque), on peut imprimer le nom de l'entrée analogique 1 :
print system$("./scidll32 ./liblxdllvide.so nead 1 ")
 

Appel du pilote en Python

Sous Linux, Python possède le module «commands».
Il faut d'abord charger ce module par l'instruction import commands, en plus du module «os» chargeable par import os.
La commande la plus importante est : getoutput qui exécute une commande et récupère son résultat.
os.chdir('./home/utilisateur/travail_dll')
data=commands.getoutput('./scidll32 ./liblxdllvide.so nea 1')
Dans la variable data se trouve le résultat de la commande, c'est à dire le nom de l'entrée analogique 1.
(Début de page)

Pilotes enregistrant le résultat dans un fichier

C'est le moins pratique : il faut que le logiciel lance d'abord le pilote, puis lise le fichier ainsi écrit.
C'est (apparemment) le seul moyen utilisable pour PureBasic pour Linux, au moins dans la version existant actuellement (décembre 2002). Il faut espérer que les concepteurs de SmallBasic vont travailler aussi efficacement pour faire SmallBasic sous Linux que pour SmallBasic pour Windows.
 

StarOffice

StarOffice, et son successeur OpenOffice existe aussi bien pour Windows que pour Linux.
Malheureusement, le système d'appel des bibliothèques à liaison dynamique semble ne fonctionner que pour Windows.
Pour Linux, il semble obligatoire d'utiliser les fonction d'appel de logiciels extérieur, ce qui est beaucoup plus lent.
Par exemple, le sous-programme en StarBasic ci-dessous affiche dans une boite de dialogue le résultat de la mesure sur 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
open aFile for output as #inumber
close #inumber
temps0=getsystemticks()
shell(lignecommande$,false)
while (filelen(afile)<2)and(getsystemticks()-temps0<1000)
wend
iNumber = Freefile
Open aFile For input As #iNumber
Line Input #iNumber, sLine
close #inumber
msgbox(val(sline))
end sub