рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

АРХИТЕКТУРА ПРИЛОЖЕНИЙ ОС WINDOWS, ПОСТРОЕННЫХ НА БАЗЕ БИБЛИОТЕКЫ MFC

АРХИТЕКТУРА ПРИЛОЖЕНИЙ ОС WINDOWS, ПОСТРОЕННЫХ НА БАЗЕ БИБЛИОТЕКЫ MFC - Конспект Лекций, раздел Науковедение, КОНСПЕКТ ЛЕКЦИЙ по дисциплине Операционные системы   3.1. Введение   Первое Решение, Которо...

 

3.1. Введение

 

Первое решение, которое должен принять программист при разработке приложения для операционных систем Windows 98, Windows NT и Windows 2000 – сколько окон будет поддерживать будущее приложение, т. е. определить тип приложения. При использовании библиотеки MFC (Microsoft Foundation Classis) типы приложений могут быть следующими:

- SDI – приложение с единственным документом (SDI - Single Document Interface) позволяет в каждый данный момент времени открытым только один документ;

- MDI – приложение с многими документами (MDI - Multiple Document Interface) может одновременно держать открытыми несколько документов (как правило, файлов);

- простое диалоговое приложение, которое вообще не открывает документов.

 

3.2. Приложение с единственным документом.

 

SDI-приложение имеет меню, которое пользователь может применять для того, чтобы открыть какой-либо документ, но только один, и затем с ним работать. Здесь мы рассмотрим тексты программ, подготовленные для такого приложения мастером приложений AppWizard при следующих настройках: отсутствует поддержка операций с БД и составными документами, но есть панель инструментов и строка состояния, оперативная справка, комментарии в тексте программы, подключены функции с библиотеки MFC в качестве DLL-модулей.

После генерацации мастером кода будет создано 5 классов

- CaboutDlg - класс диалога для окна About;

- CFirstSDIApp - класс для приложения в целом, порожденный CWinApp;

- CFirstSDIDoc - класс документов;

- CFirstSDIView - класс просмотра;

- CMainFrame - класс рамки окна

Файл заголовок (header file) для CFirstSDIApp приведен в листинге ниже.

 

// FirstSDI.h : Главный файл заголовка для приложения FirstSDI

//

 

#if !defined(AFX_FIRSTSDI_H__2E4C11E5_8F06_11D4_8CD8_000021033DFE__INCLUDED_)

#define AFX_FIRSTSDI_H__2E4C11E5_8F06_11D4_8CD8_000021033DFE__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

#ifndef __AFXWIN_H__

#error Включение ‘stdafx.h’ предшествует включению этого файла для PCH

#endif

 

#include "resource.h" // главные символы

 

// CFirstSDIApp:

// Использование этих классов – смотри в FirstSDI.cpp

 

//

 

class CFirstSDIApp : public CWinApp

{

public:

CFirstSDIApp();

 

// Перегрузка

// Виртуальная функция, созданная ClassWizard, перегружает //{{AFX_VIRTUAL(CFirstSDIApp)

public:

virtual BOOL InitInstance();

//}}AFX_VIRTUAL

 

// Реализация

//{{AFX_MSG(CFirstSDIApp)

afx_msg void OnAppAbout();

// ВНИМАНИЕ!! Здесь ClassWizard будет добавлять

// и удалять функции-члены.

// НЕ РЕДАКТИРУЙТЕ текст в этих блоках!

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio будет вставдять дополнительные

// объявления непосредственно

// перед предыдущей строкой.

#endif

//!defined(AFX_FIRSTSDI_H__2E4C11E5_8F06_11D4_8CD8_000021033DFE__INCLUDED_)

В начале текста директива #if !defined, за которой следует очень длинное выражение, есть в явном виде защита заголовка (include guarding).

 

Пример: #ifndef test_h

#include “test.h”

#define test_h

#endif

 

Такая конструкция гарантирует, что файл заголовка test.h не будет включен в данный модуль дважды. Двойное включение файла заголовка крайне нежелательно в программах на С++. Предположим, определен класс Employee (персонал), и он использует класс Manager (менеджер). Если оба файла заголовков и для класса Manager, и для класса Employee в свою очередь включают файл BigCorp.h, то компилятор выдаст сообщение об ошибке, гласящее, что некоторые символы переопределены, а произошло это из-за неявного повторного включения в модуль файла BigCorp.h.

Использование приведенной ниже конструкции не решает проблемы. Если некто включит test.h, но забудет определить константу test_h, появляется возможность повторно включить файл test.h. Решение вопроса состоит в том, чтобы включить и проверку, и определение константы в сам файл заголовка. Тогда фрагмент файла test.h будет выглядеть так:

 

#ifndef test_h

…. Собственно текст файла

#define test_h

#endif

 

То, что сделал AppWizard в созданном им файле, - сформировал более длинное выражение, чем просто test_h. Это длинное выражение предотвращает возникновение проблем с одинаковыми именами файлов заголовков, которые, однако, размещены в разных папках. Кроме того, используется несколько отличный синтаксис проверки выражения. Директива #pragma once является второй ступенью предохранения от повторного определения объектов в случае, если все-таки кто-то попробует еще раз включить файл заголовка.

В действительности «съедобной начинкой» файла заголовка, ради которой затевался весь этот сыр-бор, является объявление класса CFirstSDIApp. Этот класс - наследник CwinApp, класса MFC, который включает в себя большинство функциональных возможностей, необходимых приложению. AppWizard сгенерировал несколько функций для класса наследника, которые перегружают соответствующие функции базового класса. Фрагмент текста, который начинается с // Перегрузка, как раз и представляет собой перегрузку виртуальной функции. AppWizard генерирует странный комментарий вокруг объявления InitInstance(). Эти комментарии затем будут использованы ClassWizard и облегчат ему включение, при необходимости, новых перегрузок. Следующая секция текста программы – карта сообщений, - и в ней объявляется функция OnAppAbout ().

В файле FirstSDI.cpp AppWizard генерирует тект функций-членов класса CFirstSDIApp – конструктора, InitInstance() и OnAppAbout(). Ниже приведен листинг конструктора, который инициализирует объект класса.

 

CFirsSDIApp::CFirstApp()

{

// что cделать: сюда добавить текст программы конструктора.

// включите все инициализации, существенные для объекта, в эту программу

}

Это конструктор, типичный для Microsoft . Поскольку конструктор ничего не возвращает, сообщить программе о каких-то проблемах, возникших при инициализации объекта совсем не просто. Есть 2 совершенно различных способа выхода из создавшейся ситуации. Подход, исповедуемый Microsoft , - так называемая 2-х этапная инициализация. При этом создается отдельная функция инициализации, так что сам конструктор по сути ничего не инициализирует. Эта функция имеет стандартное название InitInstance (Инициализировать экземпляр), а ее текст представлен ниже.

 

BOOL CFirstSDIApp::InitInstance()

{

AfxEnableControlContainer();

 

// Стандартная инициализация

// Если Вы не будете использовать эту функцию или желаете

// уменьшить размер выполняемого модуля, нужно удалить те

// из следующих ниже подпрограмм инициализации, в которых

// нет необходимости.

 

#ifdef _AFXDLL

Enable3dControls(); // Эту функцию следует вызывать в том

// случае, если используется MFC и

// формируется DLL-модуль

#else

Enable3dControlsStatic(); // Эту функцию следует вызывать

// в том случае, если функции из MFC

// прикомпоновываются статически

#endif

 

// Измените ключ регистрации, под которым хранятся установки.

// Эту строку нужно изменить соответственно наименованию

// вашей фирмы или организации.

SetRegistryKey(_T("Local AppWizard-Generated Applications"));

 

LoadStdProfileSettings(); // Загрузить стандартный файл

// опций INI (включая MRU)

 

// Зарегистрировать шаблон документа. Шаблон документа

// служит в качестве связующего звена между документами,

// рамкой окна и представлениями.

 

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CFirstSDIDoc),

RUNTIME_CLASS(CMainFrame), // рамка главного SDI-окна

RUNTIME_CLASS(CFirstSDIView));

AddDocTemplate(pDocTemplate);

 

// Разбиение командной строки для команд оболочки, DDE

// и открытия файлов

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

 

// Распределить функции, заданные в командной строке

if (!ProcessShellCommand(cmdInfo))

return FALSE;

 

// Создается первое и единственное окно программы,

// показать и обновить его.

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

 

return TRUE;

}

 

Функция InitInstance() готовит приложение к работе. Все начинается с разрешения приложению содержать в своем составе элементы управления ActiveX, для чего вызывается AfxEnableControlContaner(). Затем наступает очередь объемного дизайна элементов управления и ключа регистрации приложения. Следующее действие InitInstance() – регистрация единственного шаблона документа, того самого, который будет создан SDI-приложением. Для анализа командной строки InitInstance() организуют пустой объект класса CCommandLineInfo. Затем программа ParseCommandLine() помещает в него параметры, заданные в командной строке при запуске приложения. И наконец, вызывается ProcessShellCommand(), которая должна организовать выполнение всего того, что задано этими параметрами. Это означает, что ваше приложение сможет поддерживать параметры командной строки и дает таким образом возможность пользователю сэкономить время, необходимое для настройки его работы. Например, если пользователь наберет в командной строке FirstSDI fooble, приложение сразу же после вызова откроет файл fooble. Функция ProcessShellCommand() поддерживает следующие параметры в командной строке.

 

Параметр Действие
Без параметров Запускает приложение и открывает новый файл
Имя_файла Запускает приложение и открывает указанный файл
/p имя_файла Запускает приложение, распечатывает указанный файл на принтере, заданном по умолчанию
/pt имя_файла Принтер Драйвер Порт Запускает приложение, распечатывает указанный файл на указанном принтере
/dde Запускает приложение и ждет команды dde (динамического обмена данными)
/Automation Запускает приложение в качестве автоматного сервера OLE
/Embedding Запускает приложение в режиме редактирования внедренного объекта OLE

 

 

Если вам понадобится реализовать какие-либо другие функции, создайте класс, который унаследует от CCommandLineInfo способность накапливать компоненты, образующиеся при анализе командной строки, а затем в собственном App-классе перегрузите функции CWinApp::ParseCommandLine() и CWinApp::ProcessShellCommand(). Можно обращаться к другим параметрам командной строки следующим образом: набрав Notepad /p blah.txt, вы откроете файл blah.txt в программе Notepad и распечатаете его.

Последний оператор в InitInstance() возвращает TRUE, извещая таким образом вызывающую программу о том, что инициализация завершена и можно приступать к работе.

Присутствие карты сообщений в файле заголовка есть индикатор того, что функция OnAppAbout организует вывод сообщения. Вот как выглядит карта сообщений в файле текста программы:

 

BEGIN_MESSAGE_MAP(CFirstSDIApp, CWinApp)

//{{AFX_MSG_MAP(CFirstSDIApp)

ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

// ВНИМАНИЕ – Здесь ClassWizard будет вставлять и удалять // макросы отображения сообщений

// НЕ РЕДАКТИРУЙТЕ текст в этом блоке!

//}}AFX_MSG_MAP

// Стандартные команды работы с файлами документов

ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

// Стандартные команды установки принтера

ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

END_MESSAGE_MAP()

 

Эта карта сообщений перехватывает команды из меню. Когда пользователь выберет Help => About, будет функция-член CFirstSDIApp::OnAppAbout(). Если же пользователь File => New, или File => Open, или File => Print Setup, то за дело возьмутся соответствующие функции-члены класса CWinApp. Эти функции можно перегрузить функциями собственной разработки, если вы хотите, чтобы они выполняли нечто нестандартное в ответ на перечисленные команды меню. Текст функции OnAppAbout() выглядит так:

 

void CFirstSDIApp::OnAppAbout()

{

CAboutDlg aboutDlg;

aboutDlg.DoModal();

}

Здесь объявляется объект, который является экземпляром класса CAboutDlg, и вызывается функция DoModal(), которая выводит на экран окно диалога. Изменять что-либо в стандартной процедуре обработки щелчков на кнопках Ok и Cancel нет никакой необходимости – а это все, что делается в простейшем окне сообщения.

 

3.3. Приложение с многими документами

 

MDI-приложение также имеет меню, но позволяет пользователю одновременно работать более, чем с одним документом. В этом разделе будут рассмотрены тексты программ, которые готовит AppWizard при таком выборе типа приложения. При этом полагается, что была сделана следующая настройка: отсутствует поддержка операций с базами данных и составными документами, но панель инструментов и строка состояния, оперативная справка, комментарии в тексте программы, подключены функции из библиотеки MFC в качестве DLL-модулей. Как и в случае SDI-приложения – это настройка, которую предлагает AppWizard по умолчанию на всех этапах после первого. Основное внимание в этом разделе будет уделено отличиям в тексте программ от рассмотренного в предыдущем разделе SDI-приложения.

Будет создано пять классов. Имена этих классов для приложения FirstMDI перечислены ниже:

- CAboutDlg – класс диалога для окна About;

- CFirstMDIApp – класс для приложения в целом, порожденный CWinApp;

- CFirstMDIDoc – класс документа;

- CFirstMDIView – класс просмотра;

- CMainFrame –класс рамки окна.

 

FirstMDI.h – главный файл заголовка для приложения FirstMDI:

// FirstMDI.h : главный файл заголовка для приложения FirstMDI

//

 

#if !defined(AFX_FIRSTMDI_H__CECAAE25_9626_11D4_8CD8_000021033E04__INCLUDED_)

#define AFX_FIRSTMDI_H__CECAAE25_9626_11D4_8CD8_000021033E04__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

#ifndef __AFXWIN_H__

#error Включение 'stdafx.h' предшествует включению этого файла для PCH

#endif

 

#include "resource.h" // главные символы

 

// CFirstMDIApp:

// Использование этих классов смотри в FirstMDI.cpp

//

 

class CFirstMDIApp : public CWinApp

{

public:

CFirstMDIApp();

 

// Перегрузка

// Виртуальная функция, созданная ClassWizard, перегружает

//{{AFX_VIRTUAL(CFirstMDIApp)

public:

virtual BOOL InitInstance();

//}}AFX_VIRTUAL

 

// Реализация

//{{AFX_MSG(CFirstMDIApp)

afx_msg void OnAppAbout();

// ВНИМАНИЕ!! Здесь ClassWizard будет добавлять и

// удалять функции-члены.

// НЕ РЕДАКТИРУЙТЕ текст в этих блоках!

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio будет вставлять дополнительные

// объявления непосредственно перед предыдущей строкой.

#endif//!defined(AFX_FIRSTMDI_H__CECAAE25_9626_11D4_8CD8_000021033E04__INCLUDED_)

В чем же отличие этого файла от FirstSDI.h ? Только в именах классов. Даже конструктор тот же самый. Функция OnAppAbout () также в точности повторяет вариант для SDI-приложения. А как насчет InitInstance() ? Текст этой функции приведен в следующем листинге.

 

BOOL CFirstMDIApp::InitInstance()

{

AfxEnableControlContainer();

 

// Стандартная инициализация.

// Если Вы не будете использовать эту функцию или желаете

// уменьшить размер выполняемого модуля, нужно удалить те из

// следующих ниже подпрограмм инициализации, в которых нет

// необходимости.

 

#ifdef _AFXDLL

Enable3dControls(); // Эту функцию следует вызывать в

// том случае, если используется MFC и формируется

// DLL-модуль

#else

Enable3dControlsStatic(); // Эту функцию следует вызывать

// в том случае, если функции из MFC прикомпоновываются

// статически

#endif

 

// Измените ключ регистрации, под которым хранятся установки.

// Эту строку нужно изменить соответственно наименованию

// вашей фирмы или организации.

SetRegistryKey(_T("Local AppWizard-Generated Applications"));

 

LoadStdProfileSettings(); // Загрузить стандартный файл

// опций INI (включая MRU)

 

// Зарегистрировать шаблон документа. Шаблон документа

// служит в качестве связующего звена между документами,

// рамкой окна и представлениями.

 

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(

IDR_FIRSTMTYPE,

RUNTIME_CLASS(CFirstMDIDoc),

RUNTIME_CLASS(CChildFrame), // рамка дочерних окон MDI

RUNTIME_CLASS(CFirstMDIView));

AddDocTemplate(pDocTemplate);

 

// создать рамку главного MDI-окна

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

return FALSE;

m_pMainWnd = pMainFrame;

 

// Разбиение командной строки для команд оболочки, DDE

// и открытия файлов

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

 

// Распределить функции, заданные в командной строке

if (!ProcessShellCommand(cmdInfo))

return FALSE;

 

// Главное окно программы инициализировано, так что можно

// показать и обновить его.

pMainFrame->ShowWindow(m_nCmdShow);

pMainFrame->UpdateWindow();

 

return TRUE;

}

 

В чем разница? Здесь вам поможет WinDiff – средство, которое входит в состав Visual C++, и вызвать которое можно из меню Tools (инструменты). Используя WinDiff, сравните версии функции InitInstance() в файлах программ приложений FirstMDI и FirstSDI. Вы увидите, что, кроме имен классов, имеются следующие отличия:

- MDI-приложение включает файл ChildFrm.h, SDI-приложение в таком файле не нуждается;

- MDI-приложение устанавливает шаблон CmultiDocTemplate, а SDI-приложение – CsingleDocTemplate;

- MDI-приложение организует главное окно и затем выводит его на экран, а SDI-приложение этого не делает.

Это сравнение дает ясное представление о преимуществах парадигмы Представление/Документ – достаточно серьезное отличие в функционировании приложения достигается небольшими фрагментами текстов программ проекта, причем, на сколько это возможно, все подробности их реализации скрыты от разработчика.

 

3.4. Простое диалоговое приложение

 

Простое диалоговое приложение значительно проще, чем SDI- и MDI-приложения. Создадим приложения этого вида, FirstDialog, заказав следующие параметры AppWizard – имеется окно About, отсутствует оперативная справка, используется объемный дизайн окна, отсутствует поддержка операций с автоматными серверами, но поддерживаются элементы управления ActivX, включаются комментарии в тексты программ, функции из библиотеки MFC подключаются к приложению в качестве Dll-модулей.

Будет создано три класса. Имена этих классов для приложения FirstDialog перечисленны ниже:

- CAboutDlg – класс диалога для окна About;

- CFirstDialogApp – класс для приложения в целом, порожденный CWinApp;

- CFirstDIalogDlg – класс диалога для приложения в целом.

Файл заголовка для приложения FistDialog представлен ниже в листинге:

// FirstDialog.h : Главный файл заголовка для приложения FIRSTDIALOG

//

 

#if !defined(AFX_FIRSTDIALOG_H__CECAAE3B_9626_11D4_8CD8_000021033E04__INCLUDED_)

#define AFX_FIRSTDIALOG_H__CECAAE3B_9626_11D4_8CD8_000021033E04__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

#ifndef __AFXWIN_H__

#error Включение 'stdafx.h' предшествует включению этого файла для PCH

#endif

 

#include "resource.h" // главные символы

 

// CFirstDialogApp:

// Использование этих классов смотри в FirstDialog.cpp

//

 

class CFirstDialogApp : public CWinApp

{

public:

CFirstDialogApp();

 

// Перегрузка

// Виртуальная функция, созданная ClassWizard, перегружает //{{AFX_VIRTUAL(CFirstDialogApp)

public:

virtual BOOL InitInstance();

//}}AFX_VIRTUAL

 

// Реализация

//{{AFX_MSG(CFirstDialogApp)

afx_msg void OnAppAbout();

// ВНИМАНИЕ!! Здесь ClassWizard будет добавлять и

// удалять функции-члены.

// НЕ РЕДАКТИРУЙТЕ текст в этих блоках!

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio будет вставлять дополнительные

// объявления непосредственно перед предыдущей строкой.

#endif //!defined(AFX_FIRSTDIALOG_H__CECAAE3B_9626_11D4_8CD8_000021033E04__INCLUDED_)

 

Класс CFirstDialogApp является наследником CWinApp, класса MFC, который включает в себя большинство функциональных возможностей, необходимых приложению. Класс CWinApp имеет конструктор, который ничего не делает, как, впрочем, и конструкторы в SDI- и MDI-приложениях, рассмотренные в предшествующих разделах. Кроме того, прегружается функция InitInstance().

В программе, во-первых, разрешается режим объемного дизайна элементов управления, поскольку так было заказано при настройке AppWizard. Затем выводится диалоговое окно, которое и является окном приложения. Для того, чтобы это сделать, функция создает Dlg-экземпляр класса CFirstDialogDlg, а затем вызывает функцию DoModal(), которая выодит окно на экран и возвращает IDOK, если пользователь щелкнет на ОК, или IDCANCEL – если пользователь щелкнет на Cancel. Наша задача состоит в том, чтобы организовать какую-то полезную работу в этом диалоговом окне. После всего функция InitInstance () возвращает FALSE, поскольку мы имеем дело с простым диалоговым приложением, которое прекращает функционировать после того, как диалоговое окно будет закрыто. Если вы обратили внимание, то прежде – в SDI- и MDI- приложениях функция InitInstance () возвращала TRUE, что трактуется следующим образом – все хорошо, можно выполнять оставшуюся часть приложения. В то же время возврат FALSE означал – что-то у них там не связалось при инициализации. Поскольку в данном случае никакого продолжения последовать не должно, в простом диалоговом приложении функция InitInstance () всегда возвращает FALSE.

 

– Конец работы –

Эта тема принадлежит разделу:

КОНСПЕКТ ЛЕКЦИЙ по дисциплине Операционные системы

ВОСТОЧНОУКРАИНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ... Северодонецкий технологический институт... КОНСПЕКТ ЛЕКЦИЙ...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: АРХИТЕКТУРА ПРИЛОЖЕНИЙ ОС WINDOWS, ПОСТРОЕННЫХ НА БАЗЕ БИБЛИОТЕКЫ MFC

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

УПРАВЛЕНИЕ ПРОЦЕССОРАМИ И ПАМЯТЬЮ В ОПЕРАЦИОННЫХ СИСТЕМАХ WINDOWS
  1.1. Обзор компонент архитектуры ОС Windows.   К работе над графической средой для персональных компьютеров IBM PC компания Microsoft приступила еще в 1981 го

АРХИТЕКТУРА ПРИЛОЖЕНИЙ WIN32 ДЛЯ ОС WINDOWS
2.1. Прохождение сообщений в системе Рассмотрим ситуацию, когда пользователь приложения нажимает клавишу, а система вырабатывает сообщение об этом событии. Вы знаете, что Windows обеспечив

Обработка сообщений
  Хотя операционная система и использует целые числа для идентификации событий, но в тексте про­граммы мы будем иметь дело с символьными идентификаторами. Огромное количество директив

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги