Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Problem z użyciem klasy znajdującej się we własnej bibliotece dll.

Ostatnio zmodyfikowano 2011-01-01 17:49
Autor Wiadomość
cyklopek11
Temat założony przez niniejszego użytkownika
Problem z użyciem klasy znajdującej się we własnej bibliotece dll.
» 2011-01-01 14:34:14


Zacząłem bawić się w tworzenie dll-ek na podstawie: http://cpp0x.pl/#/kursy/?id=198


Z importowaniem zwykłych funkcji czy też zmiennych z tak utworzonej dll-ki - nie ma problemu wszystko działa. Natomiast problem jest z użyciem klas. Otóż zgodnie z podanym opisem zrobiłem sobie taki projekt biblioteki dll:

/////////////////////////////////////////////////////////////////////////////////
////////////////// biblioteka Projekt1.dll///////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////kod źródłowy dll.h//////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
C/C++
#ifndef _DLL_H_
#define _DLL_H_

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

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

extern "C"
{
    class DLLIMPORT DllClass
    {
    public:
        DllClass( int );
        virtual ~DllClass( void );
        int wiek;
       
       
    private:
       
    };
}
extern "C"
{
    DllClass * DLLIMPORT CreateObject( int ); //funkcja do tworzenia obiektów
    void DLLIMPORT DestroyObject( DllClass * ); //funkcja do destrukcji obiektów
}




#endif /* _DLL_H_ */

/////////////////////////////////////////////////////////////////////////////////
//////////////////////kod źródłowy  dllmain.cpp /////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////


C/C++
/* Replace "dll.h" with the name of your header */
#include "dll.h"


DllClass::DllClass( int p_wiek )
    : wiek( p_wiek )
{
    std::cout << "Wywolano konstruktor" << std::endl;
}


DllClass::~DllClass()
{
    std::cout << "Wywolano destruktor" << std::endl;
}

DllClass * CreateObject( int a )
{
    return new DllClass( a );
}
void DestroyObject( DllClass * wsk )
{
    delete wsk;
}


BOOL APIENTRY DllMain( HINSTANCE hInst /* Library instance handle. */,
DWORD reason /* Reason this function is being called. */,
LPVOID reserved /* Not used. */ )
{
    switch( reason )
    {
    case DLL_PROCESS_ATTACH:
        break;
       
    case DLL_PROCESS_DETACH:
        break;
       
    case DLL_THREAD_ATTACH:
        break;
       
    case DLL_THREAD_DETACH:
        break;
    }
   
    /* Returns TRUE on success, FALSE on failure */
    return TRUE;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Po kompilacji otrzymuję gotową bibliotekę Projekt1.dll

Teraz kod źródłowy programu wykorzystującego ją:
////////////////////////////////////////////////////////////////////////////
///////////////////// kod źródłowy main.cpp////////////////////////////////
///////////////////////////////////////////////////////////////////////////
C/C++
#include <cstdlib>
#include <iostream>
#include <windows.h>

using namespace std;

class DllClass;

typedef DllClass *( * MYPROC )( int );

MYPROC wskaznik;

int main( int argc, char * argv[] )
{
   
   
   
   
    HINSTANCE hDll;
    hDll = LoadLibrary( "Projekt1.dll" );
   
    if( hDll != NULL )
    {
        cout << "Poprawnie zaladowano biblioteke dll" << endl;
        wskaznik =( MYPROC ) GetProcAddress( hDll, "CreateObject" );
       
       
        if( wskaznik != NULL )
        {
            cout << "znaleziono poszukiwana funkcje CreateObject" << endl;
        }
        else
        {
            cout << " Nie znaleziono funkcji CreateObject w bibliotece dll" << endl;
        }
       
       
    }
    else
    {
        cout << " Nie udalo sie zaladowac biblioteki dll" << endl;
    }
   
   
   
   
    DllClass * wsk = wskaznik( 44 );
    cout << wsk->wiek; // blad: invalid use of undefined type 'struct DllClass'
   
   
   
   
    FreeLibrary( hDll );
    system( "PAUSE" );
    return EXIT_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
Wszystko jest ok do linijki:
C/C++
DllClass * wsk = wskaznik( 44 );
Konsola pokazuje że wywołał się konstruktor a zatem obiekt klasy DllClass został utworzony i mamy do niego dostęp przy pomocy wskaźnika: wsk
Jednak gdy próbuję odczytać publiczny składnik wiek z tego obiektu kompilator wskazuje błąd
Czy ktoś z  Wielkich GURU na tym forum może pokazać gdzie robię błąd???
P-26067
DejaVu
» 2011-01-01 14:39:46
Nie posiadasz ani deklaracji ani implementacji klasy. Zdefiniowałeś tylko nazwę.
P-26068
cyklopek11
Temat założony przez niniejszego użytkownika
» 2011-01-01 14:47:51
Jest przecież w dll-ce. I tak jak autor napisał że nie można dynamicznie wyeksportować całej klasy po to są funkcje dostępowe do tworzenia obiektów tej klasy. A deklaracja w funkcji main() :
C/C++
class DllClass;
to deklaracja zapowiadająca przed załadowaniem dll. A więc pytanie pozostaje nierozwiązane.
P-26071
DejaVu
» 2011-01-01 14:57:08
Powiem tak:
C/C++
class CKlasa;
int main()
{
    CKlasa * pKlasa = new CKlasa; //1. Nie da się utworzyć klasy, której się nie zna
    pKlasa->mojaFunkcja(); //2. Nie da się wywoływać metod klasy, których nie znamy przynajmniej deklaracji
    return 0;
}
Innymi słowy: jeżeli ładujesz DLL'kę dynamicznie to musisz odczytać wskaźnik każdej metody.

A jak chcesz poczytać trochę to:
http://cpp0x.pl/forum/temat/?id=3305
http://cpp0x.pl/forum/temat/?id=520
http://cpp0x.pl/forum/temat/?id=521

P-26073
cyklopek11
Temat założony przez niniejszego użytkownika
» 2011-01-01 15:10:24
Czyli rozumiem że tekst dotyczący korzystania z klasy w dll opisany w kursie:
http://cpp0x.pl/kursy/?id=198
   to WIELKI KIT???
 Myślę, że należałoby to poprawić w tym kursie dla potomnych początkujących.
P-26075
DejaVu
» 2011-01-01 15:17:40
Zainteresowałeś mnie ;p aż siądę teraz to sprawdzić :)

/edit:
A czy dołączyłeś plik *.h do swojego projektu? (mowa tu o pliku nagłówkowym dll'ki, zawierającej deklarację).

/edit2:
Postępując wg kursu:

C/C++
// dll_tester.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include "../dll_dynamic/pliczekDLL.h"

typedef double( * MYPROC )( double );
typedef DllClass *( * FNCREATE )();
typedef void( * FNDESTROY )( DllClass * ptr );

int _tmain( int argc, _TCHAR * argv[] )
{
    HINSTANCE hDll = LoadLibrary( L"D:/projekty/tmp4/dll_dynamic/Debug/dll_dynamic.dll" );
    MYPROC FunkcjaKwadrat =( MYPROC ) GetProcAddress( hDll, "kwadrat" );
    printf( "256 do potęgi 2 jest równe %lu.\n",( long ) FunkcjaKwadrat( 256 ) );
    FNCREATE FnCreateObject =( FNCREATE ) GetProcAddress( hDll, "CreateObject" );
    FNDESTROY FnDestroyObject =( FNDESTROY ) GetProcAddress( hDll, "DestroyObject" );
   
    DllClass * pClass = FnCreateObject();
    pClass->Test(); //Tu jest błąd :)
    FnDestroyObject( pClass );
    return 0;
}

1>------ Build started: Project: dll_tester, Configuration: Debug Win32 ------
1>Linking...
1>dll_tester.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: void __thiscall DllClass::Test(void)" (__imp_?Test@DllClass@@QAEXXZ) referenced in function _wmain
1>D:\Projekty\tmp4\dll_dynamic\Debug\dll_tester.exe : fatal error LNK1120: 1 unresolved externals
1>Build log was saved at "file://d:\Projekty\tmp4\dll_dynamic\dll_tester\Debug\BuildLog.htm"
1>dll_tester - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

/edit3:
Wydaje mi się, że autor kursu miał włączone dependencies i dlatego mu to 'zadziałało' - choć może jakiś oczywisty krok po drodze nie został wyjaśniony i stąd jest też problem :)
P-26078
cyklopek11
Temat założony przez niniejszego użytkownika
» 2011-01-01 16:26:44
Masz rację DejaVu nie dołączyłem *.h mojej dllki.
Ale pojawił się kolejny problem z nazwami metod w mojej klasie. Otóż odczyt zmiennej wiek jest ok. Natomiast dorobiłem sobie do mojej klasy w dllce metodę: pokazWiek():

tak więc w pliku *.h moja klasa wygląda teraz:

C/C++
extern "C"
{
    class DLLIMPORT DllClass
    {
    public:
        DllClass( int );
        virtual ~DllClass( void );
        int wiek;
        void pokazWiek();
       
    private:
       
    };
}

W pliku *.cpp mojej dll-ki oczywiście definicja tej funkcji:

C/C++
void DllClass::pokazWiek()
{
    std::cout << "Wiek wynosi: " << wiek << std::endl;
}


Zbudowałem nową dll, zastąpiłem tą starą do kodu głównego programu w funkcji main dopisałem:

C/C++
wsk->pokazWiek();

kompiluje i linker zgłasza błąd:   [Linker error] undefined reference to `_imp___ZN8DllClass9pokazWiekEv'

A więc jest jakiś błąd z nazwą tej metody, no ale przecież externy "C" są i powinno być ok. Znowu utknąłem.......

Problem z metodą tak jak w Twoim /Edit2
P-26081
DejaVu
» 2011-01-01 16:40:01
Już mi działa :) Metody klasy muszą być wirtualne, czyli:
C/C++
virtual void Test();
P-26082
« 1 » 2
  Strona 1 z 2 Następna strona