Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > экспорт класса из dll


Автор: TaNK 22.9.2010, 13:48
Уважаемые, прочитал уйму статей в интернете, но все равно не пойму как реализовать сабж.

main.h
Код

#ifndef MAIN_H
#define MAIN_H

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

using namespace std;

#ifndef CLASS_DLL
#define dll_class _declspec(dllexport)
#else
#define dll_class _declspec(dllimport)
#endif

class dll_class Show
{
  public:
           Show();
           int Print();
  private:
           int i;

};

#endif


main.cpp
Код

#include "main.h"

int Show::Print()
{
  return (i = 100);
}


//===========================================================================

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}

запустил code::blocks 10.05 и получили dll

не пойму как вызвать из основной проги с помощью LoadLibrary и обраться к функции класса Print();

Автор: borisbn 22.9.2010, 14:14
Раз ты экспортируешь класс, то ты должен его импортировать, а LoadLibrary здесь не нужна.
Просто включаешь в основной программе твой main.h, подключаешь lib-файл, полученный при сборке dll-ки и просто используешь класс. типа того:

Код

#include "main.h"
#pragma comment( lib, "main.lib" )
Show showFromDll;
int x = showFromDll.Print();


Автор: TaNK 22.9.2010, 14:16
borisbn - у меня code::blocks не  создает *.lib а есть что то типа 
libDLL.dll.a
libDLL.dll.def

Автор: borisbn 22.9.2010, 14:23
А ещё лучше создать интерфейс, наследоваться от него ( реализовать имплементацию ), создать и экспортировать всего одну функцию, создающую имплементацию.
Код

iFace.h:

#pragma pack ( push, 4 )
class IFace {
public:
    virtual __stdcall print() = 0;
    virtual IFace() {}
};
#pragma pack ( pop )

typedef IFace* ( __cdecl *create_t)();

iFaceImpl.h:

#include "iFace.h"
class IFaceImpl : public IFace {
public:
    IFaceImpl(){}
    virtual __stdcall print() { return ( i = 100 ); }
    virtual IFaceImpl() {}
private:
    int i;
};

iFaceImpl.cpp:

#include "iFaceImpl.h"

extern "C" __declspec(dllexport) IFace * __cdecl create() {
return new IFaceImpl();
}

А в основной программе:
Код

#include "iFace.h"
HMODULE module = LoadLibrary( "main.dll" );
create_t create = (create_t)GetProcAddress( module, "create" );
IFace * face = create();
int x = face->print();
delete face;

Автор: TaNK 22.9.2010, 14:27
 virtual IFace() {} - ругается что конструктор не может быть виртуальным...убрать определение virtual?

Автор: borisbn 22.9.2010, 14:32
TaNK, пардон. это должен был быть виртуальный деструктор
Код

virtual ~IFace() {}

и то же самое с 
Код

virtual ~IFaceImpl() {}

стучи в жаббер, чтобы не захламлять форум

Автор: TaNK 22.9.2010, 14:57
Я запутался....можно ли увидеть приведенный пример уже готовй со всеми файлами....а т я не пойму что к чему должно бытьпривязано...огромное спасибо

Автор: TaNK 22.9.2010, 15:15
прошу прощения все получилось....был невнимателен!

Добавлено через 3 минуты и 41 секунду
main.h
Код

#ifndef MAIN_H
#define MAIN_H

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

using namespace std;

#pragma pack ( push, 4 )
class IFace {
public:
    virtual int __stdcall print() = 0;
    virtual ~IFace() {}
};
#pragma pack ( pop )

typedef IFace* ( __cdecl *create_t)();
#endif


main1.h
Код

#ifndef MAIN1_H_INCLUDED
#define MAIN1_H_INCLUDED

#include "main.h"

class IFaceImpl : public IFace {
public:
    IFaceImpl(){}
    virtual int __stdcall print() { return ( i = 100 ); }
    virtual ~IFaceImpl() {}
private:
    int i;
};

#endif // MAIN1_H_INCLUDED


main.cpp
Код

#include "main1.h"

extern "C" __declspec(dllexport) IFace * __cdecl create()
{
   return new IFaceImpl();
}

BOOL WINAPI DllMain(HINSTANCE hinst, unsigned long reason, void*)
{

    switch( reason )
   {
        case DLL_PROCESS_ATTACH:
           // Initialize once for each new process.
           // Return FALSE to fail DLL load.
           break;

      case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

      case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

      case DLL_PROCESS_DETACH:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}


запускаем main.cpp - получчаем dll

в основной проге 
Код

#include <iostream>
#include "main.h"


using namespace std;



int main()
{


   HMODULE module = LoadLibrary( "dll.dll" );
create_t create = (create_t)GetProcAddress( module, "create" );
IFace * face = create();
int x = face->print();
cout << x;
delete face;

    return 0;
}



borisbn + 1


Автор: xvr 22.9.2010, 15:57
Поздравляю. До повторного изобретения COM'а остался один шаг (GUID + QueryInterface)
 smile 

Автор: borisbn 22.9.2010, 16:06
Цитата(xvr @  22.9.2010,  15:57 Найти цитируемый пост)
До повторного изобретения COM'а остался один шаг (GUID + QueryInterface)

 smile 
правда эта конструкция кроссплатформенная, а подсмотрел её я действительно из COM'а, выкинув GUID, QueryInterface и обращение к реестру

Автор: TaNK 23.9.2010, 07:54
Уважаемые, а скажите а зачем делать класс абстрактным? 
и еще пример
class Date(){};

class subdate: public Date
{
   //
}

мне нужен тип Date, но обратиться я не могу т.к. в  Date объвлена чистая виртуальная функуия, как быть в этом случае, какой тип использовать в классе subdate  

Автор: GremlinProg 23.9.2010, 09:05

M
GremlinProg
Тема перемещена из раздела C/C++: Системное программирование и WinAPI

Автор: xvr 23.9.2010, 09:16
Цитата(TaNK @  23.9.2010,  07:54 Найти цитируемый пост)
Уважаемые, а скажите а зачем делать класс абстрактным? 
Что бы наследники не забыли их определить
Отдельно стоит случай абстрактного класса, состоящего ИСКЛЮЧИТЕЛЬНО из чисто виртуальных функций (пример interface'а). Такой класс можно безопасно экспортировать куда угодно, т.к. де факто в нем кроме таблицы виртуальных функций (причем оригинальная VTBL этого класса НИКОГДА не будет использоваться) вообще ничего нет. Никаких функций. Т.е. линкеру не никогда придется линковаться с его функциями (т.к. их нет)

Цитата(TaNK @  23.9.2010,  07:54 Найти цитируемый пост)
мне нужен тип Date, но обратиться я не могу т.к. в  Date объвлена чистая виртуальная функуия, как быть в этом случае, какой тип использовать в классе subdate
Тип тот же (Date), а нужно описать те самые чисто виртуальные функции из Date у себя (в subdate)


Автор: TaNK 23.9.2010, 16:49
Уважаемые, подскажите пожайлуста почему возникает ошибка

main.h 
Код

#ifndef __MAIN_H__
#define __MAIN_H__

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

using namespace std;

//Абстрактный класс, т.к. имеется чисто виртуальная фукнция IsBigDiff
class ABS_date
{
  public:
          enum datesign{dd = 1, mm, yy};
          virtual ~ABS_date(){}; // Конструктор виртуальный
          virtual bool __stdcall IsBigDiff(ABS_date&, int) = 0;     //чисто виртаульная функция
          virtual ABS_date& GetDate() = 0;                //-//-//
         // virtual void __stdcall Viewing() const = 0;               //-//-//
          virtual int datediff(datesign, ABS_date&, ABS_date&) = 0; //-//-//
          virtual bool operator== (const ABS_date&) const = 0;      //-//-//
          virtual bool operator> (const ABS_date&) const = 0;       //-//-//
          virtual bool operator< (const ABS_date&) const = 0;       //-//-//
          virtual bool IsLeapYear(int) = 0;                         //-//-//
          virtual int& MaxDayOfMonth(int&, int&, int&) = 0;         //-//-//
};

typedef ABS_date* (__cdecl *cr_IsBigDiff) ();

//Наследуем от абстрактного класса
class Date : public ABS_date
{
  public:

           enum Month{jan = 1,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec,unk};
           Date(int dd = 0, Month mm = Month(0), int year = 0);


           //Деструктор
           virtual ~Date(){};
           //Функции доступа к датам
           int   f_day()const;
           Month f_month()const;
           int   f_year()const;

           //Класс исключений
           /*class Bad_date
           {
            public:
                    Bad_date(short);
                    string& viewing_ex();
            private:
                    string error;
           };*/

           //Функция - модификатор даты
           Date& dateadd (datesign, int, Date&);

           //Проверка высокосного года
           virtual bool IsLeapYear(int);
           //Максимальный день в месяц
           virtual int& MaxDayOfMonth(int&, int&, int&);
           //Перегрузка == для сравнения двух дат
           virtual bool operator== (const Date&) const;
           //Перегрузка > для сравнения двух дат
           virtual bool operator> (const Date&) const;
           //Перегрузка < для сравнения двух дат
           virtual bool operator< (const Date&) const;
           //Функция - разница между двумя датами
           virtual int datediff(datesign, Date&, Date&);
           // Текущая дата
           virtual Date& GetDate();
          // virtual void  __stdcall Viewing()const;
           //True or False если даты сильно отличаются в днях (по умолчанию больше чем на 5 дней)
           virtual bool __stdcall IsBigDiff(ABS_date&, int);

  private:
           int day, year;
           Month month;
           //static ABS_date* default_date; // дата по умолчанию

};

//===============================================================================
//Перегрузка == для сравнения двух дат
bool Date::operator== (const Date& p_date) const
{
  return (this->day == p_date.day && this->month == p_date.month && this->year == p_date.year);
}

//Перегрузка >= для сравнения двух дат
bool Date::operator> (const Date& p_date) const
{
  if   (this->year > p_date.year)
       return true;
  else

  if   (this->year < p_date.year)
       return false;

  if   (this->month > p_date.month)
       return true;
  else

  if   (this->month < p_date.month)
       return false;

  if   (this->day > p_date.day)
       return true;
  else

  if   (this->day < p_date.day)
       return false;
}

//Перегрузка <= для сравнения двух дат
bool Date::operator< (const Date& p_date) const
{
  if   (this->year < p_date.year)
       return true;
  else

  if   (this->year > p_date.year)
       return false;

  if   (this->month < p_date.month)
       return true;
  else

  if   (this->month > p_date.month)
       return false;

  if   (this->day < p_date.day)
       return true;
  else

  if   (this->day > p_date.day)
       return false;
}

//Проверка на високосный год
bool Date::IsLeapYear(int yy)
{
    if ((yy%4 == 0 && yy%100 != 0) || yy%400 == 0)
       return true;
    else
        return false;
}

//Максимальный день в месяце
int& Date::MaxDayOfMonth(int& ref_temp_mm, int& ref_max_date, int& ref_year)
{
   switch (ref_temp_mm)
   {
     case 2:
            ref_max_date = 28 + Date::IsLeapYear(ref_year);
     break;

     case 4: case 6: case 9: case 11: ref_max_date = 30;
     break;

     case 1: case 3: case 5: case 7: case 8: case 10: case 12: ref_max_date = 31;
     break;
   }

   return ref_max_date;

}

/*
void  Date::Viewing()const
{
    cout << day << "-" << month <<  "-" << year;
}*/

//Текущая дата
Date& Date::GetDate()
{
  time_t t;
  tm* tm_t;
  time(&t);

  tm_t = localtime(&t);

  year  = (tm_t->tm_year + 1900);
  month = Month(tm_t->tm_mon + 1);
  day   = tm_t->tm_mday;

  return *this;
}
//===========================__stdcall===========================================
bool Date::IsBigDiff(ABS_date& date_isbig, int value = 5)
{

   ABS_date* g_date;
    g_date->GetDate(); // Дата по умолчанию

    if   (g_date->datediff(ABS_date::dd, date_isbig, *g_date) <= value)
         return false;
    else
         return true;

    delete g_date; // Очищаем выделенную память под Дату по умолчанию
}

//Функция - разница между двумя датами
int Date::datediff(datesign sign, Date& date_first, Date& date_second)
{
    if (date_first == date_second) // Даты идентичны
       return 0;
    else

    switch(sign)
   {
       case yy: //Год между двумя датами
                {
                  int yy_f = date_first.year, yy_s = date_second.year;
                  return (yy_s - yy_f);

                } break;

       case mm: // Месяц между двумя датами
                {
                  int mm_f = date_first.month,  yy_f = date_first.year,
                      mm_s = date_second.month, yy_s = date_second.year,
                      count_mm = 0;

                  if (date_second > date_first) // Вторая дата больше первой
                  {

                    while (yy_s != yy_f || mm_s != mm_f)
                    {
                       // Одинаковые года
                       if (yy_s == yy_f)
                           {
                             count_mm += mm_s - mm_f;
                             mm_s     -= mm_s - mm_f;
                           }
                       else
                            {
                              // Когда года у дат разные
                              yy_s--;
                              count_mm += mm_s;
                              mm_s = 12;
                            }
                    }
                    return count_mm;
                  }
                  else
                      if (date_second < date_first) // Вторая дата меньше первой
                      {
                        while (yy_f != yy_s || mm_f != mm_s)
                        {
                          // Одинаковые года
                          if (yy_f == yy_s)
                             {
                               count_mm += mm_f - mm_s;
                               mm_f     -= mm_f - mm_s;
                             }
                         else
                              {
                                // Когда года у дат разные
                                yy_f--;
                                count_mm += mm_f;
                                mm_f = 12;
                              }
                        }
                        return -count_mm;
                    }

                } break;

       case dd: // День между двумя датами
               {
                  int day_f = date_first.day,  mm_f = date_first.month,  yy_f = date_first.year,
                      day_s = date_second.day, mm_s = date_second.month, yy_s = date_second.year,
                      count_dd = 0;

                  if (date_second > date_first) // Вторая дата больше первой
                  {
                     while (yy_s != yy_f || mm_s != mm_f || day_s != day_f) // Пока даты неравны
                     {
                        // Месяцы и года у дат одинаковые
                        if (mm_s == mm_f && yy_s == yy_f)
                        {
                            count_dd += day_s - day_f;
                            day_s    -= day_s - day_f;

                        }
                        else
                        {
                            count_dd += day_s;
                            mm_s--;

                            if (0 == mm_s)
                            {
                               mm_s = 12;
                               yy_s--;
                            }
                            //Находим Max день в месяце
                            Date::MaxDayOfMonth(mm_s, day_s,yy_s);
                        }
                     }
                 }
                 else
                 if (date_second < date_first) // Вторая дата меньше первой
                 {
                     while (yy_f != yy_s || mm_f != mm_s || day_f != day_s) // Пока даты неравны
                     {
                        // Месяцы и года у дат одинаковые
                        if (mm_f == mm_s && yy_f == yy_s)
                        {
                            count_dd = (day_s - day_f) - count_dd;
                            day_f   -= day_f - day_s;

                        }
                        else
                        {
                            count_dd += day_f;
                            mm_f--;

                            if (0 == mm_f)
                            {
                               mm_f = 12;
                               yy_f--;
                            }
                            //Находим Max день в месяце
                            Date::MaxDayOfMonth(mm_f, day_f,yy_f);
                        }
                     }
                 }

               return count_dd;

               }break;

     //default: throw Bad_date(4);
   }
}

//================================================================================

#endif // __MAIN_H__


кажется в абстрактном классе портит вот это объявление
Код

enum datesign{dd = 1, mm, yy};


экспортироваться будет 
Код

virtual bool __stdcall IsBigDiff(ABS_date&, int) = 0;


все остальное запихнул  в АБС так как IsBigDiff ипользует в той или иной мере

main.cpp
Код

#include "main.h"


extern "C" __declspec(dllexport) ABS_date * __cdecl IsBigDiff()
{
   return new Date();
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
   return TRUE; // succesful
}


ругает меня компил на строку 

 return new Date();
и пишет  cannot allocate an object of abstract type 'Date'   because the following virtual functions are pure within 'Date': 
virtual int ABS_date::datediff(ABS_date::datesign, ABS_date&, ABS_date&)| и пречисляет все мои вирт функции, как исправить...подскажите..пожайлуста

Автор: xvr 23.9.2010, 19:35
Компилятор совершенно правильно ругается, разницу между
Код

int datediff(datesign, ABS_date&, ABS_date&)
и
int datediff(datesign, Date&, Date&);
видите? Подсказка - типы параметров должны совпадать
Код

bool Date::IsBigDiff(ABS_date& date_isbig, int value = 5)
{
   ABS_date* g_date;
    g_date->GetDate(); // Дата по умолчанию
    if   (g_date->datediff(ABS_date::dd, date_isbig, *g_date) <= value)
         return false;
    else
         return true;
    delete g_date; // Очищаем выделенную память под Дату по умолчанию
}
А где создание объекта для g_date ?

Автор: mes 24.9.2010, 08:36
Цитата(xvr @  23.9.2010,  18:35 Найти цитируемый пост)
А где создание объекта для g_date ?

а также удаление после return..

Автор: TaNK 24.9.2010, 09:33
xvr  - функцию datediff объявил 
так 
Код

virtual int datediff(datesign, ABS_date&, ABS_date&);

но стал ругаться на то что класс ABS_date не имет членов year, month и day;


А где создание объекта для g_date ?
вот этот момент не понял совсем, поясните пожайлуста!

Автор: mes 24.9.2010, 11:19
Цитата(TaNK @  24.9.2010,  08:33 Найти цитируемый пост)
вот этот момент не понял совсем, поясните пожайлуста! 

советую почитать с чем едят указатели  ) а в частности про new
а в примере вместо указателя можно использовать сам объект, тогда и delеte не нужен будет..
smile

Автор: TaNK 24.9.2010, 11:28
Вы имеете ввиду вот это
Код

ABS_date* ddate = new Date;
//.....
delete ddate


Добавлено через 7 минут и 37 секунд
mes - помогите дописать и осмыслить datediff, если Вам не сложно!

Автор: TaNK 24.9.2010, 15:26
буду всем признателен, если подскажите как мне правильно передавать в подкласс название абстрактного класса
для дальнейшого использования.
Всем спасибо за ответы.

Автор: mes 24.9.2010, 16:04
Цитата(TaNK @  24.9.2010,  10:28 Найти цитируемый пост)
омогите дописать и осмыслить datediff, 

так указанная проблема была с ф-цией IsBigDiff ?
или опечатались ? тогда в чем проблема ? как убрать делете ? 
откажитесь от указателя, чтоб не портить логику
 или пользуйте std::auto_ptr<> - он сам удалит когда выйдете из функции..

код  и тему внимательно не смотрел, но возникли два вопроса :
1. действительно ли Вам нужен абстрактный класс ? 
2. если действительно нужно, то все поголовно далеко не обязательно делать виртуальным..
так в частности операторы сравнения легко разгружаются одной функцией.

например так :

Код

class AbsDate
{
 ... 
     virtual int CompareTo  (const Date& rhs) const  =0;

     bool operator <  (..) const  { return CompareTo (..)  <  0; }
     bool operator >  (..) const  { return CompareTo (..)  >  0; }
     bool operator == (..) const  { return CompareTo (..)  == 0; }  
     bool operator != (..) const  { return CompareTo (..)  != 0; }   
};


Автор: xvr 24.9.2010, 18:04
Цитата(TaNK @ 24.9.2010,  09:33)
xvr  - функцию datediff объявил 
так 
Код

virtual int datediff(datesign, ABS_date&, ABS_date&);

но стал ругаться на то что класс ABS_date не имет членов year, month и day;

Либо сделайте абстрактые методы для доступа к этим членам, либо приведите внутри класса параметры к типу Date& (в последнем случае нужно быть уверенным, что ничего кроме Date туда придти не сможет)
Цитата

А где создание объекта для g_date ?
вот этот момент не понял совсем, поясните пожайлуста!
Уже вроде объяснили

Автор: TaNK 28.9.2010, 12:36
то что Вы мне изтолковали я переварил и осознал, а теперь возник следующий....вопрос...отдаю кому то dll без изходников, как человек сможет ее юзать , как должен получить адресс экспортируемой функции 
Код

cr_IsBigDiff ILY = (cr_IsBigDiff)GetProcAddress(module, "IsBigDiff");
//код который я использую


cr_IsBigDiff - объявлено в header'e
Спасибо за ответы

Автор: borisbn 28.9.2010, 12:47
Цитата(TaNK @  28.9.2010,  12:36 Найти цитируемый пост)
как человек сможет ее юзать , как должен получить адресс экспортируемой функции 


Цитата(TaNK @  28.9.2010,  12:36 Найти цитируемый пост)
cr_IsBigDiff ILY = (cr_IsBigDiff)GetProcAddress(module, "IsBigDiff");


сам же и ответил smile

а если серьёзно, то ты должен отдать человеку h-ник, в котором описан cr_IsBigDiff. Другими словами, человек, использующий твою dll-ку ( а именно функцию из неё ) должен знать как она должна вызываться, с какими параметрами и что возвращает.

Автор: TaNK 28.9.2010, 13:33
т.е. если нет исходников dll, то ничего не получится я правильно понял?

Автор: borisbn 28.9.2010, 16:46
Цитата(borisbn @  28.9.2010,  12:47 Найти цитируемый пост)
ты должен отдать человеку h-ник


h-ник, а не исходники.

Итого:
1. для подключения dll-ки в другой проект её исходники не нужны.
2. для подключения dll-ки в другой проект с ней ( как минимум ) должен поставляться h-ник, в котором должно быть описание экспортируемой функции ( функций )
3. для динамического связывания п. 2 хватит. если хочешь связывать программу и dll-ку статически, то нужна ещё библиотека импорта ( lib-ина )

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)