none
problema con dll RRS feed

  • Domanda

  • Salve a tutti,

    ho la necessità di condividere una struttura dati (un singleton) tra applicazione (.exe) e 

    plugin (.dll). Fino ad adesso avevo risolto questo problema utilizzando una dll e mettendo dentro questa l'allocazione del singleton; sia l'applicazione che i plugin accedevano alla dll per accedere al singleton condiviso. Tutto ha funzionato fino a che passando dal vs2005 al vs2008 ha iniziato a venire fuori un errore.

    Compilando la dll con il vs2008 io vedo il seguente warning 

    \globalData.cpp(31) : warning C4190: 'getApplicationPath' has C-linkage specified, but returns UDT 'std::basic_string<_Elem,_Traits,_Ax>' which is incompatible with C.

    wrapperGlobalData.h è un wrapper che con le librerie qt chiama le funzioni della dll, i cui files sono globaldata.cpp

    e globaldata.h. Ho allegato il codice.

    /********** wrapperGlobalData.h ****************/
    
    
    class wrapperGlobalData
    {
    public:
    	static int getGlobalNumberFrames()
    	{
    		QLibrary lib("singleton");
    		typedef int (*ptr2)();
    		ptr2 function2 = (ptr2) lib.resolve("getGlobalNumberFrames");
    		return function2();
    
    	}
    	static void setGlobalNumberFrames(int n)
    	{
    		QLibrary lib("singleton");
    		typedef void (*ptr)(int);
    		ptr function = (ptr) lib.resolve("setGlobalNumberFrames");
    		function(n);
    	}
    
    	static int getGlobalCurrentFrame()
    	{
    		QLibrary lib("singleton");
    		typedef int (*ptr2)();
    		ptr2 function2 = (ptr2) lib.resolve("getGlobalCurrentFrame");
    		return function2();
    
    	}
    
    	static void setGlobalCurrentFrame(int n)
    	{
    		QLibrary lib("singleton");
    		typedef void (*ptr)(int);
    		ptr function = (ptr) lib.resolve("setGlobalCurrentFrame");
    		function(n);
    	}
    
    
        static std::string getApplicationPath()
        {
            QLibrary lib("singleton");
            typedef std::string (*ptr2)();
            ptr2 function2 = (ptr2) lib.resolve("getApplicationPath");
            return function2();
    
        }
    
        static void setApplicationPath(std::string path)
        {
            QLibrary lib("singleton");
            typedef void (*ptr)(std::string);
            ptr function = (ptr) lib.resolve("setApplicationPath");
            function(path);
        }
    
        static void logMsg(logger::LEVEL level, const char * format, ...)
        {
    #ifdef _DENTALCAD_PRO_MACRO_
            char buffer[msgSize];
            va_list args;
            va_start (args, format);
            vsprintf (buffer,format, args);
            va_end (args);
    
            QLibrary lib("singleton");
            typedef  void (*ptr)(logger::LEVEL level, const char * msg, const char * method);
            ptr function = (ptr) lib.resolve("logMsg");
            function(level,buffer,NULL);
    #endif
    	}
    
        static void enableLog(bool enabled)
        {
            QLibrary lib("singleton");
            typedef  void (*ptr)(bool);
            ptr function = (ptr) lib.resolve("enableLog");
            function(enabled);
        }
    
    	static bool isLogEnabled()
    	{
    		QLibrary lib("singleton");
    		typedef  bool (*ptr)();
    		ptr function = (ptr) lib.resolve("isLoggingEnabled");
    		return function();
    	}
    };
    
    /*class LogStringConverter
    {
    public:
        /// qstring to const char *
        static const char * _QC(const QString & str)
        {
            qDebug() << str.toLocal8Bit().data();
    		return str.toLocal8Bit().data();
        }
        /// stl to const char *
        static const char * _SC(const std::string & str)
        {
            return str.c_str();
        }
    };
    
    /*************************************************/
    /****************** DLL FILES ********************/
    /*************************************************/
    
    
    /**************** global.h **************************/
    
    
    class globalData {
    private:
            /// static instance
            static globalData* instance_ptr;
            globalData() { };
    public:
            ~globalData() {};
            static globalData* get_instance();
            bool method() { return true; };
            /// numero di frame correnti
            int nframes;
            /// frame corrente
            int current_frame;
            /// application path
            std::string applicationPath;
            /// logger
            logger log;
    };
     
    
    /**************** globaldata.cpp ********************/
    
    extern "C" __declspec(dllexport) void setGlobalNumberFrames(int n)
    {
    	globalData::get_instance()->nframes=n;
    }
    
    extern "C" __declspec(dllexport) int getGlobalNumberFrames()
    {
    	return globalData::get_instance()->nframes;
    }
    
    extern "C" __declspec(dllexport) void setGlobalCurrentFrame(int n)
    {
    	globalData::get_instance()->current_frame=n;
    }
    
    extern "C" __declspec(dllexport) int getGlobalCurrentFrame()
    {
    	return globalData::get_instance()->current_frame;
    }
    
    extern "C" __declspec(dllexport) void setApplicationPath(std::string _applicationPath)
    {
        globalData::get_instance()->applicationPath=_applicationPath;
    }
    
    extern "C" __declspec(dllexport) std::string getApplicationPath()
    {
        return globalData::get_instance()->applicationPath;
    }
    
    extern "C" __declspec(dllexport) void logMsg(logger::LEVEL level, const char * msg, const char * method)
    {
        globalData::get_instance()->log.get_instance()->sendMessage(level,msg,method);
    }
    
    extern "C" __declspec(dllexport) void enableLog(bool enabled)
    {
        if (enabled) globalData::get_instance()->log.get_instance()->enableLogging();
        else globalData::get_instance()->log.get_instance()->disableLogging();
    }
    
    
    
    
    
    // initialize pointer
    globalData* globalData::instance_ptr = NULL;
    
    
    globalData* globalData::get_instance() {
        if (instance_ptr == NULL) {
                instance_ptr = new globalData;
        }
        return instance_ptr;
    }

                      

    A runtime viene lanciata un eccezione: "windows has triggered a breakpoint.This may be due to a corruption of the heap, which indicates a bug in DentalCad.exe or any of the DLLs it has loaded. E questa è la call stack che vedo.

    ntdll.dll!77360574()
    [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
    ntdll.dll!77322aba()
    ntdll.dll!772f1d17()
    > msvcr80d.dll!_unlock(int locknum=9238160)  Line 376 C
    0001e1af()
    KernelBase.dll!76605614()
    msvcr90d.dll!_CrtIsValidHeapPointer(const void * pUserData=0x0288ec88)  Line 2103 C++
    msvcr90d.dll!_free_dbg_nolock(void * pUserData=0x0288ec88, int nBlockUse=1)  Line 1317 + 0x9 bytes C++
    msvcr90d.dll!_free_dbg(void * pUserData=0x0288ec88, int nBlockUse=1)  Line 1258 + 0xd bytes C++
    msvcr90d.dll!operator delete(void * pUserData=0x0288ec88)  Line 54 + 0x10 bytes C++
    msvcp90d.dll!std::allocator<unsigned short>::deallocate(unsigned short * _Ptr=0x0288ec88, unsigned int __formal=64)  Line 146 + 0x9 bytes C++
    msvcp90d.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(bool _Built=true, unsigned int _Newsize=0)  Line 2168 C++
    msvcp90d.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> >()  Line 917 C++
    DentalCad.exe!wrapperGlobalData::setApplicationPath(std::basic_string<char,std::char_traits<char>,std::allocator<char> > path="d:/DentalCadRemakeFinalPorting/DentalCad/DentalCadDebug")  Line 64 + 0x1d bytes C++
    DentalCad.exe!main(int argc=1, char * * argv=0x028868a0)  Line 43 + 0x23 bytes C++
    DentalCad.exe!WinMain(HINSTANCE__ * instance=0x00210000, HINSTANCE__ * prevInstance=0x00000000, char * __formal=0x006c6bc8, int cmdShow=1)  Line 131 + 0x12 bytes C++
    DentalCad.exe!__tmainCRTStartup()  Line 578 + 0x35 bytes C
    DentalCad.exe!WinMainCRTStartup()  Line 403 C

    Come posso risolvere?

    martedì 17 dicembre 2013 16:22

Tutte le risposte

  • Salve a tutti,

    ho la necessità di condividere una struttura dati (un singleton) tra applicazione (.exe) e 

    plugin (.dll). Fino ad adesso avevo risolto questo problema utilizzando una dll e mettendo dentro questa l'allocazione del singleton; sia l'applicazione che i plugin accedevano alla dll per accedere al singleton condiviso. Tutto ha funzionato fino a che passando dal vs2005 al vs2008 ha iniziato a venire fuori un errore.

    Compilando la dll con il vs2008 io vedo il seguente warning 

    \globalData.cpp(31) : warning C4190: 'getApplicationPath' has C-linkage specified, but returns UDT 'std::basic_string<_Elem,_Traits,_Ax>' which is incompatible with C.

    wrapperGlobalData.h è un wrapper che con le librerie qt chiama le funzioni della dll, i cui files sono globaldata.cpp

    e globaldata.h. Ho allegato il codice.

    /********** wrapperGlobalData.h ****************/
    
    
    class wrapperGlobalData
    {
    public:
    	static int getGlobalNumberFrames()
    	{
    		QLibrary lib("singleton");
    		typedef int (*ptr2)();
    		ptr2 function2 = (ptr2) lib.resolve("getGlobalNumberFrames");
    		return function2();
    
    	}
    	static void setGlobalNumberFrames(int n)
    	{
    		QLibrary lib("singleton");
    		typedef void (*ptr)(int);
    		ptr function = (ptr) lib.resolve("setGlobalNumberFrames");
    		function(n);
    	}
    
    	static int getGlobalCurrentFrame()
    	{
    		QLibrary lib("singleton");
    		typedef int (*ptr2)();
    		ptr2 function2 = (ptr2) lib.resolve("getGlobalCurrentFrame");
    		return function2();
    
    	}
    
    	static void setGlobalCurrentFrame(int n)
    	{
    		QLibrary lib("singleton");
    		typedef void (*ptr)(int);
    		ptr function = (ptr) lib.resolve("setGlobalCurrentFrame");
    		function(n);
    	}
    
    
        static std::string getApplicationPath()
        {
            QLibrary lib("singleton");
            typedef std::string (*ptr2)();
            ptr2 function2 = (ptr2) lib.resolve("getApplicationPath");
            return function2();
    
        }
    
        static void setApplicationPath(std::string path)
        {
            QLibrary lib("singleton");
            typedef void (*ptr)(std::string);
            ptr function = (ptr) lib.resolve("setApplicationPath");
            function(path);
        }
    
        static void logMsg(logger::LEVEL level, const char * format, ...)
        {
    #ifdef _DENTALCAD_PRO_MACRO_
            char buffer[msgSize];
            va_list args;
            va_start (args, format);
            vsprintf (buffer,format, args);
            va_end (args);
    
            QLibrary lib("singleton");
            typedef  void (*ptr)(logger::LEVEL level, const char * msg, const char * method);
            ptr function = (ptr) lib.resolve("logMsg");
            function(level,buffer,NULL);
    #endif
    	}
    
        static void enableLog(bool enabled)
        {
            QLibrary lib("singleton");
            typedef  void (*ptr)(bool);
            ptr function = (ptr) lib.resolve("enableLog");
            function(enabled);
        }
    
    	static bool isLogEnabled()
    	{
    		QLibrary lib("singleton");
    		typedef  bool (*ptr)();
    		ptr function = (ptr) lib.resolve("isLoggingEnabled");
    		return function();
    	}
    };
    
    /*class LogStringConverter
    {
    public:
        /// qstring to const char *
        static const char * _QC(const QString & str)
        {
            qDebug() << str.toLocal8Bit().data();
    		return str.toLocal8Bit().data();
        }
        /// stl to const char *
        static const char * _SC(const std::string & str)
        {
            return str.c_str();
        }
    };
    
    /*************************************************/
    /****************** DLL FILES ********************/
    /*************************************************/
    
    
    /**************** global.h **************************/
    
    
    class globalData {
    private:
            /// static instance
            static globalData* instance_ptr;
            globalData() { };
    public:
            ~globalData() {};
            static globalData* get_instance();
            bool method() { return true; };
            /// numero di frame correnti
            int nframes;
            /// frame corrente
            int current_frame;
            /// application path
            std::string applicationPath;
            /// logger
            logger log;
    };
     
    
    /**************** globaldata.cpp ********************/
    
    extern "C" __declspec(dllexport) void setGlobalNumberFrames(int n)
    {
    	globalData::get_instance()->nframes=n;
    }
    
    extern "C" __declspec(dllexport) int getGlobalNumberFrames()
    {
    	return globalData::get_instance()->nframes;
    }
    
    extern "C" __declspec(dllexport) void setGlobalCurrentFrame(int n)
    {
    	globalData::get_instance()->current_frame=n;
    }
    
    extern "C" __declspec(dllexport) int getGlobalCurrentFrame()
    {
    	return globalData::get_instance()->current_frame;
    }
    
    extern "C" __declspec(dllexport) void setApplicationPath(std::string _applicationPath)
    {
        globalData::get_instance()->applicationPath=_applicationPath;
    }
    
    extern "C" __declspec(dllexport) std::string getApplicationPath()
    {
        return globalData::get_instance()->applicationPath;
    }
    
    extern "C" __declspec(dllexport) void logMsg(logger::LEVEL level, const char * msg, const char * method)
    {
        globalData::get_instance()->log.get_instance()->sendMessage(level,msg,method);
    }
    
    extern "C" __declspec(dllexport) void enableLog(bool enabled)
    {
        if (enabled) globalData::get_instance()->log.get_instance()->enableLogging();
        else globalData::get_instance()->log.get_instance()->disableLogging();
    }
    
    
    
    
    
    // initialize pointer
    globalData* globalData::instance_ptr = NULL;
    
    
    globalData* globalData::get_instance() {
        if (instance_ptr == NULL) {
                instance_ptr = new globalData;
        }
        return instance_ptr;
    }

                      

    A runtime viene lanciata un eccezione: "windows has triggered a breakpoint.This may be due to a corruption of the heap, which indicates a bug in DentalCad.exe or any of the DLLs it has loaded. E questa è la call stack che vedo.

    ntdll.dll!77360574()
    [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
    ntdll.dll!77322aba()
    ntdll.dll!772f1d17()
    > msvcr80d.dll!_unlock(int locknum=9238160)  Line 376 C
    0001e1af()
    KernelBase.dll!76605614()
    msvcr90d.dll!_CrtIsValidHeapPointer(const void * pUserData=0x0288ec88)  Line 2103 C++
    msvcr90d.dll!_free_dbg_nolock(void * pUserData=0x0288ec88, int nBlockUse=1)  Line 1317 + 0x9 bytes C++
    msvcr90d.dll!_free_dbg(void * pUserData=0x0288ec88, int nBlockUse=1)  Line 1258 + 0xd bytes C++
    msvcr90d.dll!operator delete(void * pUserData=0x0288ec88)  Line 54 + 0x10 bytes C++
    msvcp90d.dll!std::allocator<unsigned short>::deallocate(unsigned short * _Ptr=0x0288ec88, unsigned int __formal=64)  Line 146 + 0x9 bytes C++
    msvcp90d.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(bool _Built=true, unsigned int _Newsize=0)  Line 2168 C++
    msvcp90d.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> >()  Line 917 C++
    DentalCad.exe!wrapperGlobalData::setApplicationPath(std::basic_string<char,std::char_traits<char>,std::allocator<char> > path="d:/DentalCadRemakeFinalPorting/DentalCad/DentalCadDebug")  Line 64 + 0x1d bytes C++
    DentalCad.exe!main(int argc=1, char * * argv=0x028868a0)  Line 43 + 0x23 bytes C++
    DentalCad.exe!WinMain(HINSTANCE__ * instance=0x00210000, HINSTANCE__ * prevInstance=0x00000000, char * __formal=0x006c6bc8, int cmdShow=1)  Line 131 + 0x12 bytes C++
    DentalCad.exe!__tmainCRTStartup()  Line 578 + 0x35 bytes C
    DentalCad.exe!WinMainCRTStartup()  Line 403 C

    Come posso risolvere?

    Quando linki due programmi scritti con compilatori diversi o versioni diverse dello stesso compilatore hai il problema della compatibilità binaria del codice.

    I tipi di dati scambiati tra i due mondi dovrebbero essere POD (plain old data), cioe' strutture compatibili con il linguaggio C. Questo perchè l'ABI del C è piuttosto standard. La std::string non è C, è C++ e quindi va evitata in queste situazioni.

    1)

    Il problema sembra dartelo questa funzione

    void setApplicationPath(std::string path)

    dovresti sostituirla con ad esempio

    void setApplicationPath(char *path)

    all'interno puoi ricreare una std:string

    string spath(path);

    2)

    Anche questa

    std::string getApplicationPath()

    è un problema

    dovresti fare così

    char *getApplicationPath()

    MA ANCHE ASSICURARTI CHE LA STRINGA RESTITUITA NON VENGA DEALLOCATA ALLA FINE DELLA CHIAMATA A getApplicationPath!!! (ma in un secondo momento)

    martedì 17 dicembre 2013 22:32