[C] Utilisation d'une DLL

Utilisation d'une DLL [C] - C - Programmation

Marsh Posté le 11-11-2008 à 11:42:48    

Bonjour,
 
Je cherche à utiliser une DLL dans un programme en C, fournie pour l'utilisation d'un matériel spécifique; n'étant pas très au point sur ce sujet, j'ai cherché de la doc là-dessus mais je n'ai pas trouvé les infos qui me seraient utiles (notamment les infos de base).  
 
Avant même l'utilisation de la DLL en question, pour me faire la main, j'ai essayé de réaliser un exemple. Mais il me manque la base pour savoir si mon exemple correspond à la réalité. :o  
 
Déjà, qu'est-ce qu'une DLL, à part une bibliothèque logicielle (compilée, n'est-ce pas ?) Quels sont les similitudes et différences avec une API ? Qu'est-ce qu'elle a de différent vis-à-vis d'un fichier d'entête (.h) "classique" ? Le seul début de réponse que j'ai trouvé à ce sujet est qu'à priori, les fonctions de la DLL dont on a besoin doivent être chargées en RAM (?)

Message cité 1 fois
Message édité par Edwardkei le 11-11-2008 à 12:06:16
Reply

Marsh Posté le 11-11-2008 à 11:42:48   

Reply

Marsh Posté le 11-11-2008 à 14:17:20    

Edwardkei a écrit :

Bonjour,
Déjà, qu'est-ce qu'une DLL, à part une bibliothèque logicielle (compilée, n'est-ce pas ?)  


une dll c'est une bibliothèque qui à la particularité d'être chargée au démarrage de l'application et liée à l'application à ce moment là  
contrairement à une libraire statique inclue dans le programme au moment de la compilation
http://en.wikipedia.org/wiki/Linker

Edwardkei a écrit :


Quels sont les similitudes et différences avec une API ?  


une API c'est juste un ensemble de fonction dont le nom et les arguments et leur action et défini dans un document.
les dll ou les librairies statiques peuvent contenir une implementation d'une API.

Edwardkei a écrit :


Qu'est-ce qu'elle a de différent vis-à-vis d'un fichier d'entête (.h) "classique" ?  


Un en-tête contient juste les déclarations des fonctions, il dit juste au compilateur cette fonction existe et prend tels arguments, c'est ensuite à l'édition de lien que les appels à ces fonctions sont remplacées par des adresses réelles.

Edwardkei a écrit :


Le seul début de réponse que j'ai trouvé à ce sujet est qu'à priori, les fonctions de la DLL dont on a besoin doivent être chargées en RAM (?)


Oui mais si tu as codé correctement ton programme pour utiliser la DLL ça se fait tout seul au lancement du programme.
 
 
enfin si tu as un niveau suffisant en anglais:
http://en.wikipedia.org/wiki/Dynamic-link_library
très complet avec pleins de références en bas de page.

Message cité 1 fois
Message édité par sligor le 11-11-2008 à 14:26:58
Reply

Marsh Posté le 13-11-2008 à 14:34:51    

sligor a écrit :

une dll c'est une bibliothèque qui à la particularité d'être chargée au démarrage de l'application et liée à l'application à ce moment là contrairement à une libraire statique inclue dans le programme au moment de la compilation
http://en.wikipedia.org/wiki/Linker

Elle est chargée quand le progrmme en a besoin. Ca peut-être longtemps après le chargement du programme. Cela peut-être longtemps avant si un autre programme en a eu besoin.
 

sligor a écrit :

une API c'est juste un ensemble de fonction dont le nom et les arguments et leur action et défini dans un document. les dll ou les librairies statiques peuvent contenir une implementation d'une API.

Une API Windows (pour les autres API c'est peut-être différent) n'est pas un ensemble de fonctions, c'est UNE fonction, écrite en C, incluse dans Windows et documentée par M$. Les API résident physiquement dans des DLL (user32.dll, par exemple).
 

sligor a écrit :

Oui mais si tu as codé correctement ton programme pour utiliser la DLL ça se fait tout seul au lancement du programme.

Cela dépend de la DLL. Si c'est une DLL du noyau, il n'y a pas besoin de demander son chargement, mais si c'est une DLL maison, alors il faut demander son chargement (que Windows ne fera pas s'il voit qu'elle est déjà chargée en mémoire) avec l'API LoadLibrary().

Reply

Marsh Posté le 13-11-2008 à 16:57:35    

Citation :

Une API Windows (pour les autres API c'est peut-être différent) n'est pas un ensemble de fonctions, c'est UNE fonction, écrite en C, incluse dans Windows et documentée par M$. Les API résident physiquement dans des DLL (user32.dll, par exemple).

:non:  
C'est un ensemble de choses pouvant être:
Des structures de données.
Des fonctions et procedures.
Des classes et méthodes.
Des protocoles.
Et ce n'est pas nécessairement écrit en C, même si un prototype C, utilisable pour linker, est fourni.
 
Une API peut être réduite a une fonction, mais en général ce n'est pas le cas.
Et en ce qui concerne windows, in wikipaedia veritas:  

Citation :

An application programming interface (API) is a set of functions, procedures, methods, classes or protocols that an operating system, library or service provides to support requests made by computer programs


Citation :

The Windows API, informally WinAPI, is Microsoft's core set of application programming interfaces (APIs) available in the Microsoft Windows operating systems. It was formerly called the Win32 API; however, the name Windows API more accurately reflects its roots in 16-bit Windows and its support on 64-bit Windows. All Windows programs must interact with the Windows API regardless of the language.


L'API Windows est constituée d'un paquet d'apis relativement indépendantes, par exemple l'API Direct X.
A+,


Message édité par gilou le 13-11-2008 à 16:59:25

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 17-11-2008 à 10:51:01    

La différence réside dans le fait que pour un chargement explicite, il faut inclure dans le programme l'appel à LoadLibrary(), GetProcAddress(), et FreeLibrary() alors que ce n'est pas nécessaire si le chargement est implicite.
En général pour les DLL que l'on crée soi-même, le chargement est explicite, donc on fait les trois appels dans le programme appelant.


Message édité par olivthill le 17-11-2008 à 10:53:37
Reply

Marsh Posté le 17-11-2008 à 13:05:56    

Avec LoadLibrary(), on est certain que la DLL sera chargée. Cela évite d'avoir à se poser des questions en fonction de la version de Windows ou d'autres paramètres. Et si on fait LoadLibrary() alors que ce n'est pas utile, alors tout marche quand même. Mais, pour les DLL hyper communes, du genre user32.dll, c'est inutile de le faire.
 
Souvent les booleans sont en fait des integers. Mais ce serait mieux si la DLL retournait des integers.

Reply

Marsh Posté le 17-11-2008 à 15:56:35    

En général vaut mieux laisser Windows faire ça, car le code est nettement plus simple.
 
Il peut tout de même y avoir un intérêt à charger la dll soit même : lorsqu'on veut proposer des fonctionnalités facultatives. Par exemple ton programme peut tourner sans une certaine dll, mais si elle est présente, ça permet d'offrir quelques fonctionnalités supplémentaires. Cette dll pour une raison ou une autre est difficile à distribuer (payante, lourde, compliquée à installée, etc ...).  
 
Si tu utilise la liaison dynamique normale, ton programme imposera que cette dll soit présente dès le démarrage, même si on n'utilise pas les fonctions de cette dll. Avec LoadLibrary, tu pourra simplement afficher un message si la dll n'est pas trouvée. Mais bon, ça va être lourd à gérer dans le code, puisqu'en général les dll ne sont pas prévues pour être ouverte à la main.
 
Par exemple avec gcc, c'est le genre de code que j'écris pour rediriger de manière transparente toutes les fonctions vers des pointeurs. C'est le plus "simple" que j'ai pu trouvé et je trouve que c'est encore super lourd.
 

Code :
  1. #define declPtr(func)  typeof(func) (*p##func) = NULL
  2. #define openPtr(func)  p##func = (typeof(func)) GetProcAddress(dll, #func)
  3. declPtr(fonction1);
  4. declPtr(fonction2);
  5. /* ... */
  6. #define fonction1    pfonction1
  7. #define fonction2    pfonction2
  8. /* ... */
  9. int main(void)
  10. {
  11.     HMODULE dll = LoadLibrary("bleurp.dll" );
  12.     if (dll)
  13.     {
  14.         openPtr(fonction1);
  15.         openPtr(fonction1);
  16.     }
  17.     else fprintf(stderr, "dll not found. Exiting\n" ), exit(1);
  18.     /* ... */
  19.     return 0;
  20. }

Reply

Marsh Posté le 18-11-2008 à 14:03:21    

Ta DLL, tu dois l'écrire avec labWindows non ?
Si oui, alors oui, il ne s'agit que d'un compilateur C. Pas de C++.
Cependant, pas de problème particulier normalement à utiliser des DLL écrites en C++.
 
Edit : pour la caméra, tu utilises NI Vision ?


Message édité par kao98 le 18-11-2008 à 14:07:57

---------------
Kao ..98 - Uplay (R6S) : kao98.7.62x39 - Origin (BF4, BF1) : kntkao98
Reply

Marsh Posté le 19-11-2008 à 13:07:56    

Edwardkei a écrit :

Oui mais dans le cas où Windows gère tout seul le chargement en mémoire, il peut y avoir un problème lors de l'utilisation de la DLL sur un OS proche mais suffisamment différent pour poser potentiellement problème (au hasard Windows Vista :D). En d'autres termes, le code n'est pas "tellement" portable d'un OS (de même type) à un autre... Je me trompe ?
 
Sinon, en fait, pour clarifier les choses, l'utilisation de la DLL propriétaire dont j'ai besoin repose sur le fait que je puisse la mettre en oeuvre via une autre DLL de ma conception. Tout ceci pour permettre l'utilisation d'une caméra sous LabVIEW (qui n'accepte pas comme valeur de retour un pointeur sur fonction, d'où l'intérêt de ma DLL, qui jouerait le rôle d'interface). Ceci se résume comme suit :
 
| Caméra | <=> | DLL caméra | <=> |Ma DLL| <=> |LabVIEW
 
Les fonctions exportées par la DLL de la caméra sont, pour une bonne partie, écrites en C++, ce qui fait hurler mon compilateur (GCC). La question que je me pose c'est donc est-ce que les DLL ne sont écrites qu'en C ? D'ailleurs, lorsque je crée un projet de DLL dans cet IDE, il ne me laisse pas le choix du langage...

Utiliser une DLL compilée avec un compilo A dans un programme compilé avec un compilo B, ca a toujours été périlleux: Un exemple de problème rencontré: le compilo A installe son handler d'erreur en cas de division par zero. Le compilo B aussi.  
Le programme se lance => handler de div par 0 du comp A installé
Il appelle le dll qui execute du code => handler de div par 0 du comp B installé, qui masque le précédent.
Le code principal de l'appli (pas de la dll) fait une division par 0 => handler de div par 0 du comp B appellé. Bref on appelle un pointeur, mais dans le mauvais espace d'adressage (celui de l'appli et non celui de la DLL) d'ou plantage.
Bon, en virant la div par 0 du code principal, le probleme disparait, mais ca donne une idée de ce a quoi il faut faire gaffe.
Si mes souvenirs sont bons, de plus, le compilo A (Metaware) fonctionnait en addressage 32 bits, sous windows 3.1 et le compilo B etait celui de Microsoft, en 16 bits donc.
A+,


Message édité par gilou le 19-11-2008 à 13:45:36

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 19-11-2008 à 15:13:35    

C'est pour cela que en environnement professionnel, les vendeurs de dll payantes te proposent parfois la dll compilée avec plusieurs versions du compilo :D
Disons qu'entre la théorie et la pratique, y'a parfois un décalage.
Mais c'est vrai qu'en général, l'interopérabilité est assez bonne.

 

A+,


Message édité par gilou le 19-11-2008 à 15:18:30

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 19-11-2008 à 15:13:35   

Reply

Marsh Posté le 27-11-2008 à 15:40:10    

Edwardkei a écrit :


je ne peux utiliser un tableau à taille variable comme en C++ (où C99):

Code :
  1. unsigned short pImageData[AllocatedSize]={0}




Ouais et tant mieux, les VLA d eplus de 128K font planter les systemes en general. C'ets la plaie c'ets truc, à ne pas utiliser :o
 
 

Edwardkei a écrit :


A quoi sert le "+3" et le "& -4" (pour ce dernier, masquage ?) ?


c'est une astuce pr  calculer le multiple de 4 strictement supérieur à  width * colorChannels
 

Edwardkei a écrit :


Qu'en pensez-vous ?


n'oublie pas le free qui va avec à la fin

Reply

Marsh Posté le 27-11-2008 à 16:50:20    

L'intérêt de la chose est que si ce n'est pas un multiple de 4, alors les données ne sont pas "alignées" et cela ne marche pas.

Reply

Marsh Posté le 27-11-2008 à 16:50:52    

Edwardkei a écrit :

Tu peux détailler ? l'intérêt de la chose par exemple ?


 
Les bitmaps sous Windows doivent avoir les lignes paddés sur 32bits pour être manipulés avec GDI ou GDI+.

Reply

Marsh Posté le 28-11-2008 à 12:13:36    

Pourquoi aligner les début de ligne sur 4 octets ? Parce que c'est plus rapide sur les architectures 32-bit (CPU et/ou chip de la carte graphique), car sinon le microprocesseur est obligé de faire un masquage pour ne récupérer qu'à partir du deuxième, troisième ou quatrième octet dans son registre de 32 bits.

Reply

Marsh Posté le 28-11-2008 à 16:12:00    

Ce n'est pas une question d'intérêt, mais de nécessité. Essayez votre progrmame avec une longueur de 663 et s'il ne marche pas (comme je le suppose), essayez avec l'alignement sur 664 (et il devrait marcher).

Reply

Marsh Posté le 28-11-2008 à 17:12:10    

Plus que de nécessité, je dirais d'optimisation. Enfin, ça reste encore à prouver que c'est toujours utile à l'heure actuelle. Pour autant que je me souvienne cette contrainte date de la préhistoire : Windows 3.1 au plus. Par compatibilité ascendante, Microsoft n'avait pas trop d'autre choix que de garder cette contrainte. Cela dit, c'est pas la mort non plus. Perso j'aligne ça avec un code du genre :

Code :
  1. width = (width + 3) & ~3


Reply

Sujets relatifs:

Leave a Replay

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