Création de DLL sur VB

Création de DLL sur VB - VB/VBA/VBS - Programmation

Marsh Posté le 11-03-2013 à 19:25:33    

Bonjour à tous

 

J'utilise un logiciel (Profilab Expert) pour communiquer avec des interfaces de mesure.
La programmation de ce logiciel s’effectue de façon graphique, un peu comme Labview ; il est très facile de faire une application, mais sur certains points ce logiciel montre des limites. Par exemple Profilab est un peu lent pour récupérer des trames sur le port série. Il n'est également pas très adapté pour gérer des conditions et des boucles.

 

Je voudrais effectuer certaines fonctions par le biais de DLL écrites en VB, le problème étant que je ne connais pas grand chose dans ce domaine...

 

Pour commencer pensez vous que ce soit faisable ?
Est-ce abordable pour un débutant (j'utilise régulièrement VBA sur Excel, mais je n'utilise pas VB) ?
J'ai un CD de VB5, puis-je l'utiliser, ou serait il préférable d'utiliser une autre version ?

 

Je vous ai recopié le texte présent dans le fichier d'aide sur Profilab en rapport avec l'utilisation des DLL.

 

Merci d'avance pour votre participation.

 
Citation :

   Import DLL

 

   Présent dans la version:
    DMM-ProfiLab: Non
    Digital-ProfiLab: Non
    ProfiLab-Expert: Oui

 

   Ce composant offre une interface de programmation qui vous permettra de créer vous-même vos propres composants afin que vous puissiez piloter vos propres cartes d'interfaces.

 

   Afin d'y parvenir, vous aurez besoin d'un langage de programmation capable de compiler les fichiers DLL (Dynamic Link Libraries), et vous devrez avoir certaines connaissance en programmation. Vous devrez aussi vous assurer que les DLL exportent certaines fonctions qui détermineront le nombre d'entrées et de sorties, le nom des broches et la fonction interne du composant. Les fonctions ci-dessous sont nécessaires pour chaque composant :

 

   Delphi: function NumInputs: Byte;
    C++: unsigned char _stdcall NumInputs()
    ou:
    Delphi: function NumInputsEx(PUser: PDLLParams): Byte;
    C++: unsigned char _stdcall CNumInputsEx(double *PUser)
    Le résultat de cette fonction doit retourner un octet dont la valeur détermine le nombre d'entrées du composant. Le type de fonction étendu peut être utilisé, pour rendre le nombre des canaux réglable.

 

   Delphi: function NumOutputs: Byte ;
    C++: unsigned char _stdcall NumOutputs()
    ou:
    Delphi: function NumOutputsEx(PUser: PDLLParams): Byte;
    C++: unsigned char _stdcall CNumOutputsEx(double *PUser)
    Le résultat de cette fonction doit retourner un octet dont la valeur détermine le nombre de sorties du composant. Le type de fonction étendu peut être utilisé, pour rendre le nombre des canaux réglable.

 

   Delphi: function InputName(Channel: Byte): ShortString;
    C++: void _stdcall GetInputName(unsigned char Channel, unsigned char *Name)
    Le résultat de cette fonction doit retourner un petit texte pour la description des broches de chaque entrée (canal) de votre composant. ProfiLab appel cette fonction pour chaque broche d'entrée pour en avoir la description correspondante. Le paramètre CHANNELS identifie la broche de 0 à NumInputs-1.

 

   Delphi: function OutputName(Channel: Byte): ShortString;
    C++: void _stdcall GetOutputName(unsigned char Channel, unsigned char *Name)
    Le résultat de cette fonction doit retourner un petit texte pour la description des broches de chaque sortie (canal) de votre composant. ProfiLab appel cette fonction pour chaque broche de sortie pour en avoir la description correspondante. Le paramètre CHANNELS identifie la broche de 0 à NumOutputs -1.

 

   Delphi: Procedure Calculate(PInput,POutput,PUser: PDLLParams);
    C++: void _stdcall CCalculate(double *PInput, double *POutput, double *PUser)
    Ceci est la procédure principale de calcul de votre composant, laquelle déterminera comment votre composant fonctionnera. Les paramètres de procédure PINPUT, POUTPUT et PUSER offrent 3 variables pointeurs aux fonctions suivantes :

 

   Le pointeur PINPUT pointe vers une zone mémoire, dans laquelle les valeurs d'entrées sont stockées, de telle sorte que la DLL puisse accéder aux valeurs d'entrée du composant.
    Le pointeur POUTPUT pointe vers une zone mémoire, dans laquelle les valeurs de sorties sont stockées, de telle sorte que la DLL puisse accéder aux valeurs de sorties du composant.
    Le pointeur PUSER pointe vers une zone mémoire, dans laquelle la DLL pourra stocker ses propres valeurs (locale). A savoir: Les variables définies dans la DLL en tant que variables globales « s'écraseront » les unes les autres si un composant DLL est utilisé plus d'une fois dans un projet ProFilab. Pour disposer de variables locales, ProFilab utilise le pointeur PUSER dans la DLL, de telle sorte que la DLL puisse mémoriser des variables locales dans des zones mémoires indiquées par le pointeur PUSER.

 

   Si vous ne voulez pas utiliser le pointeur PUSER, mais que vous ayez besoin de déclarer des variables dans la DLL qui devront être considérées comme des variables locales (pour des composants utilisés plusieurs fois dans un projet ProFilab), vous pouvez renommer les fichiers de DLL et les importer successivement avec différents noms dans le projet ProFilab.

 

   Chacun des 3 pointeurs PINPUT, POUTPUT et PUSER déterminent un tableau de 100 variables ETENDUES (EXTENDED). Les 3 pointeurs doivent être déclarés en tant que PDLLParams.

 

   La déclaration en Delphis est comme suit:

 

   type TDLLParams = array[0..100] of extended;
    PDLLParams = ^TDLLParams; // C++: (double *PDLLParams)

 

   Le tableau du pointeur PINPUT donne accès aux valeurs d'entrée du composant. On accède aux valeurs d'entrées comme suit :

 

   PInput^[0] contient la valeur numérique de la première entrée.,
    PInput^[1] contient la valeur numérique de la seconde entrée, et ainsi de suite...

 

   Le tableau du pointeur POUTPUT donne accès aux valeurs de sortie du composant. On accède aux valeurs de sortie comme suit :

 

   POutput^[0] doit être rempli avec la valeur de la première sortie,
    POutput^[1] doit être rempli avec la valeur de la seconde sortie, et ainsi de suite...

 

   PUser^[0] à PUser^[99] peut être utilisé pour mémoriser des valeurs numériques à usage « personnel ». Les valeurs de ces variables sont sauvegardées dans le fichier de projet de ProfiLab, afin de pouvoir à nouveau être exploitable à chaque fois que le projet et chargé à nouveau. La variable PUser^[100], configurée par ProfiLab contient le nombre de composants DLL: 1 pour DLL1, 2 pour DLL2, et ainsi de suite…

 

   La procédure CALCULATE est appelée de façon répétée lorsque ProfiLab est en mode-RUN pour rafraîchir l'état des entrées et sorties de la DLL. Ceci implique que la DLL doit être la plus courte possible et ne doit contenir aucune pause (du type Boucle WAIT ou commande SLEEP) qui monopoliserait du temps machine. Après avoir lu les valeurs d'entrées et remis à jours les sorties la routine doit se terminer le plus rapidement possible. La durée de traitement de la DLL influencera directement la fréquence de simulation de ProfiLab.

 

   Delphi: Procedure CalculateEx(PInput,POutput,PUser: PDLLParams; PStrings: PStringParams);
    C++: void _stdcall CCalculateEx(double *PInput, double *POutput, double *PUser; StringParam PStrings)
    Cette méthode a été présentée pour permettre chaines traitant avec des DLL. Elle peut être employée comme alternative pour CALCULATE. Le paramètre PSTRINGS ont été ajoutés pour des données d'interface de chaines. Son delclaration de Delphes est comme suit :

 

   type TStringParams = array[0..100] of PChar;
    PStringParams = ^TStringParams;

 

   Chaque entrée-sortie (maximum 100) a un indicateur nul-terminé de caractère (PChar) assigné, qui se dirige à un espace mémoire qui est fourni par ProfiLab. Droit avant que ProfiLab écrive la méthode, des données sont cherchées du $entrees. Après être parti les données de méthode sont distribuerées par $sorties. Elles ne sont pas distinguées entre les entrées et les sorties. Ceci signifie cette entrée 0 et a produit 0 par exemple parts le même PChar. Faire une goupille devenir une $entrée ou une $sortie a produit sa goupille nom doit être déclarée avec un caractère principal '$'.
    Les exemples pour chaines traitant avec des DLL et le ProfiLab sont disponibles.

 

   Delphi: Procedure SimStart(PInput,POutput,PUser: PDLLParams);
    C++: void _stdcall CSimStart(double *PInput, double *POutput, double *PUser)
    Cette procédure est appelée lorsque ProfiLab entre en mode-RUN, et peut être utilisée pour initialiser les variables de la DLL.

 

   Delphi: Procedure SimStop(PInput,POutput,PUser: PDLLParams);
    C++: void _stdcall CSimStop(double *PInput, double *POutput, double *PUser)
    Cette procédure est appelée lorsque ProfiLab sort du mode-RUN, et peut être utilisée pour fermer les fichiers ouverts.

 

   Delphi: Procedure Configure(UserValues: PDLLParam);
    C++: void _stdcall CConfigure(double *PUser)
    Dès que votre DLL exporte cette procédure, le bouton CONFIGURE... est actif dans la boîte de propriétés du composant. Avec un click sur ce bouton, ProfiLab ira à votre procédure de CONFIGURATION, où vous pourrez ajouter votre propre dialogue pour votre DLL.

 

   Ces quelques routines vous permettront de programmer n'importe quel type de composant à ProfiLab. Vous pourrez ainsi créer des DLL capables de gérer vos propres cartes d'interfaces ou encore des DLL capables de réaliser des calculs très complexes.

 

   Si vous voulez programmer des composants avec des sorties digitales, mettez simplement les valeurs de ces dernières à 5 pour un niveau HAUT ou 0 pour un niveau BAS. Des valeurs numériques supérieure à 2.5 seront interprétées comme un niveau HAUT, des valeurs inférieures à 2,5 comme un niveau BAS.

 

   Votre fichier de DLL compilé peut être chargé dans la boîte de dialogue des propriétés du composant. Toutes les fonctions et procédure importées sont listées dans la boîte de dialogue. Le composant apparaîtra dans le circuit comme il a été désigné dans la DLL.

 

   En compilant votre propre projet de DLL assurez-vous que l'option "RTL dynamique" d'éditeur de liens est handicapée. Autrement le DLL ne peut pas être chargé sur des systèmes sans environnement installé de C++.


Message édité par Gruber Hans le 11-03-2013 à 19:26:15
Reply

Marsh Posté le 11-03-2013 à 19:25:33   

Reply

Marsh Posté le 13-03-2013 à 17:57:57    

Bonjour,
Je suis également sur une recherche similaire mais plutôt sur VB .NET (VB express 2010 gratuit)
J'ai fait un essai avec Visual C++ et j'ai finalement réussi à créer une DLL, pour ne rien oublier j'ai créé une page web sur la manière de procéder.
http://perso.numericable.fr/pboucheny/profilab/
Comme je ne pratique que le C sur µcontroleur PIC, ma cible actuelle est de faire la même chose avec VB2010 mais pour le moment je sèche la dessus. Il me crée une DLL mais lorsque je la test avec DLL export Viewer je ne vois aucune fonction.
J'ai déclaré par exemple GetInputName comme cela en C++ :
DLLEXPORT void _stdcall GetInputName(unsigned _int8 Channel,unsigned char *Name)
et comme cela en VB :
    Public Function GetInputName(Channel As Char, <MarshalAsAttribute(UnmanagedType.LPWStr)> ByRef Name As String)
Mais je ne suis absolument pas sûr de ce que je fais ici, si quelqu'un a une remarque...
Je te tiendrais au courant de mon avancement sur le sujet, et je crérais une page web comme pour le C++
 
J'ai placé en citation mon source actuel qui ne fonctionne hélas pas, il doit aussi y avoir des problèmes d'option paramétrage de VB pour générer la DLL.
Je pense à cette option dans C++ : Génération de code bibliothèque Runtime Multithread (/MT) que je n'ai pas trouvé dans VB.
Il y a aussi le fichier .def de C++ dont je n'ai pas trouvé d'équivalent en VB.
 

Citation :


Imports System
Imports System.IO.Ports
Imports System.Runtime.InteropServices
 
Public Class Class1
 
 
 
    'Index for input variables
    Const CLK = 0
    Const RST = 1
 
    'Index for user variables
    Const CLK_OLD = 0
    Const RST_OLD = 1
    Const COUNT = 2
 
    Dim inputs As Integer = 2 'two inputs
    Dim outputs As Integer = 2 'eight outputs
 
    Dim TDLLParams(100) As Decimal
 
    'return number of input channels...
    Public Function NumInputs() As Char
        Return CChar(CStr(inputs))
    End Function
 
 
    'return number of output channels...
    Public Function NumOutputs() As Char
        Return CChar(CStr(outputs))
    End Function
 
 
    'return name for each input...
    Public Function GetInputName(Channel As Char, <MarshalAsAttribute(UnmanagedType.LPWStr)> ByRef Name As String)
 
        'Dim ptr As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(GetType(Char)))
 
        If Int(Channel) = 0 Then
            'Name = Runtime.InteropServices.Marshal.ReadInt32(ptr)
            Name = "CLK" 'Name input 0
        Else
            Name = "RST" 'Name input 1
        End If
        Return Nothing
    End Function
 
 
    'return name for each output...
    Public Function GetOutputName(Channel As Char, <MarshalAsAttribute(UnmanagedType.LPWStr)> ByRef Name As String)
        If Int(Channel) = 0 Then
            'Name = Runtime.InteropServices.Marshal.ReadInt32(ptr)
            Name = "Q1" 'Name input 0
        Else
            Name = "Q2" 'Name input 1
        End If
        Return Nothing
    End Function
 
 
    'reset counter on start...
    Public Function CSimStart(<MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PInput() As Double, _
                              <MarshalAsAttribute(UnmanagedType.LPArray)> ByRef POutput() As Double, _
                              <MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PUser() As Double)
        Return Nothing
    End Function
 
 
    'check inputs and set outputs while running...
    Public Function CCalculate(<MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PInput() As Double, _
                              <MarshalAsAttribute(UnmanagedType.LPArray)> ByRef POutput() As Double, _
                              <MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PUser() As Double)
        Return Nothing
    End Function
 
 
 
    'called when project is stopped...
    Public Function CSimStop(<MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PInput() As Double, _
                              <MarshalAsAttribute(UnmanagedType.LPArray)> ByRef POutput() As Double, _
                              <MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PUser() As Double)
        'nothing to do...
        Return Nothing
    End Function
 
    'called when button CONFIGURE is pressed in dialogue...
    Public Function CConfigure(<MarshalAsAttribute(UnmanagedType.LPArray)> ByRef PUser() As Double)
        MsgBox("Nothing to configure", MsgBoxStyle.OkOnly, "Configure" )
        Return Nothing
    End Function
    'DONE!!!  
 
 
 
End Class


 
Cordialement


Message édité par philippe_b_77 le 13-03-2013 à 18:12:46
Reply

Marsh Posté le 15-03-2013 à 00:30:12    

Merci pour cette réponse.
 
Je suis bien sur très intéressé par ton avancée sur ce thème.
 
Cordialement.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed