2017-09-04 1 views
2

J'ai une application C++ qui est liée à certaines bibliothèques dynamiques tierces. Certaines de mes classes principales héritent de ces bibliothèques, et font des appels de fonction à ces bibliothèques, etc. Mon application fonctionne sans l'inclusion de ces bibliothèques en théorie (ie, si je supprimais manuellement tout le code et les références se rapportant à ces bibliothèques, fonctionne encore), il serait juste plus limité dans la fonctionnalité. Si je pouvais faire une analogie, imaginez que j'ai créé un clone Windows Notepad, et inclus une bibliothèque tierce qui permet aux utilisateurs d'intégrer des images et des vidéos dans le document.C++: autorise l'exécution du programme même si une DLL tierce est manquante?

Lorsque je distribue mon application, il est possible que mes clients ne disposent pas de ces bibliothèques. Existe-t-il une façon dont mon programme peut détecter si la bibliothèque de DLL requise existe, et ignore simplement tout le code lié s'il n'est pas installé?

Actuellement, si j'exécute mon application sans les bibliothèques tierces installées, elle affiche les erreurs liées aux DLL manquantes et aux plantages. Une solution évidente est de simplement libérer deux versions de mon application ... une sans les dépendances externes et une avec, mais je voudrais éviter de gérer deux produits indépendamment comme ça.

+1

Vous devrez peut-être procéder à une nouvelle architecture, mais [chargement dynamique] (https://en.wikipedia.org/wiki/Dynamic_loading) pourrait faire partie de la solution. –

+1

Vous pouvez être intéressé par le [Plugin Pattern] (https://stackoverflow.com/questions/785480/good-patterns-for-a-c-c-plugin-based-system). – user0042

Répondre

2

Il y a une telle option « dll charge de retard »

  1. Pour dll xxx.dll vous configurez éditeur de liens à utiliser « delayload »
  2. Jusqu'à ce que vous appelez une fonction de dll il ne sera pas chargé et votre application va démarrer avec succès même si la DLL n'est pas présente
  3. Vous utilisez LoadLibrary pour vérifier si xxx.dll est disponible.
  4. Si LoadLibrary a échoué - vous désactivez le module en utilisant xxx.dll
  5. Si LoadLibrary réussit - Vous le déchargez (vous n'avez pas besoin de chargement dynamique - il ne sert qu'à tester la présence de la DLL) et utilisez la bibliothèque comme si elle est liée régulièrement - pas besoin de modifier le code en utilisant toutes les fonctionnalités liées à la xxx.dll
+0

Retarder la charge est très facile, plus utile si le nom de la DLL est fixe. Mais certaines bibliothèques tierces modifient leur nom de DLL, par exemple, il inclut (stupidement) un numéro de version. Dans ce cas, voir la réponse de Wayne ci-dessous. Malheureusement GetProcAddress est fastidieux. – davidbak

0

Si vous souhaitez distribuer le binaire de votre application, vous pouvez utiliser le chargement dynamique (jetez un oeil here)

Mais si vous avez la possibilité de construire votre application sur le système des clients, vous pouvez utiliser CMake et définir la compilation f retarde s'il n'a pas pu trouver la bibliothèque que vous voulez. Ensuite, votre code peut se comporter en fonction de la valeur de cet indicateur (c.-à cette façon, vous avez les informations sur la météo cette bibliothèque existe ou non dans votre code)

2

Voir cette réponse ici: Dynamically load a function from a DLL

  1. Vous utilisez essentiellement LoadLibrary pour charger la DLL, le résultat sera null ou non si elle est chargée.

  2. Ensuite, vous utilisez GetProcAddress pour obtenir les fonctions.

0

Chargement lib dynamique ou l'injection au processus ou ... peut être en utilisant après cela, vous pouvez:

if (ul_reason_for_call == DLL_PROCESS_ATTACH) 
{ 
    inj_hModule = hModule; 
    DisableThreadLibraryCalls(hModule); // Disable DllMain calls for DLL_THREAD_* 

    HANDLE hThreadProc = CreateThread(nullptr, NULL, LPTHREAD_START_ROUTINE(ThreadProc), hModule, NULL, nullptr); 
    CloseHandle(hThreadProc); 
    Beep(2000, 500); 
} 

if (ul_reason_for_call == DLL_PROCESS_DETACH) 
{ 
    Beep(2000, 500); 
    FreeLibraryAndExitThread(hModule, 0); 
    // exit this thread 
    ExitThread(0); 
} 
0

Eh bien, vous devriez revoir votre architecture logicielle, et aller sur un Plugin Design Pattern tout comme présenté par Martin Fowler.
Vous ne voulez pas de liaison dynamique pour un tel cas, même si c'est assez similaire.

implémentations En ce qui concerne en C++ qui signifie essentiellement vous présenter une première interface abstraite

struct Foo { 
    virtual void Bar() = 0; 
    virtual ~Foo() {} 
}; 

et recherche pour les implémentations appropriées à venir avec les bibliothèques partagées à l'exécution .

L'interface exportée de l'implémentation de bibliothèque partagée doit correspondre à votre déclaration d'interface abstraite.

Vous pouvez utiliser un Factory pour effectuer cette recherche, charger la bibliothèque partagée et créer une instance de l'implémentation.

Here Plus d'informations sur les fonctions du système d'exploitation impliquées dans le chargement et la liaison dynamiques du plug-in.


1) Notez que les bibliothèques partagées ne pas besoin d'avoir l'extension .dll ou .so si vous chargez ces activement.

0

Mon conseil serait de fractionner soigneusement le code dépendant de cette DLL. Concevez une interface propre à cette partie de votre projet qui peut être facilement chargée dynamiquement (LoadLibrary), et ne disposez que d'interfaces virtuelles pures (pas d'exportation de DLL) sur les classes avec lesquelles vous interagissez dans la partie principale de votre programme. Idéalement, il a une interface de fonction pure, car ceux-ci sont les plus stables.

Maintenant, que DLL peut dépendre de la DLL tierce comme normale. Votre code principal appelle votre DLL "wrapping" en le chargeant manuellement, et gère l'échec de chargement avec élégance. Ceci est plus facile que d'utiliser une DLL non conçue pour cela, et vous pouvez expérimenter sans installer/désinstaller la DLL tierce en omettant votre DLL de retour à la ligne.