2008-12-11 10 views
13

J'utilise ctypes pour charger une DLL en Python. Cela fonctionne très bien.Comment puis-je décharger une DLL en utilisant ctypes en Python?

Maintenant, nous aimerions être en mesure de recharger cette DLL lors de l'exécution.

L'approche simple semble être: 1. Décharger DLL 2. charge DLL

Malheureusement, je ne suis pas sûr de ce que la bonne façon de décharger la DLL est.

_ctypes.FreeLibrary est disponible, mais privée.

Existe-t-il un autre moyen de décharger la DLL?

+0

Avez-vous trouvé une meilleure réponse que ma façon laide? Sinon peut-être, vous devriez demander sur leur liste de diffusion, et si ce n'est pas présent, signalez-le. 'del' devrait appeler la fonction pour récupérer les ressources! –

Répondre

13

vous devriez être en mesure de le faire en disposant l'objet

mydll = ctypes.CDLL('...') 
del mydll 
mydll = ctypes.CDLL('...') 

EDIT: Commentaire de Hop est juste, ce délie le nom, mais la collecte des ordures ne se passe pas rapidement, en fait, je même doute qu'il libère même la bibliothèque chargée.

ctypes ne semble pas fournir un moyen propre de libérer des ressources, il ne fournit qu'un champ _handle à la poignée dlopen ...

La seule façon que je vois, vraiment, vraiment non manière propre, est de débloquer le système de manière dépendante du système, mais il est très très sale, car de plus ctypes conserve des références internes à ce handle. Donc, le déchargement prend quelque chose de la forme:

mydll = ctypes.CDLL('./mylib.so') 
handle = mydll._handle 
del mydll 
while isLoaded('./mylib.so'): 
    dlclose(handle) 

Il est tellement sale que je ne vérifié fonctionne à l'aide:

def isLoaded(lib): 
    libp = os.path.abspath(lib) 
    ret = os.system("lsof -p %d | grep %s > /dev/null" % (os.getpid(), libp)) 
    return (ret == 0) 

def dlclose(handle) 
    libdl = ctypes.CDLL("libdl.so") 
    libdl.dlclose(handle) 
+0

je ne sais pas, mais je doute que cela décharge la DLL. Je suppose qu'il ne supprime que la liaison du nom dans l'espace de noms actuel (selon la référence du langage) – hop

+0

Lorsque la bibliothèque partagée ne peut pas être décrémentée, POSIX 'dlclose' renvoie une valeur non nulle et Windows' FreeLibrary' renvoie zéro. '_ctypes.dlclose' et' _ctypes.FreeLibrary' (notez le trait de soulignement) soulèvent 'OSError' dans ce cas. – eryksun

+0

Pour les personnes qui souhaitent trouver un moyen de le faire sous Windows, voir http: // stackoverflow.com/questions/19547084/can-i-explicitement-fermer-un-ctypes-cdll – Gamrix

3

Il est utile de pouvoir décharger la DLL de sorte que vous pouvez reconstruire la DLL sans avoir à redémarrer la session si vous utilisez iPython ou un flux de travail similaire. Travailler dans Windows, j'ai seulement essayé de travailler avec les méthodes liées à Windows DLL. Je ne connais pas grand-chose de l'interne, donc je ne suis pas vraiment sûr de la propreté de ce système. Je pense que la suppression de mydll libère les ressources Python et l'appel FreeLibrary indique à Windows de le libérer. J'avais supposé que libérer avec FreeLibary d'abord aurait produit des problèmes ainsi j'ai sauvé une copie de la poignée de bibliothèque et l'ai libérée dans l'ordre montré dans l'exemple.

J'ai basé cette méthode sur ctypes unload dll qui a chargé la poignée explicitement à l'avant. La convention de chargement ne fonctionne pas aussi bien que le simple "ctypes.cdll.LoadLibrary ('test.dll')" donc j'ai opté pour la méthode montrée.

+1

Ceci est faux. Un descripteur de module DLL/EXE est un pointeur vers l'adresse de base du module, qui est en général une valeur de 64 bits dans Python 64 bits. Mais ctypes passe les entiers comme des valeurs C 'int' de 32 bits; qui va tronquer la valeur d'un pointeur 64 bits. Vous devez soit envelopper le handle comme un pointeur, c.-à-d. 'Ctypes.c_void_p (mydll._handle)', ou déclarer 'kernel32.FreeLibrary.argtypes = (ctypes.c_void_p,)', ou appeler à la place '_ctypes.FreeLibrary' (note le trait de soulignement initial, c'est le module d'extension '_ctypes' sous-jacent). – eryksun

Questions connexes