Tag d'archives : DLL

Une coupure d’Internet dans la matinée nous a fait perdre un peu de temps.

La solution proposée par la JMF n’étant pas très concluante, Nicolas R. m’a montré le code Java qu’il avait réalisé permettant de récupérer le nom des périphériques audio. Ce code fonctionne très bien et renvoie bien la même liste de périphériques audio que le faisait ma DLL. J’ai donc tenté de partir de ce code et de voir s’il existait quelque chose d’équivalent pour les périphériques vidéo. Malheureusement, il semblerait bien que non. La JMF reste la seule alternative, mais afin de l’utiliser correctement, il faut utiliser parallèlement une application appelée la JMFRegistery. Tant qu’un périphérique vidéo n’est pas enregistré dans la JMFRegistery, il ne pourra pas être détecté par la JMF. Par ailleurs, sur Internet, quelques personnes conseillent, dans ce genre de situation, de créer une DLL en C qui sera ensuite appelée par Java. Retour à la case départ.

Sur les conseils d’un Internaute, j’ai téléchargé et installé Dependency Walker, un logiciel qui permet de tracer le graphe de dépendance d’une DLL à toutes les autres DLL qu’elle utilise. Ma DLL dépend d’un nombre très important d’autres DLL, et il est difficile de déterminer lesquelles appartiennent au framework .NET. Nous avons cependant tout de même tenté d’en installer quelques-unes sur l’ordinateur de Lorenzo, mai rien n’y fait, Eclipse ne réussit toujours pas à utiliser ma DLL.

J’ai ensuite jeté un coup d’œil au code dont Nicolas R. s’est inspiré, que vous pouvez trouver ici. En le testant, il ne m’a renvoyé qu’un seul périphérique : celui permettant la capture des images de la webcam, tout comme le faisait la JMF. Pour permettre le choix de la webcam, l’auteur de ce code a simplement appelé une fonction de la DLL User32 qui affiche un boîte de dialogue contenant la liste déroulante des webcams connectées.

Après avoir quelque peut “fignolé” ma dll et avoir écrit des fonctions Java permettant de récupérer les périphériques audio et vidéo, ainsi que leurs codecs, j’ai fourni à Lorenzo le .jar et la dll dont il aurait besoin pour son projet. Malheureusement, après les avoir installés et après avoir reconfiguré le projet de sorte à ce qu’il prenne ces deux fichiers en compte, lorsqu’il a essayé d’utiliser une des fonctions java dans son code, cela lui renvoyait l’erreur suivante :

java.lang.UnsatisfiedLinkError: Unable to load library ‘DShowUtil’: The specified module could not be found.

À travers ce que nous avons compris dans certains forums, il semblerait que problème vienne du fait que ma dll utilise elle-même d’autres librairies que ne sont pas installées, ou que le projet n’arrive pas à trouver. Nous avons alors entrepris d’installer le SDK de Windows fournissant DirectShow, mais cela n’a rien changé. Nous avons ensuite installé Visual C++ 2008 Express, dans le but de compiler les BaseClasses de DirectShow, mais même sans compiler ces classes, le code a soudain fonctionné. Lorsque  nous avons désinstallé le SDK de Microsoft, le code fonctionnait toujours, mais plus après avoir désinstallé Visual Studio. Pour que Eclipse puisse utiliser cette dll, Visual C++, et donc le Framework .NET doivent donc nécessairement être installés sur l’ordinateur. Ceci pose un gros problème, car on ne peut pas demander aux utilisateurs d’installer un framework aussi lourd pour une seule petite fonctionnalité. J’ai donc jeté un coup d’œil, parallèlement, à ce qui était possible de faire avec la JMF, mais il semblerait que ça ne soit pas les bons périphériques qui sont retournés. Je vais cependant tenter de creuser encore un peu de ce côté-là.

Voici à présent un petit tutoriel expliquant comment compiler la DLL :

- Téléchargez et installez Visual C++ 2008 Express

-Téléchargez et installez Windows SDK for Windows Server 2008 and .NET Framework 3.5

- Sous Visual, ouvrez le projet contenant la DLL (Ouvrir > Projet, puis ouvrez le dossier DShowUtils et sélectionnez le ficher DshowUtils)

- Dans les propriétés de l’éditeur de liens (Projet > Propriétés > Propriétés de configuration > Editeur de liens > Entrée > Dépendances supplémentaires) , ajoutez les librairies suivantes : user32.lib, ole32.lib, oleaut32.lib, quartz.lib, strmiids.lib.

Nicolas R. m’a montré comment indiquer le chemin de la DLL à la JNA. J’ai donc pu écrire un bout de code utilisant les fonctions de ma DLL. Ce code affiche le premier élément de chaque liste (périphériques vidéo, périphériques audio, compresseurs vidéo et compresseurs audio). Cela fonctionne, mais selon les cas, le programme est interrompu et renvoie l’exception suivante :

#
# An unexpected error has been detected by Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0×7c921639, pid=448, tid=1348
#
# Java VM: Java HotSpot(TM) Client VM (11.2-b01 mixed mode, sharing windows-x86)
# Problematic frame:
# C  [ntdll.dll+0x11639]
#
# An error report file with more information is saved as:
# C:\Documents and Settings\Administrateur\workspace\JNATest\hs_err_pid448.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

J’ai effectué quelques recherches sur Internet, indiquant que cela pouvait venir de la JVM. Mais j’ai également vérifié les logs de ces erreurs, et ils semblerait que cela soit plutôt dû à un problème de pointeurs. J’ai donc modifié un peu le code de ma dll, mais le problème persiste selon les cas.

Après plusieurs modifications de la DLL, et avec l’aide de Nicolas R., il s’est finalement avéré que l’objet récupéré n’était pas le bon, puisqu’il s’agissait du premier élément de chaque liste, et non de la liste en elle-même. J’ai ensuite dû faire attention au fait que lorsqu’aucun périphérique n’est connecté, l’exception précédente était renvoyée. J’ai donc fait en sorte que l’on vérifie que l’énumérateur de périphériques est bien crée, et que, dans le cas contraire, renvoie un tableau vide et une taille nulle. Cela m’a pris un certain temps car je n’avais pas tout de suite réalisé que l’absence de périphériques empêchait la création de cet énumérateur.

J’ai continué à travailler à la résolution de mon exception. Ne réussissant pas à trouver de solution, on m’a fait savoir qu’en dernier recours, je pouvais éventuellement abandonner le code C++ pour la JMF de Java. Celle-ci permet en effet de récupérer la liste des périphériques vidéo et audio connectés, comme vous pouvez le voir ici.

J’ai cependant tenté de poursuivre l’implémentation en C++. Au bout d’un moment, j’ai fini par comprendre que le problème venait du tableau de string que je renvoyais. J’ai remplacé ce dernier par un TCHAR**, qui est donc un type non managé, mais l’erreur persistait, ce que j’ai trouvé très étrange. En effet, il ne fallait pas oublier de recopier le fichier de la DLL dans le répertoire du projet qui l’utilisait! J’ai eu par la suite quelques petites erreurs classiques dont il fut bien plus simple de venir à bout, et j’ai finalement réussi à faire fonctionner mon projet avec le code de la DLL, même si celui-ci n’est pas encore parfait.

À présent, j’essaye d’importer cette DLL avec l’aide de la JNA. La seule difficulté à laquelle je me heurte pour le moment est de faire en sorte que la JNA trouve cette DLL.

J’ai effectué plusieurs tentatives afin d’écrire une dll qui fonctionne. En effet, de nombreux sites donnaient des informations contradictoires et de plus, il existe apparemment plusieurs manières d’écrire une dll sous Visual C++ 2008 Express. J’ai finalement trouvé cette solution qui est très facile à mettre en place et qui fonctionne très bien. Cependant, il y a deux petits détails qui ont étés omis dans ce post, qui sont les suivants : il faut également penser à ajouter le répertoire où se trouve le header de votre librairie à l’ensemble des répertoires d’Include du projet utilisant la ddl, (Outils -> Options -> Projets et solutions -> Répertoires de VC++ -> Afficher les répertoires pour : Fichiers Include), et il faut ajouter votre fichier dll au répertoire Debug de ce même projet.

J’ai ensuite implémenté les fonctions que je désirais dans ma DLL. Malheureusement, cela ne fonctionnait pas, car j’utilisais des types managés. Pour pouvoir contourner ce problème, au lieu d’utiliser dllexport dans la librairie, il suffit d’écrire la librairie comme n’importe quel projet Visual C++, et d’y ajouter un fichier de définition. Cela m’a pris un peu de temps car je ne savais pas comment ajouter un tel fichier dans un projet C++. Enfin, il faut utiliser DLLImport dans le projet qui utilise cette librairie, comme indique à la fin de cet article.

Mon projet compile enfin avec la DLL, mais malheureusement, je rencontre une exception à l’exécution, indiquant qu’il est impossible de marshaler les types génériques. Je travaille actuellement à sa résolution.

J’ai finalement réussi à faire fonctionner l’émetteur vidéo. Malheureusement, il semblerait bien qu’il ne réussisse toujours pas à envoyer les données au récepteur. Qui-plus-est, le récepteur provoque à présent des erreurs à l’exécution, et je n’arrive pas à déterminer d’où cela vient.  En effet, il semblerait qu’il se ferme lorsqu’on lance un nouveau thread, chose qu’il ne faisait pas auparavant.

Parallèlement, pour pallier à mes problèmes de JNA, on m’a conseillé d’écrire une DLL contenant des fonctions qui réalisent le remplissage des listes déroulantes, auxquelles on ne passerait en paramètre que des objets de type simple. J’ai donc écrit une telle DLL, mais j’ai rencontré quelques soucis à la compilation, car les propriétés du projet n’étaient pas bien configurées. J’essaie à présent d’utiliser certaines des fonctions de cette DLL dans un projet, mais je rencontre là aussi, quelques difficultés.