2008-08-26 14 views
23

मेरी सी के अधिकांश/C++ विकास अखंड मॉड्यूल फ़ाइलें और बिल्कुल कोई जो भी कक्षाएं, शामिल है तो आम तौर पर जब मैं मैं सिर्फ मानक __declspec(dllexport) निर्देशों का उपयोग उन्हें निर्यात सुलभ कार्यों के साथ एक DLL बनाने की जरूरत है । फिर उन्हें LoadLibrary() या हेडर और lib फ़ाइल के साथ संकलित समय पर गतिशील रूप से एक्सेस करें।एक DLL से एक सी ++ वर्ग निर्यात

जब आप एक संपूर्ण कक्षा (और इसकी सभी सार्वजनिक विधियों और गुणों) को निर्यात करना चाहते हैं तो आप यह कैसे करते हैं?

क्या रनटाइम पर उस वर्ग को गतिशील रूप से लोड करना संभव है और यदि ऐसा है, तो कैसे?

संकलन समय के लिए आप इसे हेडर और lib के साथ कैसे करेंगे?

+0

एक बहुत अच्छा जवाब लिखा बाद में: http://stackoverflow.com/a/22797419/1995714 –

उत्तर

15

देर से बाध्यकारी के बारे में क्या? लोडिंग के रूप में लोड लोडर() और GetProcAddress() के साथ लोड करने के रूप में? मैं रन टाइम पर लाइब्रेरी लोड करने के लिए सक्षम होने का उपयोग कर रहा हूं और बहुत अच्छा होगा यदि आप यहां कर सकते हैं।

तो DLL लोड करने के दो तरीके हैं। पहला डीएलएल (उदाहरण के लिए, आपका वर्गनाम) से एक या अधिक प्रतीकों का संदर्भ देना है, उचित आयात की आपूर्ति करें। एलआईबी और लिंकर को सब कुछ समझने दें।

दूसरा लोडलोडर के माध्यम से डीएलएल को स्पष्ट रूप से लोड करना है।

या तो दृष्टिकोण सी-स्तरीय फ़ंक्शन निर्यात के लिए ठीक काम करता है। आप या तो लिंकर को इसे संभालने या GetProcAddress को कॉल करने के लिए कॉल कर सकते हैं जैसा आपने नोट किया था।

लेकिन जब कक्षा निर्यात करने की बात आती है, आम तौर पर केवल पहला दृष्टिकोण उपयोग किया जाता है, यानी, डीएलएल से निस्संदेह लिंक करें। इस मामले में डीएलएल एप्लिकेशन स्टार्ट टाइम पर लोड होता है, और यदि डीएलएल नहीं मिल पाता है तो एप्लिकेशन लोड होने में विफल रहता है।

  1. का उपयोग कर वर्ग की वस्तुओं बनाएँ:

    आप एक वर्ग एक DLL में परिभाषित लिंक करना चाहते हैं, और आप चाहते हैं कि DLL गतिशील लोड करने के लिए, कुछ समय कार्यक्रम दीक्षा के बाद, तो आप दो विकल्प हैं एक विशेष कारखाना समारोह, जिसे आंतरिक रूप से (एक छोटे से) असेंबलर को अपने बनाए गए ऑब्जेक्ट्स में नव निर्मित वस्तुओं को "हुक अप" करने के लिए उपयोग करना होगा। यह स्पष्ट रूप से डीएलएल लोड होने के बाद रन-टाइम पर किया जाना है। इस दृष्टिकोण का एक अच्छा स्पष्टीकरण here पाया जा सकता है।

  2. delay-load DLL का उपयोग करें।

सभी चीजों पर विचार किया ... शायद बेहतर सिर्फ अंतर्निहित जोड़ने के साथ जाना है, जिस स्थिति में आप निश्चित रूप से पूर्वप्रक्रमक तकनीक ऊपर दिखाए उपयोग करना चाहते हैं। वास्तव में, यदि आप विजुअल स्टूडियो में एक नया डीएलएल बनाते हैं और "निर्यात प्रतीक" विकल्प चुनते हैं तो ये मैक्रोज़ आपके लिए बनाए जाएंगे।

गुड लक ...

+0

मुझे विश्वास नहीं है कि कक्षाओं में वर्चुअल फ़ंक्शंस होने पर आप आयातित कक्षाओं के साथ विलंब लोड का उपयोग कर सकते हैं, क्योंकि उन वर्गों के vtables डेटा प्रतीकों के रूप में आयात किए जाएंगे। देरी लोड का उपयोग कर डेटा प्रतीक आयात करना preculdes। – RichieHindle

12

मैं आयात या निर्यात के लिए कोड को चिह्नित करने के कुछ मैक्रो का उपयोग

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

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

फिर एक हेडर फाइल में वर्ग की घोषणा:

 
class DLL MyClassToExport { ... } 

फिर पुस्तकालय में #define ISDLL, और USEDLL शामिल करने से पहले उस स्थान पर हेडर फ़ाइल जिसे आप कक्षा का उपयोग करना चाहते हैं।

मैं अगर तुम LoadLibrary

16

के साथ काम कर जब आप DLL और मॉड्यूल है कि DLL का उपयोग करेगा निर्माण के लिए कुछ अलग करने के लिए आवश्यकता हो सकती है पता नहीं है, #define है कि आप करने के लिए उपयोग कर सकते हैं के कुछ प्रकार है एक और अन्य के बीच भेद, तो आप अपने वर्ग हेडर फाइल में कुछ इस तरह कर सकते हैं:

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

संपादित करें: crashmstr मुझे यह करने के लिए पार कर लिया!

+0

घायल वर्ग और कंस्ट्रक्टर (आदि) के नाम सर से कैसे निपटें।? – null

+0

यह बात है - आपको उलझन वाले नामों से निपटने की आवश्यकता नहीं है। '__declspec (dllimport)' संकलक/लिंकर को बताता है कि आप इसे आयात कर रहे हैं और यह सही काम करता है। –

+0

न तो यह या क्रैशमस्ट्रेट की प्रतिक्रिया मूल प्रश्न के साथ कुछ भी करने के लिए है। इसके अलावा नल का सवाल ठीक तरह से संबोधित नहीं किया गया है। – AudioGL

0

आप वर्ग आप निर्यात कर रहे हैं में एक vtable डाल करने के लिए तैयार हैं, तो आप एक समारोह है कि एक अंतरफलक देता है निर्यात और .dll में वर्ग को लागू कर सकते हैं, तो डाल कि .def फ़ाइल में। आपको कुछ घोषणा ट्रिकरी करना पड़ सकता है, लेकिन यह बहुत कठिन नहीं होना चाहिए।

बस COM की तरह। :)

7

हाल ही में मैंने खुद को एक ही प्रश्न पूछा, और मेरे निष्कर्षों को सारांशित किया in a blog post। आप इसे उपयोगी पा सकते हैं।

इसमें डीएलएल से सी ++ कक्षाओं को निर्यात करने के साथ-साथ उन्हें LoadLibrary के साथ गतिशील रूप से लोड करना शामिल है, और इसके आसपास के कुछ मुद्दों पर चर्चा करता है, जैसे मेमोरी प्रबंधन, नाम मैंगलिंग और कॉलिंग कॉन्वेंटेंस।

11

एक DLL से एक सी ++ वर्ग के निर्यात के लिए एक सरल काम कर उदाहरण जोड़ना:

उदाहरण नीचे दिया गया है कि आप केवल कैसे dll और exe एक दूसरे को (आत्म व्याख्यात्मक) बातचीत कर सकते हैं का एक संक्षिप्त अवलोकन देता है, लेकिन इसे और अधिक चीजों की जरूरत है एक उत्पादन कोड में बदलने के लिए जोड़ने के लिए।

पूर्ण नमूना उदाहरण दो भाग

ए एक .dll पुस्तकालय (MyDLL.dll)

बी बनाना एक आवेदन जो .dll पुस्तकालय (एप्लिकेशन) का उपयोग करता है बनाना करने में बांटा गया है।

ए .dll प्रोजेक्ट फ़ाइल (MyDLL.dll):

1. dllHeader.h

#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; 
} 
+0

धन्यवाद। इस जवाब में इंटरफ़ेस क्लास दृष्टिकोण के बिना, मुझे लिंकर त्रुटियों को रोकने के लिए .h फ़ाइल में सबकुछ रखना था। –

+0

फ़ैक्टरी फ़ंक्शन की आवश्यकता क्यों है? अगर कारखाने के काम के बिना, मुझे कैसे करना चाहिए? – Nibnat

संबंधित मुद्दे