2009-06-27 7 views
6

Quelle est la meilleure façon de concevoir une API C pour dll qui traite le problème du passage des "objets" qui dépendent de l'exécution C (FILE *, pointeur retourné par malloc, etc ...) . Par exemple, si deux DLL sont liées à une version différente de l'exécution, je crois comprendre que vous ne pouvez pas transmettre un FICHIER * d'un DLL à l'autre en toute sécurité.C Objets Runtime, limites dll

Est-ce la seule solution à utiliser une API dépendante de Windows (qui est garantie pour fonctionner avec les DLL)? L'API C existe déjà et est mature, mais a été conçue à partir d'un POV unix, pour la plupart (et doit encore fonctionner sur unix, bien sûr).

Répondre

0

Le problème avec les différents temps d'exécution n'est pas résolu car la structure FILE * appartient à une seule exécution sur un système Windows.

Mais si vous écrivez un petit wrapper Interface, c'est fait et ça ne fait pas vraiment mal.

stdcall IFile* IFileFactory(const char* filename, const char* mode); 

class IFile { 

    virtual fwrite(...) = 0; 
    virtual fread(...) = 0; 

    virtual delete() = 0; 
} 

Ceci est enregistré pour être transmis à travers les limites dll partout et ne fait pas vraiment mal.

P.S .: Soyez prudent si vous commencez à lancer des exceptions à travers les limites de la DLL. Cela fonctionnera bien si vous remplissez certains crétins de conception sur Windows OS, mais échouera sur certains autres.

1

Aucune des réponses existantes n'est correcte: Étant donné ce qui suit sous Windows: vous avez deux DLL, chacune est liée statiquement à deux versions différentes des bibliothèques standard C/C++.

Dans ce cas, vous ne devez pas passer de pointeurs aux structures créées par la bibliothèque standard C/C++ dans une DLL à l'autre. La raison en est que ces structures peuvent être différentes entre les deux implémentations de bibliothèque standard C/C++. L'autre chose que vous ne devriez pas faire est de libérer un pointeur alloué par new ou malloc à partir d'une DLL allouée dans l'autre. Le gestionnaire de tas peut être implémenté différemment. Remarquez, vous pouvez utiliser les pointeurs entre les DLL - ils pointent juste vers la mémoire. C'est le libre qui est le problème. Maintenant, vous pouvez trouver que cela fonctionne, mais si c'est le cas, alors vous êtes juste de la chance. Cela risque de vous causer des problèmes à l'avenir.

Une solution potentielle à votre problème est la liaison dynamique au CRT. Par exemple, vous pouvez lier dynamiquement à MSVCRT.DLL. De cette façon, vos DLL utiliseront toujours le même CRT.

Remarque, je suggère que ce n'est pas une bonne pratique pour passer des structures de données CRT entre les DLL. Vous pourriez vouloir voir si vous pouvez mieux factoriser les choses. Remarque: je ne suis pas un expert Linux/Unix, mais vous aurez également les mêmes problèmes sur ces systèmes d'exploitation.

+0

Je comprends les problèmes - Je demande des réponses à ce problème :) J'espérais une solution qui ne suppose pas de changer l'API C existante (avec FILE * dans la signature et ainsi de suite), mais il semble qu'il n'y a pas 't si je ne peux pas garantir tout à lier contre le même runtime C? Bien que le problème soit théoriquement le même sur Unix, il s'agit rarement d'un problème car il n'existe qu'un seul cycle d'exécution C. Je n'ai jamais eu un seul problème en passant FILE *, les descripteurs de fichiers sur unix entre les bibliothèques - beaucoup de C APIS sont conçus de cette façon et fonctionnent parfaitement sur ces systèmes d'exploitation. –

+0

Si avoir FICHIER * dans la signature de l'API n'est pas une bonne pratique, comment traitez-vous les flux de fichiers? Avez-vous besoin d'exporter les fonctions pour ouvrir et fermer les fichiers si la DLL que vous appelez a certaines fonctions qui appellent en interne fprintf et d'autres fonctions qui attendent FILE *? –

+0

J'ai fait une suggestion une solution :) Ne pas lier statiquement à la CRT. lien vers MSVCRT.DLL. Je serais très surpris si toutes les bibliothèques CRT sous Linux, Unix ou le MAC fonctionnaient sans problème. Je pense que vous avez été chanceux là aussi. – Foredecker

0

Si l'API C existe et est mature, contournant le CRT en interne à l'aide de l'API Win32 pure, vous obtenez la moitié du chemin. L'autre moitié s'assure que l'utilisateur de la DLL utilise les fonctions correspondantes de l'API Win32. Cela rendra votre API moins portable, à la fois pour l'utilisation et la documentation. Aussi, même si vous allez de cette façon avec l'allocation de mémoire, où les fonctions CRT et Win32 traitent avec void *, vous êtes toujours en difficulté avec le fichier - Win32 API utilise des handles, et ne sait rien de la structure FILE.Je ne suis pas tout à fait sûr quelles sont les limites du FICHIER *, mais je suppose que le problème est le même que pour les allocations CRT entre les modules. MSVCRT utilise Win32 en interne pour gérer les opérations de fichier et le handle de fichier sous-jacent peut être utilisé à partir de chaque module dans le même processus. Ce qui ne fonctionne pas, c'est la fermeture d'un fichier qui a été ouvert par un autre module, ce qui implique de libérer la structure FILE sur un CRT éventuellement différent. Ce que je ferais, si la modification de l'API est toujours une option, serait de faire des fonctions de nettoyage d'exportation pour tout "objet" possible créé dans la DLL. Ces fonctions de nettoyage géreront la disposition de l'objet donné de la manière qui correspond à la façon dont il a été créé dans cette DLL. Cela rendra la DLL absolument portable en termes d'utilisation. Le seul souci que vous aurez alors est de vous assurer que l'utilisateur de la DLL utilise effectivement vos fonctions de nettoyage plutôt que celles du CRT. Cela peut être fait en utilisant plusieurs astuces, qui méritent une autre question ...

2

Vous avez demandé une solution C, pas une solution C++.

La méthode habituelle (s) pour faire ce genre de chose en C sont:

  • Conception de l'API modules tout simplement pas besoin d'objets CRT. Faites passer des données dans des types C bruts, c'est-à-dire que le consommateur charge le fichier et vous passe simplement le pointeur. Ou, faites en sorte que le consommateur transmette un nom de fichier complet, ouvert, lu et fermé en interne. Une approche utilisée par d'autres modules c, le cabinet MS SD et des parties de la bibliothèque OpenSSL iirc, vient à l'esprit, faire passer l'application consommatrice dans des pointeurs vers des fonctions à la fonction d'initialisation. Ainsi, toute API que vous passez un FICHIER * à un moment donné lors de l'initialisation a pris un pointeur vers une structure avec des pointeurs de fonction correspondant aux signatures de fread, fopen etc. En traitant les FICHIERS * externes, la DLL utilise toujours le passé fonctions plutôt que les fonctions CRT.

Avec quelques trucs simples comme cela, vous pouvez faire votre interface C de DLL entièrement indépendante du CRT hôtes - ou en fait besoin d'être l'hôte écrit en C ou C++ du tout.