2010-03-29 12 views
13

साझा लाइब्रेरी/डीएलएल से फ़ंक्शन कॉल करने का सबसे आसान और सुरक्षित तरीका क्या है? मुझे लिनक्स पर ऐसा करने में अधिक दिलचस्पी है, लेकिन प्लेटफ़ॉर्म-स्वतंत्र तरीके से बेहतर होगा।साझा लाइब्रेरी से फ़ंक्शन कैसे कॉल करें?

क्या कोई निम्नलिखित उदाहरण बनाने के लिए उदाहरण कोड प्रदान कर सकता है, जहां उपयोगकर्ता ने साझा पुस्तकालय में foo का अपना संस्करण संकलित किया है?

// function prototype, implementation loaded at runtime: 
std::string foo(const std::string); 

int main(int argc, char** argv) { 
    LoadLibrary(argv[1]); // loads library implementing foo 
    std::cout << "Result: " << foo("test"); 
    return 0; 
} 

Btw, मैं कैसे साझा lib (foo.so) संकलित करने के लिए पता है, मैं तो बस रनटाइम पर लोड करने के लिए एक आसान तरीका जानना चाहते हैं।

उत्तर

25

नोट: आप पुस्तकालय कॉल के आसपास सी ++ ऑब्जेक्ट्स (इस मामले में एसटीएल तार) पास कर रहे हैं। कोई मानक C++ ABI इस स्तर पर पर है, इसलिए या तो सी ++ ऑब्जेक्ट्स को पार करने से बचने का प्रयास करें, या सुनिश्चित करें कि आपकी लाइब्रेरी और आपका प्रोग्राम दोनों एक ही कंपाइलर (आदर्श रूप से उसी मशीन पर एक ही कंपाइलर से बचने के लिए बनाया गया है) से बचने के लिए किसी भी सूक्ष्म विन्यास से संबंधित आश्चर्य।)

के लिए मत भूलना अपने निर्यात तरीकों extern "C" अपने पुस्तकालय कोड के अंदर घोषणा करते हैं।

उपरोक्त, यहाँ कहा गया है कुछ को लागू करने कि तुम क्या कहा आप हासिल करना चाहते हैं कोड है:

typedef std::string (*foo_t)(const std::string); 
foo_t foo = NULL; 

... 

# ifdef _WIN32 
    HMODULE hDLL = ::LoadLibrary(szMyLib); 
    if (!hDll) { /*error*/ } 
    foo = (foo_t)::GetProcAddress(hDLL, "foo"); 
# else 
    void *pLib = ::dlopen(szMyLib, RTLD_LAZY); 
    if (!pLib) { /*error*/ } 
    foo = (foo_t)::dlsym(pLib, "foo"); 
# endif 
    if (!foo) { /*error*/ } 

    ... 

    foo("bar"); 

    ... 

# ifdef _WIN32 
    ::FreeLibrary(hDLL); 
# else 
    ::dlclose(pLib); 
# endif 

आप कर सकते हैं सार यह आगे:

#ifdef _WIN32 
#include <windows.h> 
typedef HANDLE my_lib_t; 
#else 
#include <dlfcn.h> 
typedef void* my_lib_t; 
#endif 

my_lib_t MyLoadLib(const char* szMyLib) { 
# ifdef _WIN32 
    return ::LoadLibraryA(szMyLib); 
# else //_WIN32 
    return ::dlopen(szMyLib, RTLD_LAZY); 
# endif //_WIN32 
} 

void MyUnloadLib(my_lib_t hMyLib) { 
# ifdef _WIN32 
    return ::FreeLibrary(hMyLib); 
# else //_WIN32 
    return ::dlclose(hMyLib); 
# endif //_WIN32 
} 

void* MyLoadProc(my_lib_t hMyLib, const char* szMyProc) { 
# ifdef _WIN32 
    return ::GetProcAddress(hMyLib, szMyProc); 
# else //_WIN32 
    return ::dlsym(hMyLib, szMyProc); 
# endif //_WIN32 
} 

typedef std::string (*foo_t)(const std::string); 
typedef int (*bar_t)(int); 
my_lib_t hMyLib = NULL; 
foo_t foo = NULL; 
bar_t bar = NULL; 

... 

    if (!(hMyLib = ::MyLoadLib(szMyLib)) { /*error*/ } 
    if (!(foo = (foo_t)::MyLoadProc(hMyLib, "foo")) { /*error*/ } 
    if (!(bar = (bar_t)::MyLoadProc(hMyLib, "bar")) { /*error*/ } 

    ... 

    foo("bar"); 
    bar(7); 

    ... 

    ::MyUnloadLib(hMyLib); 
+0

आप का उल्लेख किया, तो जो यूनिक्स/लिनक्स पर शामिल करने के लिए हेडर ... –

+0

दूसरे कोड ब्लॉक में किया गया। – vladr

+0

सी ++ में फ़ंक्शन नाम मैंगलिंग के बारे में क्या, क्या जटिल चीजें नहीं होंगी? इसके अलावा, आपने यहां विंडोज़ की गलत वर्तनी की है # #' – sbk

0

लिनक्स पर आपको dlsym का उपयोग करने की आवश्यकता है। पृष्ठ के अंत में एक उदाहरण देखें। विंडो पर: GetProcAddress

1

LoadLibrary DLL लोड करने के लिए एक विंडोज फ़ंक्शन है। आप GetProcAddress के साथ प्रतीक अस्तित्व की जांच कर सकते हैं। लिनक्स/यूनिक्स पर आप dlopen/dlsym चाहते हैं। क्रॉस प्लेटफॉर्म में ऐसा करने के लिए, आप एक समारोह है कि इन पूर्व प्रोसेसर का उपयोग किसी भी विधि का कॉल की तरह कुछ लिख सकता है, इसलिए,:

int loadlibrary(char* library) 
{ 
#ifdef _WIN32 
    /* do windows code */ 

#endif 
#ifdef _LINUX 
    /* do linux code */ 

#endif 
} 

यह एक तरीका है बात इस तरह की प्राप्त करने के लिए है। आप कार्यों के विशिष्ट प्लेटफॉर्म कार्यान्वयन के लिए अपने स्वयं के स्रोत पेड़ में एक अलग शीर्षलेख सहित इसे भी कर सकते हैं। यह शायद एक बेहतर तरीका है। किसी भी मामले में विचार अंतर्निहित एपीआई से सारणी है।