Создание программ с использованием объектно-ориентированного подхода - это практика программирования, в основу которой положены те же принципы, что используются при любом техническом проектировании. И это существенно облегчает разработку, снижает затраты, уменьшает число ошибок, сокращает сроки и является приемом борьбы со сложностью в больших проектах.
DLL ( - динамически загружаемые библиотеки. Существуют два типа DLL
DLL MFC - библиотеки ( MFC regular DLL )DLL MFC - библиотеки ( MFC extension DLL )Динамически подключаемая библиотека - это специального вида исполняемый файл с расширением .dll, используемый для хранения классов, функций и ресурсов отдельно от исполняемого файла.
Существует и другой способ хранения скомпилированного кода отдельно от исходного кода приложения - в библиотечных файлах с расширением .lib. Этот код включается в приложение линковщиком в процессе создания приложения. Такой процесс называется статическим связыванием. Код библиотеки хранится в исполняемом файле приложения. И если библиотеку использует несколько приложений, экземпляр кода будет включен в исполнимый файл каждого приложения.
Использование DLL обеспечивает динамическое связывание, когда код библиотеки загружается в память и присоединяется к приложению при его запуске на выполнение. Приложение, запущенное на выполнение, называется процессом. Если одновременно выполняются несколько процессов, то каждый процесс может загружать из DLL и присоединять к себе нужную функцию или даже все процессы одну и ту же функцию одновременно.
Применение DLL позволяет реконструировать и сопровождать функцию (или класс) только в одном экземпляре и все внесенные в нее изменения будут немедленно учтены любыми использующими ее приложениями без предварительной их перекомпиляции. Можно считать, что DLL является источником кода, а все упакованные в нее функции и классы - экспортируемыми функциями и классами.
Создание программ с использованием объектно-ориентированного подхода - это практика программирования, в основу которой положены те же принципы, что используются при любом техническом проектировании
DLL можно разместить функции, к которым обращаются многие приложения, то уменьшаются размеры исполняемых файлов приложений на этапе компиляцииDLL не изменяется, то ее можно заменить более новой, причем сами приложения обновлять не придетсяDLL ее можно использовать в приложениях, написанных на других языках программирования для Windows Динамически загружаемые библиотеки - это файлы с заранее откомпилированными кодами функций или классов, которые могут использоваться другими приложениями на этапе выполнения. Функция или класс добавляются в специальную таблицу, являющуюся неотъемлемой частью DLL. В таблице указывается местоположение всех функций и классов, содержащихся в DLL, что обеспечивает быстрый их поиск и вызов исполняемым внешним приложением при его загрузке в память.
Приложение может вызывать код из DLL двумя способами:
LIB -файлом, в котором содержатся фиктивные модули программного кода (заглушки). При запуске приложения фиктивный псевдокод замещается реальным кодом из DLL Заглушка - это псевдофункция, у которой имя и список аргументов совпадают с именем и списком аргументов реальной функции. Внутри функции-заглушки имеется незначительное количество кода, вызывающего реальную функцию из DLL, причем реальной функции при вызове передаются все те аргументы, которые были переданы заглушке. В этом смысле функции DLL можно рассматривать как часть кода приложения, а не как отдельный файл.
Второй способ значительно проще. Библиотечный LIB -файл при компиляции DLL создается автоматически. Для его создания не приходится предпринимать каких-либо особых действий. При использовании LIB -файлов все используемые в приложении DLL загружаются в память в момент запуска приложения и если некоторые из них отсутствуют, то Windows автоматически предупреждает об этом и приложение не выполняется.
Когда используется первый способ, разработчику приложения необходимо самостоятельно организовывать загрузку DLL в память и обрабатывать все ошибочные ситуации при отсутствии нужных DLL.
DLL создаются с помощью оболочки Visual Studio специальным мастером DLL Wizard.
- это динамически загружаемые библиотеки, расширяющие библиотеку базовых классов MFC. Такой тип DLL легче всего создавать и кодировать. Чтобы сделать класс экспортируемым DLL, нужно при его объявлении указать макрос AFX_EXT_CLASS примерно так
class AFX_EXT_CLASS MyClass // Объявление класса
{
..................
};
Далее в приложении, использующем класс, достаточно будет включить этот макрос, и при запуске приложения будет импортирование из DLL нужный класс.
Одним из недостатков является то, что их нельзя использовать в программах, написанных на других языках программирования или в программах C++, компиляторы которых не поддерживают MFC. Но компиляторы фирмы Borland и Symantec поддерживают .
MFC regular DLL - это обычные динамически загружаемые библиотеки. Этот тип DLL поддерживает стандартные функции, а не классы, поэтому планировать их приходится несколько тщательнее, чем . Внутри самой DLL классы можно использовать, но вызов кода внешним приложением нужно организовать через функцию.
Для обеспечения возможности экспорта функции библиотекой следует эту функцию объявить экспортируемой по такому синтаксису
extern "C" тип_возвращаемого_значения PASCAL EXPORT объявление_функции
Необходимо включить все эти дополнительные слова как в заголовочный файл прототипа функции, так и в исходный код ее реализации.
extern "C" объявляет, что это вызов стандартной функции C, поэтому корректировщик имен C++ не должен корректировать имя функцииPASCAL сообщает компилятору, что все параметры функции передаются в порядке, принятом в языке PASCAL, т.е. параметры в стеке размещаются в порядке, обратном обычномуEXPORT информирует компилятор о том, что эта функция будет экспортироваться динамически загружаемой библиотекой во внешние приложенияДля создания DLL применяется специальный тип проекта оболочки Visual Studio. Чтобы сделать функции экспортируемыми DLL, следует добавить их имена в файл определений DEF.lib этого проекта. Файл DEF.lib представляет собой библиотечный (т.е. с расширением LIB ) файл заглушек и таблицу экспортируемых функций, содержащихся в DLL. В него включается имя DLL, ее краткое описание и имена всех экспортируемых библиотекой функций. Файл DEF проекта DLL автоматически создается мастером "DLL Wizard" и имеет определенный формат. Формат файла изменять нельзя, в него можно только добавлять имена экспортируемых функций.
Примерный вид файла определений DEF.lib
LIBRARY "mydll" DESCRIPTION 'mydll Windows Dynamic Link Library' EXPORTS ; Explicit exports can go here MyFun1 MyFun2 MyFun3
Если в MFC regular DLL используются классы из MFC, то первой строчкой тела всех экспортируемых функций должен быть вызов макроса AFX_MANAGE_STATE. Это диктуется необходимостью обеспечить многопоточную поддержку в функциях, благодаря которой можно вызывать функции класса одновременно несколькими потоками процесса. Макрос AFX_MANAGE_STATE имеет единственный аргумент - указатель на структуру AFX_MANAGE_STATE, который можно получить в результате вызова функции AfxGetStaticModuleState(). Типичная экспортируемая функция, использующая библиотеку MFC, имеет следующий вид
extern "C" void PASCAL EXPORT MyFun(список_аргументов)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Далее идет обычное тело функции
.....................
}
При проектировании функций для DLL нужно соблюдать правила:
Создадим одну библиотеку DLL, расширяющую MFC, в которую включим два класса. Работа будет опираться на результаты работы Lab10. Первым пусть будет класс MyLine из этой работы. Второй класс будет создавать случайные рисунки на поверхности рисования. В него войдет массив объектов MyLine, который он будет создавать и заполнять данными во время рисования.
В этом классе должна находиться функция для сохранения и восстановления рисунков, а также для удаления уже не нужных рисунков, чтобы можно было создавать новые. Кроме того, класс должен знать размеры поверхности рисования, так как ему придется генерировать рисунки в границах поверхности рисования.
Создайте новый проект, указав, что это проект
Установите настройку мастера
Щелкните по кнопке Finish, после чего заготовка проекта мастером будет создана
Скопируйте файлы MyLine.h и MyLine.cpp из папки проекта Lab10 - DrawSDI (VS.NET 2003) в папку текущего проекта ModArtDll
Присоедините файлы MyLine.h и MyLine.cpp к текущему проекту. Для этого выполните в меню оболочки команду Project/Add Existing Item (Добавить существующий элемент)После добавления обоих файлов к проекту класс MyLine появится во вкладке Class View.
Теперь основа проекта готова, пришло время заняться наполнением модуля. Класс MyLine представляет собой вполне удобный механизм для повторного использования некоторых созданных ранее функций и параметров. Имеющиеся в этом модуле функции можно использовать для генерации случайных рисунков.
Для реализации нужных нам функциональных возможностей необходимо создать новый класс. Для этого выполните следующие шаги:
Добавьте новый класс к создаваемому проекту. Для этого во вкладке Class View выделите верхний узел

и через контекстное меню выберите команду Add/Add Class (Добавить класс). Выберите шаблон Generic C++ Class

Присвойте новому классу имя MyModArt, базовому классу - имя CObject, а в качестве модификатора доступа укажите public

Щелкните по кнопке Finish
После создания нового класса необходимо добавить в него две переменные: m_oaLines и m_rDrawArea.
Переменные класса MyModArt | |||
|---|---|---|---|
| Тип | Имя | Доступ | Назначение |
CObArray |
m_oaLines |
private |
Для хранения массива объектов линий |
CRect |
m_rDrawArea |
private |
Для хранения размеров области рисования |
Во вкладке Class View выделите класс MyModArt

и через контекстное меню выполните команду Add/Add Variable

Для каждой переменной заполните мастер так

После этих действий в классе появится код
Код, добавленный мастером в файл MyModArt.h
#pragma once
#include "afx.h"
#include "afxcoll.h"
#include "atltypes.h"
class MyModArt :
public CObject
{
public:
MyModArt(void);
~MyModArt(void);
private:
// Для хранения массива объектов линий
CObArray m_oaLines;
// Для хранения размеров области рисования
CRect m_rDrawArea;
};
Перед тем, как начать рисование, нужно узнать размеры области рисования, куда будет помещен рисунок. Для этого в новый класс MyModArt нужно добавить функцию, которая скопирует информацию в переменную-член m_rDrawArea.
Во вкладке
Щелкните по кнопке Add, затем по кнопке Finish
Мастер добавит следующий код в файлы объявления и реализации
Код, добавленный мастером в файл MyModArt.h
#pragma once
#include "afx.h"
#include "afxcoll.h"
#include "atltypes.h"
class MyModArt :
public CObject
{
public:
MyModArt(void);
~MyModArt(void);
private:
// Для хранения массива объектов линий
CObArray m_oaLines;
// Для хранения размеров области рисования
CRect m_rDrawArea;
public:
// Установить прямоугольник области рисования Drawing Area
void SetRect(CRect rDrawArea);
};
Код, добавленный мастером в файл MyModArt.cpp
#include "StdAfx.h"
#include ".\mymodart.h"
MyModArt::MyModArt(void)
{
}
MyModArt::~MyModArt(void)
{
}
// Установить прямоугольник области рисования Drawing Area
void MyModArt::SetRect(CRect rDrawArea)
{
}
Наполните код функции такКод функции SetRect() в файле MyModArt.cpp
// Установить прямоугольник области рисования Drawing Area
void MyModArt::SetRect(CRect rDrawArea)
{
m_rDrawArea = rDrawArea;
}
Основная особенность этого модуля - его способность создавать в области рисования случайные волнистые линии разной толщины и цвета. Сначала необходимо создать одну функцию рисования случайных линий, затем многократно ее вызывать. Для этой функции требуется задать количество линий, цвет и толщину пера, а также начальную точку рисования. Добавим эту функцию к классу рисования.
Во вкладке
Наполните новую функцию необходимым кодом, как показано нижеКод функции NewLine() в файле MyModArt.cpp
// Функция рисования одной случайной волны
void MyModArt::NewLine()
{
int iNumLines;
int iCurLine;
int iCurColor;
unsigned int iCurWidth;
CPoint ptBegin;
CPoint ptEnd;
static COLORREF crColors[8] = {
// Таблица цветов
RGB( 0, 0, 0), // Black - Черный
RGB( 0, 0, 255), // Blue - Синий
RGB( 0, 255, 0), // Green - Зеленый
RGB( 0, 255, 255), // Cyan - Голубой
RGB( 255, 0, 0), // Red - Красный
RGB( 255, 0, 255), // Magenta - Сиреневый
RGB( 255, 255, 0), // Yellow - Желтый
RGB( 255, 255, 255) // White - Белый
};
// Упорядочить (Normalize) координаты прямоугольника
// перед определением ширины и высоты
m_rDrawArea.NormalizeRect();
// Получить ширину и высоту области рисования
int iWidth = m_rDrawArea.Width();
int iHeight = m_rDrawArea.Height();
// Сгенерировать случайное ненулевое число частей волны
while(!(iNumLines = rand() % 100));
iCurColor = rand() % 8; // Случайный цвет
iCurWidth = (rand() % 8) + 1; // Случайная толщина
// Случайная начальная точка рисования в области рисования
ptBegin.x = (rand() % iWidth) + m_rDrawArea.left;
ptBegin.y = (rand() % iHeight) + m_rDrawArea.top;
// Рисование волны посегментно
for(iCurLine = 0; iCurLine < iNumLines; iCurLine++){
// Определить конечную точку сегмента
ptEnd.x = ((rand() % 20) - 10) + ptBegin.x;
ptEnd.y = ((rand() % 20) - 10) + ptBegin.y;
MyLine *pLine = NULL;
try // Попытка
{
// Создать и инициализировать новый объект MyLine
pLine = new MyLine(ptBegin, ptEnd);
pLine->Set(crColors[iCurColor], iCurWidth);
// Добавить новую линию к массиву объектов
m_oaLines.Add(pLine);
}
catch(CMemoryException *perr) // Исключение по памяти
{
AfxMessageBox("Не хватило памяти", MB_ICONSTOP | MB_OK);
if(pLine){
delete pLine;
pLine = NULL;
}
perr->Delete(); // Удалить объект-исключение
}
// Переместить начало рисования для продолжения
ptBegin = ptEnd;
} // End of for
}
Таким образом мы создали функцию, которая рисует одну волнистую линию со случайными характеристиками.
Теперь нужно разработать функцию, которая будет генерировать последовательность таких линий. Для этого добавим новый метод к классу рисования.
Выделите во вкладке
Мастер сгенерирует заготовку функции, которую заполните следующим кодомКод функции NewDrawing() в файле MyModArt.cpp
// Генерация полного рисунка
void MyModArt::NewDrawing(void)
{
int iNumLines;
// Определить количество создаваемых линий
while(!(iNumLines = rand() % 10));
// Рисуем линии
for(int iCurLine = 0; iCurLine < iNumLines; iCurLine++)
NewLine();
}
Функция NewDrawing() заполнит массив объектов, на который указывает переменная-член m_oaLines.
После того, как массив линий всего рисунка будет заполнен, его нужно отобразить в классе представления -приложения. Каждый элемент массива линий представляет собой объект-экземпляр класса MyLine, члены-данные которого содержат начальную и конечную координаты прямолинейного отрезка, а также его цвет и толщину. Кроме того, каждый объект MyLine способен нарисовать себя в переданном ему контексте устройства. Добавим к классу MyModArt метод, который в цикле будет перебирать все объекты массива отрезков прямых и рисовать каждый из них в указанном контексте устройства.
Во вкладке Class View выделите класс MyModArt и через контекстное меню вызовите мастер добавления функций, который заполните так

Не забудьте нажать кнопку Add!
Сгенерированную мастером заготовку новой функции рисования наполните следующим кодомКод функции Draw() в файле MyModArt.cpp
// Рисование всех линий
void MyModArt::Draw(CDC* pDC)
{
// Получить количество элементов массива линий
int iCount = m_oaLines.GetSize();
if(!iCount) // Если нечего рисовать
return;
// Рисование каждой линии
for(int iPos = 0; iPos < iCount; iPos++)
((MyLine*)m_oaLines.GetAt(iPos))->Draw(pDC);
}
Для преобразования в последовательную форму воспользуемся функцией Serialize массива объектов, которую мы уже применяли ранее в классе MyLine. Упакуем ее в функцию с таким же именем класса MyModArt.
Вызовите для класса MyModArt мастер добавления функций и заполните его так

Не забудьте нажать кнопку Add!
Сгенерированную мастером заготовку новой функции рисования наполните следующим кодомКод функции Serialize() в файле MyModArt.cpp
// Преобразование в последовательную форму
void MyModArt::Serialize(CArchive ar)
{
// Передать архивный объект массиву объектов
m_oaLines.Serialize(ar);
}
Для полноценного набора функциональных возможностей нужно предусмотреть и возможность удаления рисунка из класса рисования. Это нужно для того, чтобы можно было создать новый рисунок или загрузить существующий. Для этого достаточно перебрать все элементы массива объектов линий и удалить каждый из них. При этом нужно учесть, что в массиве объектов находятся не сами объекты, а указатели на неименованную область, где хранятся экземпляры. Поэтому после удаления каждого неименованного объекта по его указателю необходимо очистить сам массив указателей.
Добавьте новый метод к классу рисования
Сгенерированную мастером заготовку новой функции рисования наполните следующим кодомКод функции ClearDrawing() в файле MyModArt.cpp
// Очистка рисунка
void MyModArt::ClearDrawing(void)
{
// Получить количество элементов массива линий
int iCount = m_oaLines.GetSize();
// Удаление каждой линии
for(int iPos = 0; iPos < iCount; iPos++)
delete m_oaLines.GetAt(iPos);
m_oaLines.RemoveAll();
}
Осталось инициализировать генератор случайных чисел и пометить класс как .
Внесите изменения в конструктор рисования, чтобы он выглядел такКод конструктора в файле MyModArt.cpp
MyModArt::MyModArt(void)
{
srand((unsigned)time(NULL));
}
Добавьте макрос AFX_EXT_CLASS в объявление классаДобавление макроса в файле MyModArt.h
class AFX_EXT_CLASS MyModArt :
public CObject
{
...........................................
};
Добавьте в начало файла MyModArt.cpp непосредственно перед конструктором директиву подключения файла MyLine.hДобавление директивы в файле MyModArt.cpp
.........................
#include "MyLine.h"
MyModArt::MyModArt(void)
{
srand((unsigned)time(NULL));
}
.........................
Выполните команду
Откомпилируйте проект и для режима Release
Переместитесь в каталог проекта и убедитесь, что в результате компиляции появились файлы ModArtDll.dll и ModArtDll.lib, причем для режима Release размер файла ModArtDll.dll на порядок меньше, чем для DebugДля проверки созданного модуля следует создать тестовое приложение, поскольку напрямую библиотечный модуль запустить нельзя. Для тестирования не обязательно создавать полнофункциональное приложение, а можно обойтись минимальным набором функций, достаточным для тщательной проверки библиотечного модуля.
При создании тестового приложения заголовочный файл для класса MyModArt, реализация которого упакована в DLL, следует подключить к соответствующим модулям. Для -приложения это будут, как минимум, модули класса документа, а также, возможно, LIB -файл, созданный в проекте DLL -приложения вместе с DLL -файлом, чтобы он был скомпонован вместе с тестовым приложением.
Сохраните и закройте предыдущий DLL -проект ModArtDLL
Создайте новый проект с именем 






После создания оболочки тестового приложения к нему необходимо подключить библиотечный модуль.
Выполните через главное меню оболочки команду Project/Add Existing Item (Добавить существующий элемент)
В открывшемся диалоговом окне настройте фильтр 'Files of type:' на значение All Files (*.*)
Найдите в каталоге проекта предыдущего
Посмотрите в панели После подключения библиотечного модуля необходимо в тестовое приложение добавить подключение заголовочных файлов всех упакованных в DLL классов, которые будут использоваться в соответствующих файлах исходных текстов, для их видимости компилятором.
Выполните команду Project/Add Existing Item (Добавить существующий элемент)
В открывшемся диалоговом окне найдите папку
После щелчка на кнопке Замечание. Необходимо добавлять заголовочные файлы только тех экспортируемых классов, упакованных в DLL, которые действительно будут использованы в проекте. Если же будут добавлены в приложение заголовочные файлы классов, не востребуемых приложением, то могут возникнуть ошибки линковщика.
Все функциональные возможности по созданию рисунка из случайных волнистых линий заложены нами ранее в класс MyModArt, который мы создали в DLL -проекте и упаковали его в DLL -библиотеку. В данном тестовом приложении мы создадим экземпляр этого класса и включим его в класс документа.
панели Мастер включит следующее объявление экземпляра в класс CTestArtDoc:
Создание объекта в файле TestArtDoc.h
class CTestArtDoc : public CDocument
{
......................
private:
// Объект рисования волнистых линий
MyModArt m_Drawing;
};
Теперь у нас в классе документа тестового приложения имеется объект, созданный как экземпляр DLL -библиотечного созданного нами ранее класса MyModArt. И мы можем организовать управление этим объектом и заставить его выполнить в тестовом приложении те функциональности, которые нами были в него заложены ранее.
При создании объекта нового документа в тестовом приложении автоматически срабатывает функция OnNewDocument() этого объекта. Разместим в этой функции блок кода по управлению объектом m_Drawing, чтобы он создал новый рисунок. Для этого нужно получить от класса представления координаты клиентской области рисования и передать объекту m_Drawing. Затем дать команду этому объекту сгенерировать внутри себя полный рисунок, который позднее можно передать для рисования классу представления.
Для реализации сказанного дополните функцию OnNewDocument() класса документа следующим кодомДополнение OnNewDocument() в файле TestArtDoc.cpp
BOOL CTestArtDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
// Получить позицию от представления
POSITION pos = GetFirstViewPosition();
if(pos != NULL){
// Получить указатель на представление View
CView *pView = GetNextView(pos);
RECT rWndRect;// Создать структуру
// Заполнить структуру координатами области рисования
pView->GetClientRect(rWndRect);
// Передать область в наш объект генерации линий
m_Drawing.SetRect(rWndRect);
// Сгенерировать координаты линий всего рисунка
m_Drawing.NewDrawing();
}
return TRUE;
}
В класс документа добавим функциональность по управлению возможностью сохранения, восстановления и удаления рисунка.
Для сохранения в файле и восстановления из файла отредактируйте в классе документа тестового приложения функцию-член Serialize() следующим образомРедактирование функции Serialize() в файле TestArtDoc.cpp
// CTestArtDoc serialization
void CTestArtDoc::Serialize(CArchive ar)
{
m_Drawing.Serialize(ar);
}
Редактирование заключается в полном удалении текущего автоматически сгенерированного мастером кода и замене его вызовом функции Serialize() класса рисования MyModArt.
Теперь следует добавить функцию для удаления текущего рисунка. Она должна очищать объект m_Drawing тогда, когда создается новый или открывается сохраненный ранее рисунок. В обеих этих случаях автоматически срабатывает функция DeleteContents() базового класса CDocument. Ее и нужно переопределить в нашем классе документа CTestArtDoc, являющимся расширением базового класса CDocument.
В панели Class View выделите класс CTestArtDoc
В панели Properties переключитесь в режим Overrides
Найдите функцию
Отредактируйте заготовку функции такПереопределение функции DeleteContents() базового класса CDocument в производном классе CTestArtDoc файла TestArtDoc.cpp
void CTestArtDoc::DeleteContents()
{
// TODO: Add your specialized
// code here and/or call the base class
// Очищаем массив объектов класса рисунка
m_Drawing.ClearDrawing();
CDocument::DeleteContents();
}
За отображение данных, хранящихся в объекте рисунка m_Drawing класса MyModArt, в нашем тестовом -приложении отвечает класс представления CTestArtView. Именно объект класса представления знает, когда нужно себя перерисовать. Для того, чтобы в классе представления можно было управлять объектом m_Drawing, который умеет себя нарисовать с помощью своего метода Draw(, добавим в класс документа функцию-член, возвращающую указатель на этот объект m_Drawing.
Выделите в панели Class View класс CTestArtDoc
Через контекстное меню вызовите мастер добавления функций, который заполните так
Созданную мастером заготовку функции отредактируйте так
Функция доступа к объекту m_Drawing
// Возвращает указатель на объект рисования
MyModArt* CTestArtDoc::GetDrawing(void)
{
return m_Drawing;
}
Чтобы добавить возможность отображения рисунка в наше приложение, нужно в функции OnDraw() класса представления получить указатель на объект с рисунком, затем вызвать через этот указатель функцию Draw() объекта m_Drawing. Вспомним, что координаты области рисования сохранены в объекте ранее в функции OnNewDocument() класса документа и там же выполнена генерация рисунка.
Найдите в файле TestArtView.cpp реализацию функции OnDraw() класса представления и отредактируйте ее такФункция OnDraw() в файле TestArtView.cpp
void CTestArtView::OnDraw(CDC* pDC)
{
CTestArtDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Получить указатель на объект рисунка
MyModArt *pDrawing = pDoc->GetDrawing();
// Вывести рисунок
pDrawing->Draw(pDC);
}
Не забудьте раскомментировать аргумент pDC функции OnDraw()
С помощью проводника по файлам найдите в каталоге Debug или Release DLL -приложения файл ModArtDll.dll, созданный ранее, и скопируйте его в каталог Debug или Release данного проекта тестового приложения туда, где будет храниться исполнимый файл теста
Постройте проект и убедитесь, что все работаетЭкран тестового приложения должен примерно выглядеть так

Оформите диалоговое окно Создание программ с использованием объектно-ориентированного подхода - это практика программирования, в основу которой положены те же принципы, что используются при любом техническом проектировании. И это существенно облегчает разработку, снижает затраты, уменьшает число ошибок, сокращает сроки и является приемом борьбы со сложностью в больших проектах.
DLL ( - динамически загружаемые библиотеки. Существуют два типа DLL
DLL MFC - библиотеки ( MFC regular DLL )DLL MFC - библиотеки ( MFC extension DLL )Динамически подключаемая библиотека - это специального вида исполняемый файл с расширением .dll, используемый для хранения классов, функций и ресурсов отдельно от исполняемого файла.
Существует и другой способ хранения скомпилированного кода отдельно от исходного кода приложения - в библиотечных файлах с расширением .lib. Этот код включается в приложение линковщиком в процессе создания приложения. Такой процесс называется статическим связыванием. Код библиотеки хранится в исполняемом файле приложения. И если библиотеку использует несколько приложений, экземпляр кода будет включен в исполнимый файл каждого приложения.
Использование DLL обеспечивает динамическое связывание, когда код библиотеки загружается в память и присоединяется к приложению при его запуске на выполнение. Приложение, запущенное на выполнение, называется процессом. Если одновременно выполняются несколько процессов, то каждый процесс может загружать из DLL и присоединять к себе нужную функцию или даже все процессы одну и ту же функцию одновременно.
Применение DLL позволяет реконструировать и сопровождать функцию (или класс) только в одном экземпляре и все внесенные в нее изменения будут немедленно учтены любыми использующими ее приложениями без предварительной их перекомпиляции. Можно считать, что DLL является источником кода, а все упакованные в нее функции и классы - экспортируемыми функциями и классами.
Создание программ с использованием объектно-ориентированного подхода - это практика программирования, в основу которой положены те же принципы, что используются при любом техническом проектировании
DLL можно разместить функции, к которым обращаются многие приложения, то уменьшаются размеры исполняемых файлов приложений на этапе компиляцииDLL не изменяется, то ее можно заменить более новой, причем сами приложения обновлять не придетсяDLL ее можно использовать в приложениях, написанных на других языках программирования для Windows Динамически загружаемые библиотеки - это файлы с заранее откомпилированными кодами функций или классов, которые могут использоваться другими приложениями на этапе выполнения. Функция или класс добавляются в специальную таблицу, являющуюся неотъемлемой частью DLL. В таблице указывается местоположение всех функций и классов, содержащихся в DLL, что обеспечивает быстрый их поиск и вызов исполняемым внешним приложением при его загрузке в память.
Приложение может вызывать код из DLL двумя способами:
LIB -файлом, в котором содержатся фиктивные модули программного кода (заглушки). При запуске приложения фиктивный псевдокод замещается реальным кодом из DLL Заглушка - это псевдофункция, у которой имя и список аргументов совпадают с именем и списком аргументов реальной функции. Внутри функции-заглушки имеется незначительное количество кода, вызывающего реальную функцию из DLL, причем реальной функции при вызове передаются все те аргументы, которые были переданы заглушке. В этом смысле функции DLL можно рассматривать как часть кода приложения, а не как отдельный файл.
Второй способ значительно проще. Библиотечный LIB -файл при компиляции DLL создается автоматически. Для его создания не приходится предпринимать каких-либо особых действий. При использовании LIB -файлов все используемые в приложении DLL загружаются в память в момент запуска приложения и если некоторые из них отсутствуют, то Windows автоматически предупреждает об этом и приложение не выполняется.
Когда используется первый способ, разработчику приложения необходимо самостоятельно организовывать загрузку DLL в память и обрабатывать все ошибочные ситуации при отсутствии нужных DLL.
DLL создаются с помощью оболочки Visual Studio специальным мастером DLL Wizard.
- это динамически загружаемые библиотеки, расширяющие библиотеку базовых классов MFC. Такой тип DLL легче всего создавать и кодировать. Чтобы сделать класс экспортируемым DLL, нужно при его объявлении указать макрос AFX_EXT_CLASS примерно так
class AFX_EXT_CLASS MyClass // Объявление класса
{
..................
};
Далее в приложении, использующем класс, достаточно будет включить этот макрос, и при запуске приложения будет импортирование из DLL нужный класс.
Одним из недостатков является то, что их нельзя использовать в программах, написанных на других языках программирования или в программах C++, компиляторы которых не поддерживают MFC. Но компиляторы фирмы Borland и Symantec поддерживают .
MFC regular DLL - это обычные динамически загружаемые библиотеки. Этот тип DLL поддерживает стандартные функции, а не классы, поэтому планировать их приходится несколько тщательнее, чем . Внутри самой DLL классы можно использовать, но вызов кода внешним приложением нужно организовать через функцию.
Для обеспечения возможности экспорта функции библиотекой следует эту функцию объявить экспортируемой по такому синтаксису
extern "C" тип_возвращаемого_значения PASCAL EXPORT объявление_функции
Необходимо включить все эти дополнительные слова как в заголовочный файл прототипа функции, так и в исходный код ее реализации.
extern "C" объявляет, что это вызов стандартной функции C, поэтому корректировщик имен C++ не должен корректировать имя функцииPASCAL сообщает компилятору, что все параметры функции передаются в порядке, принятом в языке PASCAL, т.е. параметры в стеке размещаются в порядке, обратном обычномуEXPORT информирует компилятор о том, что эта функция будет экспортироваться динамически загружаемой библиотекой во внешние приложенияДля создания DLL применяется специальный тип проекта оболочки Visual Studio. Чтобы сделать функции экспортируемыми DLL, следует добавить их имена в файл определений DEF.lib этого проекта. Файл DEF.lib представляет собой библиотечный (т.е. с расширением LIB ) файл заглушек и таблицу экспортируемых функций, содержащихся в DLL. В него включается имя DLL, ее краткое описание и имена всех экспортируемых библиотекой функций. Файл DEF проекта DLL автоматически создается мастером "DLL Wizard" и имеет определенный формат. Формат файла изменять нельзя, в него можно только добавлять имена экспортируемых функций.
Примерный вид файла определений DEF.lib
LIBRARY "mydll" DESCRIPTION 'mydll Windows Dynamic Link Library' EXPORTS ; Explicit exports can go here MyFun1 MyFun2 MyFun3
Если в MFC regular DLL используются классы из MFC, то первой строчкой тела всех экспортируемых функций должен быть вызов макроса AFX_MANAGE_STATE. Это диктуется необходимостью обеспечить многопоточную поддержку в функциях, благодаря которой можно вызывать функции класса одновременно несколькими потоками процесса. Макрос AFX_MANAGE_STATE имеет единственный аргумент - указатель на структуру AFX_MANAGE_STATE, который можно получить в результате вызова функции AfxGetStaticModuleState(). Типичная экспортируемая функция, использующая библиотеку MFC, имеет следующий вид
extern "C" void PASCAL EXPORT MyFun(список_аргументов)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Далее идет обычное тело функции
.....................
}
При проектировании функций для DLL нужно соблюдать правила:
Создадим одну библиотеку DLL, расширяющую MFC, в которую включим два класса. Работа будет опираться на результаты работы Lab10. Первым пусть будет класс MyLine из этой работы. Второй класс будет создавать случайные рисунки на поверхности рисования. В него войдет массив объектов MyLine, который он будет создавать и заполнять данными во время рисования.
В этом классе должна находиться функция для сохранения и восстановления рисунков, а также для удаления уже не нужных рисунков, чтобы можно было создавать новые. Кроме того, класс должен знать размеры поверхности рисования, так как ему придется генерировать рисунки в границах поверхности рисования.
Создайте новый проект, указав, что это проект
Установите настройку мастера
Щелкните по кнопке Finish, после чего заготовка проекта мастером будет создана
Скопируйте файлы MyLine.h и MyLine.cpp из папки проекта Lab10 - DrawSDI (VS.NET 2003) в папку текущего проекта ModArtDll
Присоедините файлы MyLine.h и MyLine.cpp к текущему проекту. Для этого выполните в меню оболочки команду Project/Add Existing Item (Добавить существующий элемент)После добавления обоих файлов к проекту класс MyLine появится во вкладке Class View.
Теперь основа проекта готова, пришло время заняться наполнением модуля. Класс MyLine представляет собой вполне удобный механизм для повторного использования некоторых созданных ранее функций и параметров. Имеющиеся в этом модуле функции можно использовать для генерации случайных рисунков.
Для реализации нужных нам функциональных возможностей необходимо создать новый класс. Для этого выполните следующие шаги:
Добавьте новый класс к создаваемому проекту. Для этого во вкладке Class View выделите верхний узел

и через контекстное меню выберите команду Add/Add Class (Добавить класс). Выберите шаблон Generic C++ Class

Присвойте новому классу имя MyModArt, базовому классу - имя CObject, а в качестве модификатора доступа укажите public

Щелкните по кнопке Finish
После создания нового класса необходимо добавить в него две переменные: m_oaLines и m_rDrawArea.
Переменные класса MyModArt | |||
|---|---|---|---|
| Тип | Имя | Доступ | Назначение |
CObArray |
m_oaLines |
private |
Для хранения массива объектов линий |
CRect |
m_rDrawArea |
private |
Для хранения размеров области рисования |
Во вкладке Class View выделите класс MyModArt

и через контекстное меню выполните команду Add/Add Variable

Для каждой переменной заполните мастер так

После этих действий в классе появится код
Код, добавленный мастером в файл MyModArt.h
#pragma once
#include "afx.h"
#include "afxcoll.h"
#include "atltypes.h"
class MyModArt :
public CObject
{
public:
MyModArt(void);
~MyModArt(void);
private:
// Для хранения массива объектов линий
CObArray m_oaLines;
// Для хранения размеров области рисования
CRect m_rDrawArea;
};
Перед тем, как начать рисование, нужно узнать размеры области рисования, куда будет помещен рисунок. Для этого в новый класс MyModArt нужно добавить функцию, которая скопирует информацию в переменную-член m_rDrawArea.
Во вкладке
Щелкните по кнопке Add, затем по кнопке Finish
Мастер добавит следующий код в файлы объявления и реализации
Код, добавленный мастером в файл MyModArt.h
#pragma once
#include "afx.h"
#include "afxcoll.h"
#include "atltypes.h"
class MyModArt :
public CObject
{
public:
MyModArt(void);
~MyModArt(void);
private:
// Для хранения массива объектов линий
CObArray m_oaLines;
// Для хранения размеров области рисования
CRect m_rDrawArea;
public:
// Установить прямоугольник области рисования Drawing Area
void SetRect(CRect rDrawArea);
};
Код, добавленный мастером в файл MyModArt.cpp
#include "StdAfx.h"
#include ".\mymodart.h"
MyModArt::MyModArt(void)
{
}
MyModArt::~MyModArt(void)
{
}
// Установить прямоугольник области рисования Drawing Area
void MyModArt::SetRect(CRect rDrawArea)
{
}
Наполните код функции такКод функции SetRect() в файле MyModArt.cpp
// Установить прямоугольник области рисования Drawing Area
void MyModArt::SetRect(CRect rDrawArea)
{
m_rDrawArea = rDrawArea;
}
Основная особенность этого модуля - его способность создавать в области рисования случайные волнистые линии разной толщины и цвета. Сначала необходимо создать одну функцию рисования случайных линий, затем многократно ее вызывать. Для этой функции требуется задать количество линий, цвет и толщину пера, а также начальную точку рисования. Добавим эту функцию к классу рисования.
Во вкладке
Наполните новую функцию необходимым кодом, как показано нижеКод функции NewLine() в файле MyModArt.cpp
// Функция рисования одной случайной волны
void MyModArt::NewLine()
{
int iNumLines;
int iCurLine;
int iCurColor;
unsigned int iCurWidth;
CPoint ptBegin;
CPoint ptEnd;
static COLORREF crColors[8] = {
// Таблица цветов
RGB( 0, 0, 0), // Black - Черный
RGB( 0, 0, 255), // Blue - Синий
RGB( 0, 255, 0), // Green - Зеленый
RGB( 0, 255, 255), // Cyan - Голубой
RGB( 255, 0, 0), // Red - Красный
RGB( 255, 0, 255), // Magenta - Сиреневый
RGB( 255, 255, 0), // Yellow - Желтый
RGB( 255, 255, 255) // White - Белый
};
// Упорядочить (Normalize) координаты прямоугольника
// перед определением ширины и высоты
m_rDrawArea.NormalizeRect();
// Получить ширину и высоту области рисования
int iWidth = m_rDrawArea.Width();
int iHeight = m_rDrawArea.Height();
// Сгенерировать случайное ненулевое число частей волны
while(!(iNumLines = rand() % 100));
iCurColor = rand() % 8; // Случайный цвет
iCurWidth = (rand() % 8) + 1; // Случайная толщина
// Случайная начальная точка рисования в области рисования
ptBegin.x = (rand() % iWidth) + m_rDrawArea.left;
ptBegin.y = (rand() % iHeight) + m_rDrawArea.top;
// Рисование волны посегментно
for(iCurLine = 0; iCurLine < iNumLines; iCurLine++){
// Определить конечную точку сегмента
ptEnd.x = ((rand() % 20) - 10) + ptBegin.x;
ptEnd.y = ((rand() % 20) - 10) + ptBegin.y;
MyLine *pLine = NULL;
try // Попытка
{
// Создать и инициализировать новый объект MyLine
pLine = new MyLine(ptBegin, ptEnd);
pLine->Set(crColors[iCurColor], iCurWidth);
// Добавить новую линию к массиву объектов
m_oaLines.Add(pLine);
}
catch(CMemoryException *perr) // Исключение по памяти
{
AfxMessageBox("Не хватило памяти", MB_ICONSTOP | MB_OK);
if(pLine){
delete pLine;
pLine = NULL;
}
perr->Delete(); // Удалить объект-исключение
}
// Переместить начало рисования для продолжения
ptBegin = ptEnd;
} // End of for
}
Таким образом мы создали функцию, которая рисует одну волнистую линию со случайными характеристиками.
Теперь нужно разработать функцию, которая будет генерировать последовательность таких линий. Для этого добавим новый метод к классу рисования.
Выделите во вкладке
Мастер сгенерирует заготовку функции, которую заполните следующим кодомКод функции NewDrawing() в файле MyModArt.cpp
// Генерация полного рисунка
void MyModArt::NewDrawing(void)
{
int iNumLines;
// Определить количество создаваемых линий
while(!(iNumLines = rand() % 10));
// Рисуем линии
for(int iCurLine = 0; iCurLine < iNumLines; iCurLine++)
NewLine();
}
Функция NewDrawing() заполнит массив объектов, на который указывает переменная-член m_oaLines.
После того, как массив линий всего рисунка будет заполнен, его нужно отобразить в классе представления -приложения. Каждый элемент массива линий представляет собой объект-экземпляр класса MyLine, члены-данные которого содержат начальную и конечную координаты прямолинейного отрезка, а также его цвет и толщину. Кроме того, каждый объект MyLine способен нарисовать себя в переданном ему контексте устройства. Добавим к классу MyModArt метод, который в цикле будет перебирать все объекты массива отрезков прямых и рисовать каждый из них в указанном контексте устройства.
Во вкладке Class View выделите класс MyModArt и через контекстное меню вызовите мастер добавления функций, который заполните так

Не забудьте нажать кнопку Add!
Сгенерированную мастером заготовку новой функции рисования наполните следующим кодомКод функции Draw() в файле MyModArt.cpp
// Рисование всех линий
void MyModArt::Draw(CDC* pDC)
{
// Получить количество элементов массива линий
int iCount = m_oaLines.GetSize();
if(!iCount) // Если нечего рисовать
return;
// Рисование каждой линии
for(int iPos = 0; iPos < iCount; iPos++)
((MyLine*)m_oaLines.GetAt(iPos))->Draw(pDC);
}
Для преобразования в последовательную форму воспользуемся функцией Serialize массива объектов, которую мы уже применяли ранее в классе MyLine. Упакуем ее в функцию с таким же именем класса MyModArt.
Вызовите для класса MyModArt мастер добавления функций и заполните его так

Не забудьте нажать кнопку Add!
Сгенерированную мастером заготовку новой функции рисования наполните следующим кодомКод функции Serialize() в файле MyModArt.cpp
// Преобразование в последовательную форму
void MyModArt::Serialize(CArchive ar)
{
// Передать архивный объект массиву объектов
m_oaLines.Serialize(ar);
}
Для полноценного набора функциональных возможностей нужно предусмотреть и возможность удаления рисунка из класса рисования. Это нужно для того, чтобы можно было создать новый рисунок или загрузить существующий. Для этого достаточно перебрать все элементы массива объектов линий и удалить каждый из них. При этом нужно учесть, что в массиве объектов находятся не сами объекты, а указатели на неименованную область, где хранятся экземпляры. Поэтому после удаления каждого неименованного объекта по его указателю необходимо очистить сам массив указателей.
Добавьте новый метод к классу рисования
Сгенерированную мастером заготовку новой функции рисования наполните следующим кодомКод функции ClearDrawing() в файле MyModArt.cpp
// Очистка рисунка
void MyModArt::ClearDrawing(void)
{
// Получить количество элементов массива линий
int iCount = m_oaLines.GetSize();
// Удаление каждой линии
for(int iPos = 0; iPos < iCount; iPos++)
delete m_oaLines.GetAt(iPos);
m_oaLines.RemoveAll();
}
Осталось инициализировать генератор случайных чисел и пометить класс как .
Внесите изменения в конструктор рисования, чтобы он выглядел такКод конструктора в файле MyModArt.cpp
MyModArt::MyModArt(void)
{
srand((unsigned)time(NULL));
}
Добавьте макрос AFX_EXT_CLASS в объявление классаДобавление макроса в файле MyModArt.h
class AFX_EXT_CLASS MyModArt :
public CObject
{
...........................................
};
Добавьте в начало файла MyModArt.cpp непосредственно перед конструктором директиву подключения файла MyLine.hДобавление директивы в файле MyModArt.cpp
.........................
#include "MyLine.h"
MyModArt::MyModArt(void)
{
srand((unsigned)time(NULL));
}
.........................
Выполните команду
Откомпилируйте проект и для режима Release
Переместитесь в каталог проекта и убедитесь, что в результате компиляции появились файлы ModArtDll.dll и ModArtDll.lib, причем для режима Release размер файла ModArtDll.dll на порядок меньше, чем для DebugДля проверки созданного модуля следует создать тестовое приложение, поскольку напрямую библиотечный модуль запустить нельзя. Для тестирования не обязательно создавать полнофункциональное приложение, а можно обойтись минимальным набором функций, достаточным для тщательной проверки библиотечного модуля.
При создании тестового приложения заголовочный файл для класса MyModArt, реализация которого упакована в DLL, следует подключить к соответствующим модулям. Для -приложения это будут, как минимум, модули класса документа, а также, возможно, LIB -файл, созданный в проекте DLL -приложения вместе с DLL -файлом, чтобы он был скомпонован вместе с тестовым приложением.
Сохраните и закройте предыдущий DLL -проект ModArtDLL
Создайте новый проект с именем 






После создания оболочки тестового приложения к нему необходимо подключить библиотечный модуль.
Выполните через главное меню оболочки команду Project/Add Existing Item (Добавить существующий элемент)
В открывшемся диалоговом окне настройте фильтр 'Files of type:' на значение All Files (*.*)
Найдите в каталоге проекта предыдущего
Посмотрите в панели После подключения библиотечного модуля необходимо в тестовое приложение добавить подключение заголовочных файлов всех упакованных в DLL классов, которые будут использоваться в соответствующих файлах исходных текстов, для их видимости компилятором.
Выполните команду Project/Add Existing Item (Добавить существующий элемент)
В открывшемся диалоговом окне найдите папку
После щелчка на кнопке Замечание. Необходимо добавлять заголовочные файлы только тех экспортируемых классов, упакованных в DLL, которые действительно будут использованы в проекте. Если же будут добавлены в приложение заголовочные файлы классов, не востребуемых приложением, то могут возникнуть ошибки линковщика.
Все функциональные возможности по созданию рисунка из случайных волнистых линий заложены нами ранее в класс MyModArt, который мы создали в DLL -проекте и упаковали его в DLL -библиотеку. В данном тестовом приложении мы создадим экземпляр этого класса и включим его в класс документа.
панели Мастер включит следующее объявление экземпляра в класс CTestArtDoc:
Создание объекта в файле TestArtDoc.h
class CTestArtDoc : public CDocument
{
......................
private:
// Объект рисования волнистых линий
MyModArt m_Drawing;
};
Теперь у нас в классе документа тестового приложения имеется объект, созданный как экземпляр DLL -библиотечного созданного нами ранее класса MyModArt. И мы можем организовать управление этим объектом и заставить его выполнить в тестовом приложении те функциональности, которые нами были в него заложены ранее.
При создании объекта нового документа в тестовом приложении автоматически срабатывает функция OnNewDocument() этого объекта. Разместим в этой функции блок кода по управлению объектом m_Drawing, чтобы он создал новый рисунок. Для этого нужно получить от класса представления координаты клиентской области рисования и передать объекту m_Drawing. Затем дать команду этому объекту сгенерировать внутри себя полный рисунок, который позднее можно передать для рисования классу представления.
Для реализации сказанного дополните функцию OnNewDocument() класса документа следующим кодомДополнение OnNewDocument() в файле TestArtDoc.cpp
BOOL CTestArtDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
// Получить позицию от представления
POSITION pos = GetFirstViewPosition();
if(pos != NULL){
// Получить указатель на представление View
CView *pView = GetNextView(pos);
RECT rWndRect;// Создать структуру
// Заполнить структуру координатами области рисования
pView->GetClientRect(rWndRect);
// Передать область в наш объект генерации линий
m_Drawing.SetRect(rWndRect);
// Сгенерировать координаты линий всего рисунка
m_Drawing.NewDrawing();
}
return TRUE;
}
В класс документа добавим функциональность по управлению возможностью сохранения, восстановления и удаления рисунка.
Для сохранения в файле и восстановления из файла отредактируйте в классе документа тестового приложения функцию-член Serialize() следующим образомРедактирование функции Serialize() в файле TestArtDoc.cpp
// CTestArtDoc serialization
void CTestArtDoc::Serialize(CArchive ar)
{
m_Drawing.Serialize(ar);
}
Редактирование заключается в полном удалении текущего автоматически сгенерированного мастером кода и замене его вызовом функции Serialize() класса рисования MyModArt.
Теперь следует добавить функцию для удаления текущего рисунка. Она должна очищать объект m_Drawing тогда, когда создается новый или открывается сохраненный ранее рисунок. В обеих этих случаях автоматически срабатывает функция DeleteContents() базового класса CDocument. Ее и нужно переопределить в нашем классе документа CTestArtDoc, являющимся расширением базового класса CDocument.
В панели Class View выделите класс CTestArtDoc
В панели Properties переключитесь в режим Overrides
Найдите функцию
Отредактируйте заготовку функции такПереопределение функции DeleteContents() базового класса CDocument в производном классе CTestArtDoc файла TestArtDoc.cpp
void CTestArtDoc::DeleteContents()
{
// TODO: Add your specialized
// code here and/or call the base class
// Очищаем массив объектов класса рисунка
m_Drawing.ClearDrawing();
CDocument::DeleteContents();
}
За отображение данных, хранящихся в объекте рисунка m_Drawing класса MyModArt, в нашем тестовом -приложении отвечает класс представления CTestArtView. Именно объект класса представления знает, когда нужно себя перерисовать. Для того, чтобы в классе представления можно было управлять объектом m_Drawing, который умеет себя нарисовать с помощью своего метода Draw(, добавим в класс документа функцию-член, возвращающую указатель на этот объект m_Drawing.
Выделите в панели Class View класс CTestArtDoc
Через контекстное меню вызовите мастер добавления функций, который заполните так
Созданную мастером заготовку функции отредактируйте так
Функция доступа к объекту m_Drawing
// Возвращает указатель на объект рисования
MyModArt* CTestArtDoc::GetDrawing(void)
{
return m_Drawing;
}
Чтобы добавить возможность отображения рисунка в наше приложение, нужно в функции OnDraw() класса представления получить указатель на объект с рисунком, затем вызвать через этот указатель функцию Draw() объекта m_Drawing. Вспомним, что координаты области рисования сохранены в объекте ранее в функции OnNewDocument() класса документа и там же выполнена генерация рисунка.
Найдите в файле TestArtView.cpp реализацию функции OnDraw() класса представления и отредактируйте ее такФункция OnDraw() в файле TestArtView.cpp
void CTestArtView::OnDraw(CDC* pDC)
{
CTestArtDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Получить указатель на объект рисунка
MyModArt *pDrawing = pDoc->GetDrawing();
// Вывести рисунок
pDrawing->Draw(pDC);
}
Не забудьте раскомментировать аргумент pDC функции OnDraw()
С помощью проводника по файлам найдите в каталоге Debug или Release DLL -приложения файл ModArtDll.dll, созданный ранее, и скопируйте его в каталог Debug или Release данного проекта тестового приложения туда, где будет храниться исполнимый файл теста
Постройте проект и убедитесь, что все работаетЭкран тестового приложения должен примерно выглядеть так

Оформите диалоговое окно Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.