Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12

Discussione: c++ classi e dll

  1. #1

    c++ classi e dll

    Ciao a tutti, è la prima volta che scrivo su questo forum.
    Il mio quesito è questo: qualcuno sa se è pssibile importare una classe da una dll con il c++ tradizionale( non vc++ o c# ecc).
    So come si fa ad importre delle funzioni, ma non riesco a trovare da nessuna parte una spiegazione su come si fa per le classi.
    ciao a tutti e grazie per l'attenzione

  2. #2
    Non mi pare che il C++ standard (senza estensioni) supporti direttamente l'importazione di classi da dll; in VC++ userei __declsec(dllimport).
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Ti ringrazio MItaly per la risposta, Io uso wxDevcpp e penso che esista un sistema di procedere anche con queste librerie (wxwidgets), ma non ho ancora capito come si fa.
    Quello che non mi è chiaro, è soprattuto come si richiama una classe dalla dll in un eseguibile.
    In Visualc++ come si procede?

  4. #4
    devi usare i modificatori, che sono estensioni dello standard c++
    nel tuo caso penso che sia
    __export

    e la usa così,

    class __export A {...};

    Mi chiedo come mai compilando con g++ per linux le classi me le trovi tutte esprotate senza utilizzare alcun modificatore?

    ciao
    sergio

  5. #5
    Originariamente inviato da mondobimbi
    Mi chiedo come mai compilando con g++ per linux le classi me le trovi tutte esprotate senza utilizzare alcun modificatore?
    Chiedo scusa, forse non sono stato molto chiaro.
    Per esportare la classe uso __declspec (dllexport), non ho ancora provato su linux, ma il mio quesito, non è realizzare il la dll, ma piuttosto come importare la classe nell’eseguibile che utilizza la libreria.

  6. #6
    Ciao Berico,

    nel seguente esempio creiamo una dll che contiene una classe chiamata CExportClassFromDll. La classe contiene una funzione membro "public" che ritorna il valore della variabile membro x (inizializzata nel costruttore):

    Dichiarazione della classe nel file header ExportClassFromDll.h:
    codice:
    #ifdef EXPORTCLASSFROMDLL_EXPORTS
    #define EXPORTCLASSFROMDLL_API __declspec(dllexport)
    #else
    #define EXPORTCLASSFROMDLL_API __declspec(dllimport)
    #endif
    
    #ifdef __cplusplus
    extern "C" {           
    #endif
    
    // This class is exported from the ExportClassFromDll.dll
    class EXPORTCLASSFROMDLL_API CExportClassFromDll {
    public:
    	CExportClassFromDll(void);
    	// TODO: add your methods here.
    	int GetValue();
    
    private:
    	int x;
    };
    
    #ifdef __cplusplus
    }
    #endif
    Definizione delle funzioni della classe nel file ExportClassFromDll.cpp:
    codice:
    #define EXPORTCLASSFROMDLL_EXPORTS
    
    #include "ExportClassFromDll.h"
    
    CExportClassFromDll::CExportClassFromDll()
    {
    	x = 21;
    
    	return;
    }
    
    int CExportClassFromDll::GetValue()
    {
    	return x;
    }
    Nel programma client, basta includere il file .lib (nell'esempio ExportClassFromDll.lib ) che il compilatore crea, fra le dipendenze del linker e includere il file ExportClassFromDll.h:

    codice:
    #include <iostream>
    using namespace std;
    
    #include "ExportClassFromDll.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	CExportClassFromDll myCLassFromDll;
    
    	cout << myCLassFromDll.GetValue() << endl;
    
    	return 0;
    }
    Come puoi notare, nel file che definisce la classe nella dll, definiamo la macro EXPORTCLASSFROMDLL_EXPORTS in modo che, compilando la dll, la macro EXPORTCLASSFROMDLL_API si espanda in __declspec(dllexport).
    Nel client invece, includendo semplicemente il file ExportClassFromDll.h senza definire la macro EXPORTCLASSFROMDLL_EXPORTS, la macro EXPORTCLASSFROMDLL_API[/b] si espande in __declspec(dllimport).

    la direttiva extern "C" consente di esportare/importare i nomi senza che vengano decorati dal compilatore CPP. Questo rende la nostra DLL utilizzabile da diversi compilatori (ogni compilatore CPP utilizza infatti una tecnica diversa per decorare i nomi esportati da una dll).

    È la tecnica utilizzata dalla Microsoft per esportare/importare le funzioni della API Win32; basta dare un'occhiata agli header file del SDK.

  7. #7
    Ciao Vincenzo

    I file che mi hai postato, mi sono stati molto utili, anche se Io compilo con g++.
    In ogni caso ho risolto coì:
    // File dll.h
    #ifndef _DLL_H_
    extern "C" {
    #define _DLL_H_

    #if BUILDING_DLL
    # define DLLIMPORT __declspec (dllexport)
    #else /* Not BUILDING_DLL */
    # define DLLIMPORT __declspec (dllimport)
    #endif /* Not BUILDING_DLL */

    #ifdef __cplusplus

    #endif
    class DLLIMPORT DllClass //Esporta ls classe
    {
    public:
    DllClass();
    virtual ~DllClass(void);
    int Somma(int a, int b);

    private:

    };

    }

    #endif /* _DLL_H_ */

    // File dll.h

    #include "dll.h"
    #include <windows.h>

    DllClass:llClass()
    {

    }


    DllClass::~DllClass ()
    {

    }

    int DllClass::Somma(int a, int b)
    {
    return a+b;
    }

    BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
    DWORD reason /* Reason :inizzio di chiamata. */ ,
    LPVOID reserved /* Non usata. */ )
    {
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
    break;

    case DLL_PROCESS_DETACH:
    break;

    case DLL_THREAD_ATTACH:
    break;

    case DLL_THREAD_DETACH:
    break;
    }

    /* Ritorna TRUE se l'esito è positivo, FALSE se fallisce */
    return TRUE;
    }

    // File client.cpp

    include <iostream>
    #include <stdlib.h>
    using namespace std;

    #include "dll.h"

    int main(int argc, char* argv[])
    {
    DllClass myCLassFromDll;

    cout << myCLassFromDll.Somma(5,5) << endl;

    system("pause");
    return 0;
    }
    Sapresti dirmi qualcosa su come si linca una classe in maniera esplicita?
    Ora voglio provare a fare un ulteriore passo in avanti, se possibile.

    Ciao by Berico3

  8. #8
    Per realizzare il linking dinamico, abbiamo bisogno di dichiarare le funzioni membro della classe come virtual.
    La DLL deve inoltre implementare una funzione (nell'esempio sotto la funzione è GetClasse) che crea l'oggetto e ne restituisce il puntatore.
    Nel programma client dichiariamo un puntatore alla classe e lo inizializziamo richiamando la funzione nella DLL.

    Header file della DLL:
    codice:
    #ifdef EXPORTCLASSFROMDLL_EXPORTS
    #define EXPORTCLASSFROMDLL_API __declspec(dllexport)
    #else
    #define EXPORTCLASSFROMDLL_API __declspec(dllimport)
    #endif
    
    #ifdef __cplusplus
    extern "C" {           
    #endif
    
    // This class is exported from the ExportClassFromDll.dll
    class EXPORTCLASSFROMDLL_API CExportClassFromDll {
    public:
    	CExportClassFromDll(void);
    	// TODO: add your methods here.
    	virtual int GetValue();
    
    private:
    	int x;
    };
    
    EXPORTCLASSFROMDLL_API CExportClassFromDll * GetClasse();
    
    #ifdef __cplusplus
    }
    #endif
    Implementazione della DLL:
    codice:
    #define EXPORTCLASSFROMDLL_EXPORTS
    
    #include "ExportClassFromDll.h"
    
    // This is the constructor of a class that has been exported.
    // see ExportClassFromDll.h for the class definition
    CExportClassFromDll::CExportClassFromDll()
    {
    	x = 21;
    
    	return;
    }
    
    int CExportClassFromDll::GetValue()
    {
    	return x;
    }
    
    EXPORTCLASSFROMDLL_API CExportClassFromDll * GetClasse()
    {
    	return new CExportClassFromDll();
    }
    Nel programma client utilizziamo le funzioni per il linking dinamico LoadLibrary e GetProcAddress:

    codice:
    #include <windows.h>
    
    #include <iostream>
    using namespace std;
    
    #include "ExportClassFromDll.h"
    
    typedef CExportClassFromDll* (*GETCLASSE_POINTER)();
    
    int main(void)
    {
    	GETCLASSE_POINTER pfnGetClasse = NULL;
    
    	CExportClassFromDll * pmyCLassFromDll = NULL;
    
    	// Carichiamo dinamicamente la DLL
    	HINSTANCE    hMyDll = ::LoadLibrary("ExportClassFromDll.dll");
    
    	if(hMyDll != NULL)
    	{
    		// Otteniamo il puntatore alla funzione GetClasse
    		pfnGetClasse = (GETCLASSE_POINTER)::GetProcAddress(hMyDll, "GetClasse");
    
    		// Se il puntatore è nullo, rilasciamo la DLL e usciamo
    		if(pfnGetClasse == 0)   
    		{
    			::FreeLibrary(hMyDll);
    			printf("Errore nel puntatore alla funzione GetClasse\n");
    			return -1;
    		}
    
    		// Se invece il puntatore è valido, richiamiamo la funzione facendoci
    		// restituire il puntatore alla classe
    		pmyCLassFromDll = pfnGetClasse();
    		if ( !pmyCLassFromDll ) // Se GetClasse restituisce un puntatore nullo, usciamo
    		{
    			::FreeLibrary(hMyDll);
    			printf("Errore nel puntatore alla classe\n");
    			return -1;
    		}
    
    		// se invece il puntatore alla classe è valido, lo utilizziamo
    		cout << pmyCLassFromDll->GetValue() << endl;
    
    		// liberiamo la memoria
    		delete pmyCLassFromDll;
       
    		// Rilasciamo la DLL
    		::FreeLibrary(hMyDll);
    	}
    	else
    	{
    		printf("Errore nel caricamento della DLL ExportClassFromDll.dll\n");
    	}
    
    	return 0;
    }

  9. #9
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    E alla fine abbiamo riscoperto il COM

    Solo un appunto. Una regola (aurea?) dovuta al tipo di linking del crt che si fa (statico/dinamico o debug/release) consiglia che chi alloca, dealloca.

    In altre parole, se l'allocazione della classe avviene nella DLL, anche la deallocazione deve avvenire nella DLL. Quindi un:
    codice:
        // liberiamo la memoria
        delete pmyCLassFromDll;
    non deve avvenire nel programma chiamante ma nella DLL stessa, pena un comportamento che varia dal funziona, al crash.

  10. #10
    Originariamente inviato da shodan
    E alla fine abbiamo riscoperto il COM

    Solo un appunto. Una regola (aurea?) dovuta al tipo di linking del crt che si fa (statico/dinamico o debug/release) consiglia che chi alloca, dealloca.

    In altre parole, se l'allocazione della classe avviene nella DLL, anche la deallocazione deve avvenire nella DLL. Quindi un:
    codice:
        // liberiamo la memoria
        delete pmyCLassFromDll;
    non deve avvenire nel programma chiamante ma nella DLL stessa, pena un comportamento che varia dal funziona, al crash.
    Ciao Shodan,

    hai perfettamente ragione. A beneficio degli utenti meno esperti, riporto il codice per deallocare il puntatore nella DLL. Ho aggiunto, nella DLL, la funzione FreeClasse che il client richiama al posto dell'operatore delete.

    Dichiarazione della classe nella dll:
    codice:
    #ifdef EXPORTCLASSFROMDLL_EXPORTS
    #define EXPORTCLASSFROMDLL_API __declspec(dllexport)
    #else
    #define EXPORTCLASSFROMDLL_API __declspec(dllimport)
    #endif
    
    #ifdef __cplusplus
    extern "C" {           
    #endif
    
    // This class is exported from the ExportClassFromDll.dll
    class EXPORTCLASSFROMDLL_API CExportClassFromDll {
    public:
    	CExportClassFromDll(void);
    	// TODO: add your methods here.
    	virtual int GetValue();
    
    private:
    	int x;
    };
    
    EXPORTCLASSFROMDLL_API CExportClassFromDll * GetClasse();
    EXPORTCLASSFROMDLL_API void FreeClasse(CExportClassFromDll *pMyClass);
    
    #ifdef __cplusplus
    }
    #endif
    Implementazione della classe:
    codice:
    #define EXPORTCLASSFROMDLL_EXPORTS
    
    #include "ExportClassFromDll.h"
    
    // This is the constructor of a class that has been exported.
    // see ExportClassFromDll.h for the class definition
    CExportClassFromDll::CExportClassFromDll()
    {
    	x = 21;
    
    	return;
    }
    
    int CExportClassFromDll::GetValue()
    {
    	return x;
    }
    
    EXPORTCLASSFROMDLL_API CExportClassFromDll * GetClasse()
    {
    	return new CExportClassFromDll();
    }
    
    EXPORTCLASSFROMDLL_API void FreeClasse(CExportClassFromDll *pMyClass)
    {
    	delete pMyClass;
    }
    Programma client:
    codice:
    #include <windows.h>
    
    #include <iostream>
    using namespace std;
    
    #include "ExportClassFromDll.h"
    
    typedef CExportClassFromDll* (*GETCLASSE_POINTER)();
    typedef void (*FREECLASSE_POINTER)(CExportClassFromDll*);
    
    int main(void)
    {
    	GETCLASSE_POINTER pfnGetClasse = NULL;
    	FREECLASSE_POINTER pfnFreeClasse = NULL;
    
    	CExportClassFromDll * pmyCLassFromDll = NULL;
    
    	// Carichiamo dinamicamente la DLL
    	HINSTANCE    hMyDll = ::LoadLibrary("ExportClassFromDll.dll");
    
    	if(hMyDll != NULL)
    	{
    		// Otteniamo il puntatore alla funzione GetClasse
    		pfnGetClasse = (GETCLASSE_POINTER)::GetProcAddress(hMyDll, "GetClasse");
    
    		// Se il puntatore è nullo, rilasciamo la DLL e usciamo
    		if(pfnGetClasse == 0)   
    		{
    			::FreeLibrary(hMyDll);
    			printf("Errore nel puntatore alla funzione GetClasse\n");
    			return -1;
    		}
    
    		// Se invece il puntatore è valido, richiamiamo la funzione facendoci
    		// restituire il puntatore alla classe
    		pmyCLassFromDll = pfnGetClasse();
    		if ( !pmyCLassFromDll ) // Se GetClasse restituisce un puntatore nullo, usciamo
    		{
    			::FreeLibrary(hMyDll);
    			printf("Errore nel puntatore alla classe\n");
    			return -1;
    		}
    
    		// se invece il puntatore alla classe è valido, lo utilizziamo
    		cout << pmyCLassFromDll->GetValue() << endl;
    
    		// Otteniamo il puntatore alla funzione FreeClasse
    		pfnFreeClasse = (FREECLASSE_POINTER)::GetProcAddress(hMyDll, "FreeClasse");
    
    		// Se il puntatore è nullo, rilasciamo la DLL e usciamo
    		if(pfnFreeClasse == 0)   
    		{
    			::FreeLibrary(hMyDll);
    			printf("Errore nel puntatore alla funzione FreeClasse\n");
    			return -1;
    		}
    
    		// liberiamo la memoria
    		pfnFreeClasse(pmyCLassFromDll);
       
    		// Rilasciamo la DLL
    		::FreeLibrary(hMyDll);
    	}
    	else
    	{
    		printf("Errore nel caricamento della DLL ExportClassFromDll.dll\n");
    	}
    
    	return 0;
    }
    Per Berico: Il codice sopra l'ho compilato col visual c++ e la piattaforma è windows. Per G++ in ambiente Linux/Unix il procedimento dovrebbe essere uguale ma dovresti vedere come caricare una dll in modo dinamico e ottenere i puntatori alle funzioni(dovrebbero esistere delle funzioni equivalenti a LoadLibrary e GetProcAddress).

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.