Мегаобучалка Главная | О нас | Обратная связь  


ЭКЗАМЕНАЦИОННЫЙ БИЛЕТ № 24




 

1. Динамические библиотеки.

В DLL содержатся все функции Windows API. Три самые важные DLL:

Kernel32.dll (управление памятью, процессами и потоками), User32.dll

(поддержка пользовательского интерфейса, в том числе, функции, связанные с

созданием окон и передачей сообщений) и GDI32.dll (графика и вывод

текста).

В Windows есть другие DLL:

AdvAPI32.dll – содержит функции для защиты объектов, работы с

реестром и регистрации событий

ComDlg32.dll – стандартные диалоговые окна (вроде FileOpen и

FileSave)

ComCtl32.dll – поддерживает стандартные элементы управления

DLL нужно применять для реализации следующих возможностей:

1. Расширение функциональности приложения.

2. Возможность использования разных языков программирования.

3. Более простое управление проектом.

4. Экономия памяти..

5. Разделение ресурсов..

6. Упрощение локализации.

7. Решение проблем, связанных с особенностями различных

платформ..

8. Реализация специфических возможностей.

DLL и адресное пространство процесса.

DLL представляет собой набор модулей исходного кода, в каждом их

которых содержится определенное число функций, вызываемых приложением

или другим DLL. Причем в DLL обычно нет кода, предназначенного для

обработки циклов выборки сообщений и создания окон.

Файлы с исходным кодом компилируются и компонуются также, как и при

создании EXE-файла, но при компоновке нужно указать ключ /DLL.

Чтобы приложение (или другая DLL) могла вызывать функции,

содержащиеся в DLL, образ ее файла нужно сначала спроецировать на адресное

пространство вызывающего процесса. Это выполняется за счет неявного

связывания при загрузке, либо за счет явного – в период выполнения. Теперь

все функции DLL доступны всем потокам этого процесса. Когда поток

вызывает из DLL какую-то функцию, та считывает свои параметры из списка

потока и размещает в этом стеке собственные локальные переменные. Кроме

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

процессу – DLL ничем не владеет.

При проецировании образа DLL-файла на адресное пространство процесса

система создает также экземпляры глобальных и статических переменных.

Неявное связывание EXE – и DLL – модулей

Неявное связывание (implicit linking) - самый распространенный метод.

Исполняемый модуль (EXE) импортирует функции и переменные из DLL, а

DLL– модули экспортирует их в исполняемый модуль. DLL – также может

импортировать функции и переменные их других DLL.

Создание DLL-модуля

DLL может экспортировать переменные, функции или С++ классы в другие

модули.

При разработке DLL сначала создается заголовочный файл, который

включается во все модули исходного кода нашей DLL. Кроме того, его нужно

поставлять вместе со своей DLL, чтобы другие разработчики могли включать

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

переменные. Единый заголовочный файл, используемый при сборке DLL и

любых исполняемых модулей, существенно облегчает поддержку приложения.

При компиляции исходного файла DLL MYLIBAPI определяется как

__declspec (dllexport) до включения заголовочного файла MyLib.h. Такой

модификатор означает, что данная переменная, функция или C++ класс

экспортируется из DLL.

Также следует обратить внимание, что в файле MyLibFile1.cpp перед

экспортируемой переменной или функцией не ставится идентификатор

MYLIBAPI. Он здесь не нужен: проанализировав заголовочный файл,

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

экспортируемыми.

Идентификатор MYLIBAPI включает extern. Модификатор extern не даёт

компилятору искажать имена переменных или функции, и они становятся

доступными исполняемым модулям, написанным на С, С++ или любом другом

языке программирования. Этим модификатором можно пользоваться только в коде С++, но ни в коем случае ни в коде на стандартном С.

Мы рассмотрели, как используется заголовочный файл в исходных файлах

DLL.

А в исходных файлах ЕХЕ-модуля MYLIBAPI определять не надо: включая

заголовочный файл, вы определяете этот идентификатор как –

DLLSPEC(DLLIMPORT), и при помещении исходного кода ЕХЕ-модуля

компилятор поймёт, что переменные и функции импортируются из DLL.

Что такое экспорт

Если перед переменной, прототипом функции или С++ классом указан

модификатор – _deсlspec(dllexport), компилятор Microsoft C/C++ встраивает

в конечный obj-файл дополнительную информацию. Она понадобится при

сборке DLL из OBJ-файлов.

Обнаружив такую информацию, компоновщик создает LIB-файл со списком

идентификаторов, экспортируемых из DLL. Этот LIB-файл нужен при сборке

любого EXE-модуля, ссылающегося на такие идентификаторы. Компоновщик

также вставляет в конечный DLL-файл таблицу экспортируемых

идентификаторов – раздел экспорта, в котором содержится список (в

алфавитном порядке) идентификаторов экспортируемых функций, переменных и классов. Туда же помещается относительный виртуальный адрес (relative

virtual address, RVA) каждого идентификатора внутри DLL-модуля.

Создание EXE-модуля

Вот пример исходного кода EXE-модуля, который импортирует

идентификаторы, экспортируемые DLL, и ссылается на них внутри в процессе

выполнения.

//Модуль: MyExeFilel.cpp

//Сюда включаются стандартные заголовочные файлы Windows и

библиотеки С

#include <windows.h>

//включаем экспортируемые структуры данных, идентификаторы,

функции и переменные

#include “MyLib\MyLib.h”

….

int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE,

LPTSTR pszCmdLine, int)

{

int nLeft=10, nRight=25;

TCHAR sz[100];

wsprintf(sz, TEXT(“%d + %d = %d”), nLeft, nRight,

Add(nLeft, nRight));

MessageBox(NULL, sz, TEXT(“Calculation”), MB_OK);

wsprintf(sz, TEXT(“The result from the last Add is: %d”),

g_nResult);

MessageBox(NULL, sz, TEXT(“Last Result”), MB_OK);

return (0);

}

Создавая фалы исходного кода для EXE-модуля, нужно включить в них

заголовочный файл DLL, иначе импортируемые идентификаторы окажутся

неопределенными, и компилятор выдаст массу предупреждений об ошибках.

MYLIBAPI в исходных файлах EXE-модуля до заголовочного файла DLL не

определяется. Поэтому при компиляции приведенного выше кода MYLIBAPI за

счет заголовочного файла MyLib.h будет определен как __declspec(dllimport).

Встречая такой модификатор перед именем переменной, функции или С++

класса, компилятор понимает, что данный идентификатор импортируется из

какого-то DLL –модуля.

Далее компоновщик собирает все OBJ-модули в конечный EXE-модуль. Для

этого он должен знать, в каких DLL содержаться импортируемые

идентификаторы, на которые есть ссылки в коде. Информацию об этом он

получает из передаваемого ему LIB-файла (в котором указан список

идентификаторов, экспортируемых DLL)

Что такое импорт

Импортируя идентификатор, необязательно прибегать к

__declspec(dllimport) – можно использовать стандартное ключевое слово

extern языка С. Но компилятор создаст чуть более эффективный код, если ему

будет заранее известно, что идентификатор, на который мы ссылаемся,

импортируется из LIB-файла DLL –модуля.

Разрешая ссылки на импортируемые идентификаторы, компоновщик создаст

в конечном EXE-модуле раздел импорта (import section).

В нем перечисляются DLL, необходимые этому модулю, и идентификаторы,

на которые есть ссылки из всех используемых DLL.

Выполнение EXE-модуля

При запуске EXE-файла загрузчик операционной системы создает для его

процесса виртуальное пространство и проецирует на него исполняемый модуль.

Далее загрузчик анализирует раздел импорта и пытается спроецировать все

необходимые DLL на адресное пространство процесса.

Поскольку в разделе импорта указано только имя DLL (без пути), загрузчику

приходится самому искать ее на дисковых устройствах в компьютере

пользователя. Поиск DLL осуществляется в следующей последовательности:

1. Каталог, содержащий EXE-файл

2. Текущий каталог процесса

3. Системный каталог Windows

4. Основной каталог Windows

5. Каталоги, указанные в переменной окружения PATH

Проецируя DLL-модули на адресное пространство, загрузчик проверяет в

каждом из них раздел импорта. Если у DLL есть раздел импорта (что обычно и

бывает), загрузчик проецирует следующий DLL-модуль. При этом загрузчик

ведет учет загружаемых DLL, и проецирует их только один раз, даже если

загрузки этих DLL требуют и другие модули.

Найдя и спроецировав на адресное пространство процесса все необходимые

DLL-модули, загрузчик настраивает ссылки на импортируемые

идентификаторы. Для этого вновь просматривает разделы импорта в каждом

модуле, проверяя наличие указанного идентификатора в соответствующей

DLL.

Обнаружив идентификатор, загрузчик отыскивает его RVA и прибавляет к

виртуальному адресу, по которому данная DLL размещена в адресное

пространство процесса, а затем сохраняет полученный адрес в разделе импорта

EXE-модуля. И с этого момента ссылка в коде на импортируемый

идентификатор приводит к выборке его адреса из раздела импорта

вызывающего модуля, открывая таким образом доступ к импортируемой

переменной, функции или функции-члену С++ класса. Как только

динамические связи будут установлены, первичный поток процесса начинает

выполняться.

Загрузчик всех этих DLL и настройка ссылок занимает какое-то время.

Чтобы сократить время загрузки приложения нужно модифицировать базовые

адреса EXE- и DLL-модулей и провести их связывание.

Явная загрузка DLL и связывание идентификаторов

Чтобы поток мог вызвать функцию из DLL-модуля, DLL надо спроецировать

на адресное пространство процесса, которому принадлежит этот поток.

Делается это двумя способами:

1. Код приложения просто ссылается на идентификаторы, содержащиеся в

DLL, и тем самым заставляет загрузчик неявно загружать (и связывать)

нужную DLL при запуске приложения.

2. Явная загрузка и связывание требуемой DLL в период выполнения

приложения. Иначе говоря, поток явно загружает DLL в адресное

пространство процесса, получает виртуальный адрес необходимой DLL-

функции и взывает ее по этому адресу. Изящество этого подхода в том,

что все происходит в уже выполняемом приложении.

 

2. Блокировка файлов.

Важный вопрос в любой системе с несколькими процессами —

координация и синхронизация доступа к совместно используемым объектам,

например файлам.

Win32 может блокировать файлы полностью или частично, т.е. так, чтобы

никакой другой процесс (выполняемая программа) не мог обращаться к

блокированной области файла. Заблокированный файл может быть открыт

только для чтения (совместный доступ) или для чтения и записи (монопольный

доступ). Следует подчеркнуть, что блокировка связана с процессом. Любая

попытка обратиться к части файла (с помощью ReadFile или WriteFile) в

нарушение существующей блокировки потерпит неудачу, так как блокировка

обязательна на уровне процесса. Любая попытка получить конфликтную

блокировку также будет неудачной, даже если процесс уже имеет блокировку.

Блокировка файлов — это ограниченная форма синхронизации параллельных

процессов и потоков.

Наиболее общая функция блокировки LockFileEx реализована только в

Windows 2000/NT. Менее общая функция LockFile может применяться в

Windows 9x.

LockFileEx принадлежит к классу функций расширенного ввода-вывода;

для указания 64-разрядных позиций в файле и размера блокируемой области

требуется структура перекрытия, которая уже применялась ранее для указания

позиции в функциях ReadFile и WriteFile.

BOOL LockFileEx ( HANDLE hFile, DWORD dwFlags,

DWORD dwReserved, DWORD nNumberOfBytesToLockLow,

DWORD nNumberOfBytesToLockHigh,

LPOVERLAPPED lpOverlapped)

Функция LockFileEx блокирует область байтов в открытом файле для

совместного (несколько читающих процессов) или монопольного (один

читающий и пишущий процесс) доступа.

Параметры

hFile — дескриптор открытого файла. Дескриптор должен иметь права

доступа либо GENERIC_READ, либо GENERIC_READ и GENERIC_WRITE.

dwFlags определяет режим блокировки и устанавливает, следует ли

ожидать, пока блокировка не станет возможна.

• LOCKFILE_EXCLUSIVE_LOCK обозначает требование на

монопольную блокировку с возможностью чтения/записи. Если этот флаг

не установлен, запрашивается совместная блокировка (с возможностью

чтения).

• LOCKFILE_FAIL_IMMEDIATELY указывает, что функция должна

завершиться немедленно, возвратив значение FALSE, если блокировку

нельзя установить. Если этот флаг не установлен, вызов функции

блокируется, пока блокировка файла не станет возможна.

dwReserved должен быть равен нулю. Следующие два параметра задают

длину области байтов и поэтому здесь не поясняются.

lpOverlapped указывает на структуру типа OVERLAPPED, содержащую

начало области байтов. Структура OVERLAPPED содержит три компонента

данных, которые должны быть заданы (остальные компоненты игнорируются);

первые два определяют позицию начала блокируемой области.

• DWORD offset (именно так, а не OffsetLow).

• DWORD OffsetHigh.

• HANDLE hEvent должен быть равен нулю.

Блокировка файла снимается с помощью функции UnlockFileEx;

параметры для нее указываются те же самые, кроме dwFlags.

BOOL UnlockFileEx ( HANDLE hFile, DWORD dwReserved,

DWORD nNumberOfBytesToLockLow,

DWORD nNumberOfBytesToLockHigh,

LPOVERLAPPED lpOverlapped)

При блокировке файлов следует учитывать несколько факторов.

• Снятие блокировки должно относиться точно к такой же области, что и

предшествующая блокировка. Не допускается, например, разблокировать

две заблокированных ранее области или часть заблокированной области.

Попытка разблокировать область, которая не точно соответствует

существующей блокировке, потерпит неудачу; функция возвратит FALSE,

и системное сообщение укажет, что блокировки не существует.

• Блокировки не могут пересекаться с ранее блокированными областями

файла, если при этом возникает конфликт.

• Допускается блокировать область, выходящую за пределы файла. Этот

подход может быть полезен, когда процесс или поток расширяет файл.

• Блокировки не наследуются вновь создаваемым процессом.

В табл. 9.1 показана логика блокировки в случае, когда вся область или ее

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

блокировка принадлежит этому же процессу.

Таблица 9.1. Логика требования блокировки

Требуемый тип блокировки

Существующая

блокировка

Совместная

блокировка

Монопольная

блокировка

Нет Предоставляется Предоставляется

Совместная (одна

или несколько)

Предоставляется Предоставляется

Исключительная Не предоставляется Не предоставляется

В табл. 9.2 показана логика, применяемая в том случае, когда процесс

пытается выполнить чтение или запись в области файла с одной либо

несколькими блокировками, принадлежащими разным процессам, во всей или в

части области, допускающей чтение/запись. Неудачное чтение или запись

может принимать форму частично завершенной операции, если блокирована

только часть записи.

Таблица 9.2. Блокировки и операции ввода-вывода

Операция ввода-вывода Существующая блокировка

Чтение Запись

Нет Проходит успешно Проходит успешно

Совместная

(одна или

несколько)

Проходит успешно. Вызывающий процесс не обязательно

должен владеть блокировкой

Неудача

Исключительная

Проходит успешно, если блокировкой владеет вызывающий

процесс. В противном случае —неудача

Проходит успешно, если блокировкой владеет вызывающий

процесс. В противном случае —неудача

Операции чтения и записи обычно имеют форму функций ReadFile и

WriteFile или их расширенных версий ReadFileEx и WriteFileEx. Для

диагностики неудачи чтения или записи вызывается GetLastError.

Еще одна форма ввода-вывода — обращение к памяти, в которую

отображается файл. Конфликты блокировки не обнаруживаются при

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

MapViewOfFile. Эта функция делает часть файла доступной для процесса, а

потому в этот момент следует проверить блокировку.

LockFile — это ограниченная специальная версия функции блокировки.

Она обеспечивает рекомендательную блокировку (advisory locking). В этом

случае предоставляется только монопольный доступ и функция возвращает

управление немедленно. Иначе говоря, LockFile не блокируется. Установлена

ли блокировка, можно проверить по возвращаемому значению.

Снятие блокировки файла

За каждым успешным вызовом LockFileEx должно следовать одно

соответствующее ему обращение к UnlockFileEx (это правило

распространяется также на LockFile и UnlockFile). Если программа не может

снять блокировку или задерживает ее дольше, чем необходимо, другие

программы не смогут продолжать работу или же это негативно повлияет на их

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

спроектированы и реализованы так, чтобы блокировки снимались как можно

скорее; логики, которая заставляла бы программу обходить операцию разбло-

кировки, следует избегать.

Удобный способ убедиться, что блокировка снята, предоставляют

обработчики завершения.

 

3. Управление файлами и каталогами.

Создание и открытие файлов

Для создания и открытия файлов всех типов служит единственная

функция API Win32 – CreateFile. В приложении можно указать, будет ли

выполняться чтение из файла, запись в файл или и то и другое. Можно также

указать, предусматривается ли совместное использование этого файла для

чтения, записи либо для того и другого.

HANDLE CreateFile ( LPCTSTR lpszName, DWORD fdwAccess,

DWORD fdwShareMode, LPSECURITY_ATTRIBUTES lpsa,

DWORD fdwCreate, DWORD fdwAttrsAndFlags,

HANDLE hTemplateFile)

Возвращаемое значение: дескриптор объекта открытого файла или

INVALID_HANDLE_FAILURE в случае неудачи.

Параметры

lpszName – указатель на строку, содержащую имя файла, канала или

другого именованного объекта, который требуется открыть или создать

fdwAccess определяет режим доступа для чтения или записи значениями

GENERIC_READ и GENERIC_WRITE соответственно. Могут использоваться

другие имена констант. Эти значения можно объединить с помощью

поразрядного “или”.

fdwShareMode – это объединение поразрядным “или” сочетание

приведенных ниже значений:

- 0 – совместный доступ к файлу не допускается.

- FILE_SHARE_READ – другие процессы, включая тот, что сделал данный

вызов, могут открывать этот файл для параллельного чтения.

- FILE_SHARE_WRITE – разрешается параллельная запись в файл.

Используя блокировку или другие механизмы, программист должен не

допустить параллельных модификаций одного и того же файла.

lpsa указывает на структуру SECURITY_ATTRIBUTES.

fdwCreate определяет, надо ли создать новый файл, заменить

существующий файл и т.д. Отдельные значения можно объединить оператором

поразрядного “или”.

- CREATE_NEW – завершается неудачей, если указанный файл уже

существует; иначе создается новый файл.

- CREATE_ALWAYS – существующий файл заменяется новым.

- OPEN_EXISTING – неудача, если файл не существует.

- OPEN_ALWAYS – файл открывается и создается, если он не существует.

- TRUNCATE_ EXISTING – устанавливается нулевая длина файла. В

fdwAccess должен быть задан по крайней мере доступ GENERIC_WRITE.

fdwAttrsAndFlags определяет атрибуты и флаги. Существует 16 флагов и

атрибутов. Атрибуты – это характеристики файла, а не открытого дескриптора

HANDLE; они игнорируются, когда открывается существующий флаг. Ниже

перечислены некоторые важные атрибуты и флаги.

- FILE_ATTRIBUTE_NORMAL – может использоваться, только если не

установлены никакие другие атрибуты (однако флаги могут быть

установлены).

- FILE_ATTRIBUTE_ READONLY – приложения не могут не писать в файл,

ни удалять его.

- FILE_FLAG_DELITE_ON_CLOSE – полезен для временных файлов. Файл

удаляется, когда закрывается его последний открытый дескриптор.

- FILE_FLAG_OVERLAPPED – важен для асинхронного ввода-вывода. В

Windows он имеет значение NULL всегда, кроме устройств

последовательного ввода-вывода.

Еще несколько дополнительных флагов определяют способ обработки файла

и позволяют Win32 оптимизировать быстродействие и целостность файла.

- FILE_FLAG_WRITE_THROUGH – промежуточные кэши немедленно

записываются в файл на диске.

- FILE_FLAG_NO_BUFFERING – в пространстве пользователя не

выполняется буферизация и кэширование, и данные передаются

непосредственно в буфера программы и из них.

- FILE_FLAG_RANDOM_ACCESS – файл предназначен для произвольного

доступа, и Windows будет пытаться оптимизировать кэширование файла.

- FILE_FLAG_SEQUENTIAL_SCAN – файл предназначен для

последовательного доступа, и Windows соответственно оптимизирует

кэширование. Эти два режима доступа не обязательны.

hTemplateFile – дескриптор файла, открытого с GENERIC_READ,

определяющий расширенные атрибуты для вновь создаваемого файла, причем

значения fdwAttrsAndFlags игнорируются. Обычно этот параметр равен NULL.

Параметр hTemplateFile игнорируется, когда открывается существующий файл.

С помощью этого параметра можно сделать так, чтобы атрибуты нового файла

были такими же, как у существующего.

Закрытие файлов.

Дескрипторы закрываются и системные ресурсы освобождаются почти для

всех объектов одной универсальной функцией. При закрытии дескриптора

также уменьшается на единицу счетчик ссылок объекта.

BOOL CloseHandle (HANDLE hObject)

Возвращаемое значение: TRUE, если функция выполняется успешно; иначе

FALSE.

Чтение файлов.

BOOL ReadFile ( HANDLE hFile, LPVOID lpBuffer,

DWORD nNumberOfBytesToRead, LPDWORD

lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)

Возвращаемое значение: TRUE, если чтение завершается успешно.

Параметры.

hfile – дескриптор файла с доступом GENERIC_READ

lpBuffer указывает на буфер памяти для получения входных данных.

nNumberOfBytesToRead – количество байтов, которые нужно прочитать

из файла.

lpNumberOfBytesRead – указывает на фактическое число байтов,

прочитанное функцией ReadFile.

lpOverlapped указывает на структуру OVERLAPPED.

Запись в файл.

BOOL WriteFile ( HANDLE hFile, CONST VOID *lpBuffer,

DWORD nNumberOfBytesToWrite, LPDWORD

lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)

Возвращаемое значение: TRUE, если функция завершается успешно, иначе

FALSE.

Win32 содержит множество функций управления файлами.

Для удаления файла:

BOOL DeleteFile (LPCTSTR lpszFileName)

Копирование файла:

BOOL CopyFile (LPCTSTR lpszExistingFile,

LPCTSTR lpszNewFile, BOOL fFaillfExists)

CopyFile копирует определенный по имени существующий файл и

присваивает копии указанное новое имя. Если файл с новым именем уже

существует, он будет заменен, только если fFailIfExists равно FALSE.

Еще две функции служат для переименования, или "перемещения", файла.

Эти функции также могут работать с каталогами.

BOOL MoveFile ( LPCTSTR lpszExisting,

LPCTSTR lpszNew) ;

BOOL MoveFileEx ( LPCTSTR lpszExisting,

LPCTSTR lpSzNew, DWORD fdwFlags)

MoveFile завершается неудачно, если новый файл уже существует; для

существующих файлов следует применять MoveFileEx.

Параметры

lpszExisting определяет имя существующего файла или каталога.

lpszNew определяет имя нового файла или каталога, который в MoveFile

не должен существовать. Новый файл может находиться в другой файловой

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

Если этот параметр имеет значение NULL, существующий файл удаляется.

fdwFlags определяет следующие опции:

• MOVEFILE_REPLACE_EXISTING — используется для замены

существующего файла;

• MOVEFILE_WRITETHROUGH — гарантирует, что функция не возвращает

управление, пока скопированный файл не будет переписан из

промежуточного буфера на диск;

• MOVEFILE_COPY_ALLOWED — когда новый файл находитсяна другом

томе, перемещение осуществляется путем выполнения CopyFile и

DeleteFile;

• MOVEFILE_DELAY_UNTIL_REBOOT — этот флаг, который не может

применяться вместе с MOVEFILE _ COPY _ ALLOWED , разрешен только для

администраторов и задерживает фактическое перемещение файла до

перезапуска системы.

Перемещение (переименование) файлов связано с несколькими важными

ограничениями.

• Поскольку в Windows 9x не реализована функция MoveFileEx, ее

необходимо

заменять последовательностью CopyFile и DeleteFile. Это означает, что

в какой-то момент времени будут существовать две копии, что может

вызвать проблемы при почти заполненном диске или большом файле. Этот

способ влияет на атрибуты файла иначе, чем "настоящее" перемещение.

• В именах файлов или каталогов не допускаются подстановочные знаки.

Следует указывать конкретное имя.

 




Читайте также:
Как вы ведете себя при стрессе?: Вы можете самостоятельно управлять стрессом! Каждый из нас имеет право и возможность уменьшить его воздействие на нас...
Генезис конфликтологии как науки в древней Греции: Для уяснения предыстории конфликтологии существенное значение имеет обращение к античной...



©2015-2020 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (370)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.008 сек.)