سؤال

معظم C/C++ التنمية ينطوي على وحدة متجانسة الملفات على الاطلاق لا توجد فصول دراسية على الإطلاق ، لذلك عادة عندما كنت في حاجة لجعل DLL مع وظائف يمكن الوصول إليها فقط تصديرها باستخدام معيار __declspec(dllexport) التوجيه.ثم الوصول إليها إما عن طريق حيوي LoadLibrary() أو في وقت الترجمة مع رأس الملف lib.

كيف يمكنك أن تفعل هذا عندما تريد تصدير فئة كاملة (وكل انها عامة أساليب وخصائص)?

هل من الممكن لتحميل حيوي تلك الفئة في وقت التشغيل إذا كان الأمر كذلك ، كيف ؟

كيف يمكنك أن تفعل ذلك مع رأس lib عن وقت الترجمة ربط ؟

هل كانت مفيدة؟

المحلول

ماذا عن وقت متأخر-ملزمة ؟ كما في التحميل مع LoadLibrary () ، GetProcAddress() ?أنا استخدامها التمكن لتحميل المكتبة في وقت التشغيل و سيكون أمرا رائعا إذا كنت يمكن أن نفعل ذلك هنا

لذلك هناك طريقتان لتحميل DLL.الأول هو مرجع واحد أو أكثر من الرموز من DLL (الخاص classname على سبيل المثال) ، العرض المناسب الاستيراد .ليب والسماح رابط معرفة كل شيء.

والثاني هو صراحة تحميل DLL عبر LoadLibrary.

أما النهج يعمل بشكل جيد ج-وظيفة على مستوى الصادرات.يمكنك إما السماح رابط التعامل معها أو الاتصال GetProcAddress كما كنت لاحظت.

ولكن عندما يتعلق الأمر تصديرها دروس, عادة فقط النهج الأول هو استخدام أي ضمنا رابط DLL.في هذه الحالة يتم تحميل DLL في تطبيق وقت البدء ، وتطبيق فشل تحميل إذا كان DLL لا يمكن العثور عليها.

إذا كنت تريد أن تصل إلى فئة محددة في DLL و تريد أن يتم تحميل DLL بشكل حيوي في وقت ما بعد البرنامج بدء لديك خياران:

  1. إنشاء كائنات من الدرجة استخدام مصنع خاص وظيفة ، والتي داخليا سوف تضطر إلى استخدام (قليل من) المجمع إلى "ربط" الكائنات التي تم إنشاؤها حديثا إلى الاقتضاء التعويضات.هذا يجب أن يتم في وقت التشغيل بعد DLL تحميل, من الواضح.تفسير جيد هذا النهج يمكن العثور عليها هنا.

  2. استخدام تأخير تحميل DLL.

كل الأمور في الاعتبار...ربما من الأفضل أن تذهب فقط مع ربط ضمني ، وفي هذه الحالة أنت بالتأكيد تريد استخدام المعالج تقنية هو موضح أعلاه.في الواقع, إذا كنت إنشاء DLL جديد في Visual Studio ثم اختر "تصدير الرموز" الخيار وحدات الماكرو هذه بالنسبة لك.

حظا سعيدا...

نصائح أخرى

عند إنشاء DLL و وحدة التي سوف تستخدم DLL يكون نوعا من #define التي يمكنك استخدامها للتمييز بين واحدة وأخرى ، ثم يمكنك أن تفعل شيئا مثل هذا في صفك رأس الملف:

#if defined( BUILD_DLL )
    #define IMPORT_EXPORT __declspec(dllexport)
#else
    #define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
    ...
};

تحرير:crashmstr سبقني إلى ذلك!

يمكنني استخدام بعض وحدات الماكرو إلى علامة رمز استيراد أو تصدير

#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif

#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif

ثم تعلن الطبقة في رأس الملف:

class DLL MyClassToExport { ... }

ثم #define ISDLL في libary ، USEDLL من قبل بما في ذلك رأس الملف في المكان الذي تريد استخدام فئة.

أنا لا أعرف إذا كنت قد تحتاج إلى القيام بأي شيء مختلف عن العمل مع LoadLibrary

إضافة بسيطة على سبيل المثال العمل على تصدير فئة C++ من DLL :

أدناه مثال يعطيك فقط لمحة قصيرة عن كيفية dll و exe يمكن أن تتفاعل مع بعضها البعض (النفس التفسيرية ) لكنه يحتاج المزيد من الأشياء إلى إضافة لتغيير في رمز الإنتاج.

عينة كاملة سبيل المثال يتم تقسيم في الجزء الثاني

A.وخلق .dll مكتبة (MyDLL.dll)

ب.إنشاء تطبيق الذي يستخدم .dll مكتبة (التطبيق).

A..dll ملف المشروع (MyDLL.dll):

1.dllHeader.ح

#ifdef  MYDLL_EXPORTS 
#define DLLCALL __declspec(dllexport)   /* Should be enabled before compiling 
                                           .dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport)  /* Should be enabled in Application side
                                          for using already created .dll*/
#endif

// Interface Class
class ImyMath {
public:
    virtual ~ImyMath() {;}
    virtual int Add(int a, int b) = 0;
    virtual int Subtract(int a, int b) = 0;
};

// Concrete Class
class MyMath: public ImyMath {
public:
    MyMath() {}
    int Add(int a, int b);
    int Subtract(int a, int b);
    int a,b;
};

//  Factory function that will return the new object instance. (Only function
//  should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
    DLLCALL ImyMath* _cdecl CreateMathObject();
};

// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();

2.dllSrc.cpp

#include "dllHeader.h"

// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
    return new MyMath();
}

int MyMath::Add(int a, int b) {
    return a+b;
}

int MyMath::Subtract(int a, int b) {
    return a-b;
}

ب.تطبيق المشروع الذي حمل الرابط الذي تم إنشاؤه بالفعل .ملف dll:

 #include <iostream>
#include <windows.h>
#include "dllHeader.h"

int main()
{
    HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"

    if (hDLL == NULL) {
        std::cout << "Failed to load library.\n";
    }
    else {
        CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
        ImyMath* pMath = pEntryFunction();
        if (pMath) {
            std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
            std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
        }
        FreeLibrary(hDLL);
    }
    std::cin.get();
    return 0;
}

مؤخرا سألت نفسي نفس السؤال بالضبط ، تلخيص النتائج التي توصلت إليها في بلوق وظيفة.قد تجد أنه من المفيد.

ويغطي المصدرة C++ فصول من DLL, وكذلك تحميلها بشكل حيوي مع LoadLibrary, ويناقش بعض القضايا ، مثل إدارة الذاكرة اسم تغيير اسم و الاتفاقيات الدعوة.

إذا كنت على استعداد لوضع vtable في الدرجة أنت المصدرة ، يمكنك تصدير الدالة التي ترجع واجهة وتنفيذ فئة في .dll, ثم وضع ذلك في .ملف def.قد تضطر إلى القيام ببعض إعلان الخداع, ولكن لا ينبغي أن يكون من الصعب جدا.

تماما مثل COM.:)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top