Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 2 сентября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

ПРОГРАММИРОВАНИЕ НА C и С++



Слушай, дружище, зачем так мучиться с этим языком С++, ты ведь не Билл Гейтс. Возьми тот же Python и программируй, он кроссплатформенный, под Windows тоже работает. Я сам давно заметил: то что на Си пишешь в страницу кода, на питоне решается в одну-две строки. При том, питон намного проще, я его сам недавно изучил по видеокурсу вот этому. Кстати, автор отлично там объясняет. Буквально день-два и уже будешь писать на нём, чего не скажешь про сложный С++.

Советы по использованию Dynamic Link Libraries (DLLs) в MFC

Автор: xicoloko.

Этот документ поможет начинающим программистам получить некоторые знания по разработке приложений для Windows. Когда я создаю новый проект, то наиболее изменяемые куски программы стараюсь поместить в DLL. Это даёт мне возможность изменять уже откомпилированную программу.

Чтобы сделать это грамотно, дам Вам несколько советов. Многи могут спросить, а почему бы просто не использовать технологию COM ?. Ответ очевиден, конечно же COM является наиболее частым выбором в таких ситуациях. Однако, DLL это одна из живучих альтернатив для решения таких задач. Я постараюсь объяснить использование технологии DLL в рамках приложения под MFC.

Одна из главных проблемм использования DLL (особенно в MFC) кроется в отладочной и релизной версиях. Эти версии не совместимы. Дело в том, что проблемма возникает при запуске отладочной версии Вашего приложения с DLL релизной версии. В таком случае Microsoft советует давать разные имена DLL (для релизной и отладочной версий). Итак релизная версия DLL остаётся в проекте с прежним именем, а отладочная версия должна выглядеть примерно так [Project Name]D.DLL. После этого Вы можете скопировать оба варианта DLL-ки в системную директорию, и быть счастливы :).

Вот несколько шагов по созданию такого приложения (имя проекта AAA):

  1. Скопируйте AAA.def в AAAD.def и измените все AAA на AAAD;
  2. В Project/Settings, установите Win32 Debug
  3. В закладке Link измените Output file name на AAAD.DLL;
  4. Изначальны Вы можете наблюдать на этой закладке:
    /def:".\AAA.def" /out:"Debug/AAAD.DLL"
    Измените на:
    /def:".\AAAD.def" /out:"Debug/AAAD.DLL"

 

Теперь отладочная версия создаст файлы AAAD.lib и AAAD.DLL. Когда я создаю DLL, я создаю для него заголовок (include header) (думаю, что все так делают), который называю DLL header. Этот заголовок содержит объявления всех экспортируемых классов. Для большей эффективности я включаю "linking stuff" в него, теперь, чтобы использовать DLL вам не нужно добавлять lib файл в Project Settings. Мой header выглядит примерно так:

 

#ifndef DEF_MUDASDASDASDASDAS
 
 #define DEF_MUDASDASDASDASDAS
 
 
 
 #ifdef _DEBUG
 
 #pragma comment(lib, AAAD.lib)
 
 #else
 
 #pragma comment(lib, AAA.lib)
 
 #endif
 
 
 
 //... сдесь начинаются объявления классов
 
 
 
 #endif //MUDASDASDASDASDAS

Программирование с изменениями

Чтобы использовать класс, содержащийся в DLL, достаточно объявить в Вашем проекте следующее:

class AFX_EXT_CLASS CFoo
 
 {
 
  //...
 
 }

В приложении, использующем этот класс, необходимо включить хедер DLL. Проблемма: Вам всё время прийдётся включать переменные-члены или методы в экспортированный класс, а для этого необходимо изменять DLL header, а это значит, что прийдётся перекомпилировать все модули, использующие DLL. Для новых методов я не знаю способа преодоления этой проблеммы, но для новых переменных такой способ есть.

Вместо того, чтобы объявлять члены класса непосредственно в теле класса, вы создаёте класс с указателем на включаемый класс:

class CFooImpl;
 
 class CFoo
 
 {
 
 protected:
 
  CFooImpl* m_pThis;
 
 };

Теперь класс CFooImpl не требует объявления, чтобы использовать его из DLL. Функции-члены класса CFoo выглядят примерно так:

class CFooImpl
 
 {
 
 public:
 
  CString m_sName;
 
 };
 
 
 
 CFoo::CFoo()
 
 {
 
  m_pThis = new CFooImpl;
 
 
 
  m_pThis->m_sName = _T("Unknown");
 
 }
 
 
 
 CFoo::~CFoo()
 
 {
 
  delete m_pThis;
 
 }

Другой способ - это использовать специальных структур Windows API. Вам нужно объявить метод, который использует в качестве входных и выходных параметров LPVOID. Данные указатели - это адреса экземпляров структур. Этот приём определяет первого члена рассмотренной структуры - DWORD, который является размером.

 
 
 typedef struct tagCHANGEABLE
 
 {
 
  DWORD dwSize;
 
  long lBytes;
 
 }CHANGEABLE, *LPCHANGEABLE;
 
 
 
 BOOL CFoo::Method(LPVOID lpIn)
 
 {
 
  LPCHANGEABLE lpChangeable = (LPCHANGEABLE)lpIn;
 
 
 
  if (lpChangeable->dwSize == sizeof(CHANGEABLE))
 
  {
 
   //...
 
   return TRUE;
 
  }
 
 
 
  return FALSE;
 
 }
 
 

Используем его:

CFoo myFoo;
 
 
 
 CHANGEABLE changeable;
 
 memset(&changeable, 0, sizeof(changeable));
 
 
 
 changeable.dwSize = sizeof(changeable);
 
 
 
 myFoo.Method(&changeable);

DLL загружается при необходимости

Иногда возникает ситуация, когда Вам нужно вызвать диалог или инициализировать класс. Тогда Вы решаете поместить его в DLL, но Вы не хотите, чтобы он загружался во время выполнения приложения. Вы хотите загрузить DLL только при необходимости (COM). Это тип DLL я называю Dynamic DLL (масло маслянное “Dynamic Dynamic link libraries”). Итак, Вы объявляете экспортируемую функцию как:

__declspec( DLLexport )
 
 void MyExportedFunc(DWORD dw)
 
 {
 
  //...
 
 }

Необходимо включить эту функцию в файлы  .def (debug и release). Отладочный def-файл будет выглядеть примерно так:

; AAAD.def : Объявление параметров модуля для DLL.
 
 
 
 LIBRARY      "AAAD"
 
 
 
 DESCRIPTION  'AAAD Windows Dynamic Link Library'
 
 
 
 EXPORTS
 
  MyExportedFunc @1
 
  ; Explicit exports can go here

Теперь, чтобы использовать эту функцию, необходимо загрузить библиотеку, найдите точку входа в функцию и вызовите её.

typedef void (*MYFUNC)(DWORD);
 
 
 
 #ifdef _DEBUG
 
  HINSTANCE hDLL = AfxLoadLibrary("AAADLLD");
 
 #else
 
  HINSTANCE hDLL = AfxLoadLibrary("AAADLL");
 
 #endif
 
 
 
 if (hDLL)
 
 {
 
  FARPROC pnProc = GetProcAddress(hDLL, "MyExportedFunc");
 
  MYFUNC pnMyfunc = (MYFUNC)pnProc;
 
 
 
  pnMyfunc(0);
 
 
 
  FreeLibrary(hDLL);
 
 }

Не забудьте, что для того, чтобы показать диалог, Вам необходимо позаботиться о необходимых ресурсах (AfxSetResource..). Такой подход позволяет создать копии класса. В определении класса должны использоваться только виртуальные функции (чтобы избежать "unresolved external symbol"). Это примерно также как в COM.

Объявление класса будет выглядеть так:

class CFoo
 
 {
 
 public:
 
  virtual void Initialize (CString sName) = 0;
 
 };

Включаем этот "interface" в другой класс, не видимый через заголовочный файл DLL.

class CFooImp  : public CFoo
 
 {
 
 public:
 
  CFooImp();
 
  virtual ~CFooImp();
 
 
 
  void Initialize (CString sName)
 
  {
 
   m_sName  = sName;
 
  }
 
 
 
 protected:
 
  CString m_sName;
 
 };

Чтобы создать образец класса (интерфейс) вам необходимо создать экспортированную функцию.

__declspec(DLLexport)
 
 
 
 CFoo* CreateFoo(DWORD dwVersion)
 
 {
 
  if (dwVersion == CURRENT_VERSION)
 
   return new CFooImp;
 
 
 
  return NULL;
 
 }

Приложение инициализирует класс следующим образом:

typedef CFoo* (*MYFUNC)(DWORD);
 
 
 
 #ifdef _DEBUG
 
  HINSTANCE hDLL = AfxLoadLibrary("AAADLLD");
 
 #else
 
  HINSTANCE hDLL = AfxLoadLibrary("AAADLL");
 
 #endif
 
 
 
 if (hDLL)
 
 {
 
  FARPROC pnProc = GetProcAddress(hDLL, " CreateFoo");
 
  MYFUNC pnMyfunc = (MYFUNC)pnProc;
 
 
 
  CFoo* pFoo = pnMyfunc(0);
 
 
 
  pFoo->Initialize(_T("Hi"));
 
 
 
  delete pFoo;
 
 
 
  FreeLibrary(hDLL);
 
 }

Не забудьте, что Вы не можете освободить библиотеку до тех пор пока Вы не удалите объект класса CFoo.



<< ВЕРНУТЬСЯ В ПОДРАЗДЕЛ

<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ




Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS