Главная > Методическое пособие


6. Лабораторная работа №5

6.1. Цель работы

Ознакомиться с основными концепциями объектной модели компонентов (COM). Получить практические навыки написания встраиваемых в процесс COM серверов на примере реализации интерфейсов расширения оболочки Windows 9x/NT/2000.

6.2. Основные теоретические положения

6.2.1. Краткие сведения о COM

Объектная модель компонентов (Component Object Model – COM) это платформонезависимая, распределенная, объектно-ориентированная система, предназначенная для разработки взаимодействующих друг с другом двоичных программных компонентов. COM является фундаментальной основой многих распространенных технологий, включая ActiveX и OLE.

COM не является объектно-ориентированным языком программирования, а является стандартом. COM также не определяет структуру приложения. Язык, структура и детали реализации выбираются программистом. COM лишь определяет объектную модель и требования к программе, которые позволяют COM объектам (называемыми также COM компонентами или иногда просто объектами) осуществлять взаимодействие с другими объектами. Эти объекты могут присутствовать в едином процессе, в различных процессах или даже на различных компьютерах в сети. Объекты могут быть написаны на различных языках программирования, и их структуры могут сильно различаться. Вот почему о COM говорят, как о двоичном стандарте – это стандарт, применяемый после компиляции программы в двоичный машинный код.

Единственным требованием, предъявляемым COM к языку программирования, является возможность создания структур указателей и вызов функций через указатели. Объектно-ориентированные языки программирования, такие как C++ и Smalltalk, включают программные средства, упрощающие написание COM объектов. Однако, такие языки, как C, Pascal, Ada, Java и даже Basic также позволяют создавать и использовать COM объекты.

Модель COM определяет структуру COM объекта. В общих чертах, программный объект состоит из набора данных и функций, манипулирующих данными. COM объект – это такой объект, в котором доступ к данным осуществляется исключительно через набор соответствующих функций. Такие наборы функций называются интерфейсами, а отдельные функции интерфейса называются методами. Более того, COM требует, чтобы доступ к методам интерфейса осуществлялся только через указатель на этот интерфейс.

Помимо спецификации двоичного объектного стандарта, COM определяет некоторые основные интерфейсы, предоставляющие функции, общие для всех технологий, основанных на COM. COM также предоставляет небольшой набор API функций, необходимых для всех компонентов. Существуют расширения модели COM, обеспечивающие взаимодействие объектов в распределенном окружении, использующих различные методы защиты информации.

В данной лекции рассматриваются основные аспекты COM по отношению к разработке COM объектов.

6.2.2. COM объекты и интерфейсы

COM является технологией, позволяющей объектам взаимодействовать в рамках процессов и компьютеров так же легко, как взаимодействуют объекты в пределах одного и того же процесса. COM позволяет осуществить это взаимодействие путем манипулирования данными объекта исключительно через интерфейсы объектов. При использовании данного термина подразумевается, что реализация кода двоично-совместимого COM интерфейса связана с объектом.

Если говорить об объекте, реализующем интерфейс, это означает, что объект использует код, реализующий каждый метод интерфейса и, предоставляющий двоично-совместимые COM указатели на эти функции COM библиотеке. COM, в свою очередь, делает соответствующие функции доступными всем клиентам, запрашивающим указатель на интерфейс в независимости от того, находится ли клиент внутри или вне процесса, реализующего данные функции.

COM делает различие между определением интерфейса и его реализацией. Интерфейс это просто соглашение, состоящее из некоторого набора прототипов функций, для которых определено их использование, но не реализация. Интерфейсы аналогичны чистым виртуальным базовым классам в языке C++. Определение интерфейса включает описание функций интерфейса, называемых методами, значения, возвращаемые этими функциями, а также количество и типы параметров. В интерфейсе отсутствует реализация его методов.

Реализация интерфейса представляет собой программный код, используемый для выполнения действий, предписанных функциям интерфейса. Реализации множества интерфейсов, которые программист может использовать в объектно-ориентированном приложении, включаются в COM библиотеки. Программист, однако, может написать и свою реализацию необходимого интерфейса. Реализация интерфейса связывается с объектом при создании его экземпляра, и предоставляет услуги, определяемые возможностями объекта.

Простые объекты могут поддерживать только один интерфейс. Более сложные объекты обычно поддерживают несколько интерфейсов. Клиенты имеют доступ к COM объекту только через указатель на один из его интерфейсов, что позволяет клиентам вызывать методы конкретного интерфейса. Методы определяют использование клиентами данных объекта.

Интерфейсы, в свою очередь, определяют соглашение между объектом и его клиентами. Соглашение указывает методы, которые должны быть связаны с соответствующим интерфейсом, а также параметры методов и возвращаемые ими значения. Соглашение, однако, не определяет то, каким образом реализовывать методы интерфейса. Другим важным аспектом соглашения является то, что если объект поддерживает интерфейс, он должен каким-либо образом поддерживать все методы интерфейса. Не обязательно, чтобы реализация каждого метода выполняла какие-либо действия – если объект не поддерживает функционал метода, реализация метода может просто возвращать управление, либо возвращать сообщение об ошибке. В любом случае реализация метода должна существовать.

Экземпляр реализации интерфейса представляет собой указатель на массив указателей на методы (таблица функций, связанная с реализацией всех методов конкретного интерфейса). Объекты с несколькими интерфейсами могут предоставлять указатели на несколько таблиц функций. Любая часть кода программы, имеющая указатель на таблицу функций, может вызывать методы интерфейса.

Обычно указатель на таблицу функций интерфейса называется просто указателем на интерфейс. Таблицы функций можно создать вручную в языке C и в большей степени автоматически в C++ (а также в любом другом объектно-ориентированном языке программирования, поддерживающим COM).

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

Ссылки на интерфейс во время выполнения программы определяются при помощи глобального уникального идентификатора интерфейса (Interface Identifier – IID). IID, являющийся экземпляром GUID (Globally Unique Identifier – глобальный уникальный идентификатор) позволяет клиенту точно узнать, поддерживает ли объект тот или иной интерфейс. Использование IID необходимо, поскольку в системе могут присутствовать несколько версий одного и того же интерфейса с одинаковыми именами.

Обобщим вышесказанное относительно интерфейса:

  • Интерфейс – это не то же самое, что и класс в языке C++;

  • Интерфейс – это не объект;

  • Интерфейсы строго типизированы;

  • Интерфейсы неизменяемы.

6.2.3. Интерфейс IUnknown и наследование инерфейсов

Наследование в COM не подразумевает повторное использование программного кода. Поскольку с интерфейсами не связаны реализации, наследование интерфейсов не означает наследование программного кода. Наследование означает только, что соглашение, связанное с интерфейсом, наследуется в стиле чистых виртуальных классов языка C++ и изменяется либо добавлением новых методов, либо модификацией их прототипов. В COM не существует выборочного наследования: если один интерфейс наследует другой, он включает в себя все методы этого интерфейса.

Наследование широко используется в предопределенных COM интерфейсах. Все предопределенные интерфейсы (и любые интерфейсы, определяемые программистом) наследуют свои определения от важного интерфейса IUnknown. Этот интерфейс содержит три виртуальных метода: QueryInterface, AddRef и Release. Все COM объекты должны реализовывать интерфейс IUnknown, поскольку он обеспечивает возможность переключения между несколькими интерфейсами, поддерживаемыми объектом (для этого используется метод QueryInterface). Также интерфейс IUnknown позволяет контролировать время жизни объекта при помощи методов AddRef и Release.

Не смотря на то, что малое количество интерфейсов наследуют свои определения от другого интерфейса, кроме IUnknown, основная идея наследования проста – интерфейс включает в себя методы IUnknown, методы, наследованные от других интерфейсов и свои собственные методы. Это делает большинство интерфейсов достаточно компактными и простыми для инкапсуляции.

6.2.4. Назначение IUnknown::QueryInterface

Обычно исходный указатель на интерфейс объекта клиент получает при создании объекта. Имея исходный указатель, клиент может получить указатели на другие интерфейсы объекта, методы которых ему необходимо вызывать. Для этого клиент запрашивает у объекта эти указатели с помощью IUnknown::QueryInterface.

Чтобы воспользоваться QueryInterface, клиент вызывает его с помощью любого из имеющихся у него в данный момент указателей на интерфейсы объекта. Клиент передает IID нужного ему интерфейса как параметр метода. Например, пусть у клиента уже имеется указатель на интерфейс А, и требуется получить указатель на интерфейс В. Клиент запрашивает данный указатель вызовом QueryInterface через указатель А, задавая в качестве параметра IID интерфейса В (шаг 1). Если объект поддерживает В, то он возвращает указатель на этот интерфейс (шаг 2), и клиент может теперь может вызывать методы В (шаг 3). Если же объект не поддерживает В, он возвращает NULL.

Вообще говоря, самый важный элемент СОМ — QueryInterface. Именно эта простая схема решает очень важную и сложную проблему — контроль версий. В современной практике программирования создание программ на основе СОМ-объектов — обычное дело. Объекты, составляющие приложения, создаются множеством организаций, каждая из которых модернизирует свои объекты независимо от остальных. Как все это будет работать, если новые возможности добавляются в разные объекты в разное время? Как установить новую версию объекта с расширенными возможностями, не повредив программам, использующим только старые возможности? И как после модернизации клиента под новые возможности обеспечить автоматическое начало их использования этим клиентом? Ответ на все эти вопросы дает QueryInterface.

Лучше всего продемонстрировать это на примере. Допустим, имеется некий набор инструментов обработки текста, реализованный в виде СОМ-объекта, поддерживающего интерфейс ISpellChecker. Если установить такой объект на компьютер, текстовый процессор (и другие клиенты) сможет его использовать. Чтобы получить доступ к сервисам объекта, текстовый процессор запрашивает указатель на ISpellChecker через QueryInterface. Так как объект поддерживает этот интерфейс, то возвращает соответствующий указатель, и текстовый процессор вызывает методы ISpellChecker.

Теперь допустим, что фирма, продающая этот объект — инструментарий для обработки текста — решила добавить поддержку словаря синонимов, доступ к которой можно получить через интерфейс IThesaurus. Таким образом, следующая версия объекта поддерживает как ISpellChecker, так и IThesaurus. После установки на машине этой новой версии, все будет работать так же, как и раньше. Текстовый процессор, как обычно, запрашивает указатель на ISpellChecker и успешно пользуется его методами. То, что объект теперь поддерживает еще и IThesaurus, неизвестно текстовому процессору, так как он не поддерживает работы со словарем синонимов. Следовательно, старый текстовый процессор никогда не запросит у объекта указатель на этот интерфейс.

Предположим теперь, что на машине установлена новая версия текстового процессора, поддерживающая работу со словарем синонимов. Когда в следующий раз пользователь вызовет старый текстовый процессор, он, как обычно, запустит объект — инструментарий для обработки текста и запросит указатель на интерфейс ISpellChecker. Однако новая версия текстового процессора обладает информацией, достаточной для того, чтобы запросить указатель на IThesaurus. Так как версия объекта, которая поддерживает данный интерфейс, была установлена ранее, нужный указатель будет возвращен, и текстовый процессор сможет воспользоваться новой функцией. Итак, в итоге установлена новая версия инструментария для обработки текста, не нарушающая при этом работы существующих его клиентов, а также обеспечено автоматическое использование этими клиентами функций новой версии, после того как сами клиенты были обновлены.

Что делать в случае установки новой версии текстового процессора, без приобретения новой версии инструментария для обработки текста? Все также работает за исключением того, что текстовый процессор не предоставляет таким пользователям возможностей словаря синонимов. Текстовый процессор запускает объект-инструментарий и через QueryInterface успешно получает указатель на ISpellChecker. Однако, запрашивая указатель на IThesaurus, он получает в ответ NULL. Если текстовый процессор написан с учетом подобной возможности, он отключает пункт меню Thesaurus. Поскольку объект, реализующий IThesaurus, отсутствует, у пользователя не будет доступа к функциям словаря синонимов. Как только пользователь установит модернизированный объект — инструментарий для обработки текста – этот пункт меню будет активизирован без каких-либо изменений в текстовом процессоре.

Рассмотрим еще один пример. Что, если создатель объекта — инструментария для обработки текста — пожелает изменить или расширить функциональные возможности объекта по корректировке орфографии? Это влечет за собой изменение или добавление новых методов, которые будут видимы клиенту объекта. Однако СОМ не разрешает изменять интерфейсы, поэтому существующий интерфейс ISpellChecker изменять нельзя. Вместо этого создатель объекта должен определить новый интерфейс, скажем, ISpellChecker2, и включить в него необходимые новые или измененные методы. Объект по-прежнему поддерживает ISpellChecker, но теперь он также будет поддерживать и ISpellChecker2. Добавление в объект поддержки ISpellChecker2 ничем не отличается от добавления поддержки любого нового интерфейса. Как и все СОМ-интерфейсы, новый имеет уникальный IID, который клиент, знающий о новом интерфейсе, может использовать для запроса указателя через QueryInterface. Как и в предыдущем случае с IThesaurus, клиенты, ничего не знающие о произошедшей модернизации, никогда не запросят указатель на ISpellChecker2, и не ощутят никакого воздействия со стороны изменений — они будут продолжать использовать ISpellChecker.

Querylnterface и требование неизменности интерфейсов СОМ позволяют программным компонентам, разрабатываемым независимыми организациями, обновляться по отдельности и, тем не менее, продолжать нормальную совместную работу. Это соображение трудно считать несущественным, и именно поэтому создатели СОМ иногда называют QueryInterface важнейшим элементом модели.

6.2.5. Подсчет ссылок

Чтобы воспользоваться СОМ объектом, клиент должен явно инициировать начало работы экземпляра этого объекта. Здесь возникает естественный вопрос: «Когда завершается работа объекта?» Кажется, очевидное решение — возложить на клиента, запустивший объект на выполнение, еще и обязанность сообщить объекту, когда тот должен остановиться. Однако данное решение не работает, так как данный клиент может со временем оказаться не единственным, кто этот объект использует. Весьма распространена практика, когда клиент запускает выполнение объекта, получает указатели на его интерфейсы и затем передает один из них другому клиенту. Последний может использовать указатель для исполнения методов в том же самом объекте, а также в свою очередь передать указатель другим клиентам. Если бы первый клиент мог деинициализировать экземпляр объекта по своему желанию, то положение остальных клиентов было бы затруднительным — исчезновение объекта в тот момент, когда его сервисы используются, в лучшем случае привело бы к программной ошибке.

В то время как один объект может использоваться несколькими клиентами одновременно, никто из них не в состоянии узнать, когда все остальные завершатся. Так что разрешить клиенту деинициализировать объект напрямую — небезопасно. Только сам объект может знать, когда он может безопасно завершить свою работу, и только в том случае, если все клиенты сообщают объекту, что они завершили работу с ним. Такой контроль объекты осуществляют с помощью механизма подсчета ссылок (reference counting), поддерживаемого двумя методами интерфейса IUnknown.

Каждый исполняющийся объект поддерживает счетчик ссылок. Всякий раз, выдав указатель на один из своих интерфейсов, объект увеличивает счетчик ссылок на 1 (вообще объект может поддерживать отдельные счетчики ссылок для каждого интерфейса СОМ). Если один клиент передает указатель интерфейса другому клиенту, т. е. увеличивает число пользователей объекта без оповещения последнего, то клиент, получающий указатель, должен вызвать с помощью этого указателя метод AddRef. В результате объект увеличивает свой счетчик ссылок. Независимо от того, как он получил указатель на интерфейс, клиент всегда обязан вызвать для этого указателя метод Release, закончив с ним работу. Исполнение этого метода объектом состоит в уменьшении числа ссылок на 1. Обычно объект уничтожает сам себя, когда счетчик ссылок становится равным 0.

Подсчет ссылок может вызывать проблемы. Если не все клиенты следуют правилам, то экземпляр объекта может либо существовать неопределенно долго, либо, что еще хуже, быть преждевременно удаленным. И все-таки подсчет ссылок выглядит единственным работающим способом управления временем жизни объектов в многопоточной и динамичной среде, которую позволяет создать СОМ.

6.2.6. Классы

Всякий СОМ-объект является экземпляром некоторого класса, и каждому классу может быть присвоен GUID-идентификатор класса (CLSID). Клиент может передавать этот CLSID библиотеке СОМ для создания экземпляра класса. Однако наличие CLSID не обязательно для всех классов — объекты некоторых классов не создаются с помощью библиотеки СОМ, поэтому такие классы не обязаны иметь CLSID. Допустимо существование в любой данный момент времени одного, двух или многих активных объектов некоторого класса.

Связь между классом объекта и интерфейсами, которые этот объект поддерживает, не очень очевидна. Естественно было бы предположить, что объект данного класса поддерживает определенный набор интерфейсов, и что добавление к объекту нового интерфейса изменяет его класс. Однако это не обязательно — добавление новых интерфейсов к объекту без изменения его класса не запрещается СОМ. Вместо этого основным назначением CLSID является идентификация некоторого фрагмента кода для библиотеки СОМ, чтобы можно было загружать и активизировать объекты данного класса. В СОМ класс объектов идентифицирует некую реализацию группы интерфейсов, а не просто саму эту группу. Предположим, что объект — инструментарий для работы с текстом — решили реализовать два разных производителя, и оба созданных ими объекта поддерживают как ISpellChecker, так и IThesaurus. Хотя эти объекты и поддерживают одинаковый набор интерфейсов, они относятся к разным классам с разными CLSID, так как их реализации различны.

6.2.7. Серверы СОМ объектов

Каждый СОМ объект реализован внутри некоторого сервера, содержащего код, который реализует методы интерфейсов объекта, а также контролирует данные объекта, пока тот активен. Один сервер может поддерживать более одного объекта некоторого класса и даже поддерживать несколько классов. Рассмотрим три основные типа серверов:

Сервер «в процессе» (in-process): объекты реализуются в динамически подключаемой библиотеке, и, таким образом, исполняются в том же процессе и адресном пространстве, что и клиент.

Локальный сервер (out-process): объекты реализованы в отдельном процессе, исполняющемся на той же машине, что и клиент.

Удаленный сервер: объекты реализованы в DLL либо в отдельном процессе, которые расположены на удаленном по отношению к клиенту компьютере. Возможность создания таких серверов поддерживает распределенная СОМ (DCOM).

С точки зрения клиента, объекты, реализованные в любой из трех разновидностей серверов, выглядят одинаково. Доступ к методам объектов клиент по-прежнему осуществляет через указатели интерфейсов. При необходимости он может проводить различие между разными типами серверов, но это не обязательно. Запуск объекта, получение указателей на его интерфейсы, вызов их методов и освобождение указателей выполняются клиентом одинаково независимо от того, каким сервером реализован объект: «в процессе», локальным или удаленным.

6.2.8. СОМ и многопоточность

В традиционном простом процессе в один и тот же момент времени выполняется только одно действие. Другими словами, у процесса имеется только один поток выполнения (thread of execution). Однако иногда полезно обеспечить выполнение процессом нескольких задач одновременно. С этой целью у процесса может быть более одного потока выполнения, т. е. он становится многопоточным (multithreaded). Многопоточный процесс может повысить производительность, например, в тех случаях, когда в компьютере установлено несколько процессоров и процесс может назначать потоки на разные процессы. Многопоточность может также использоваться в распределенной среде, где процесс на одной машине выполняет запрос к другой. Вместо того, чтобы ждать, пока вторая машина отработает запрос, вызывающий процесс может использовать отдельный поток для выполнения полезной работы, пока запрос не будет выполнен. Многопоточность вносит дополнительные сложности и в программирование. Программист должен учитывать возможность возникновения конфликтов внутри процесса, когда, например, два потока пытаются изменять одну и ту же переменную. Корректная обработка таких ситуаций требует дополнительных усилий. Библиотеки, используемые многопоточными программами, также должны быть многопоточными, иначе могут возникнуть трудные для локализации ошибки. Одна из причин сложности локализации таких ошибок в том, что их трудно воспроизвести. Так как детали выполнения потока могут изменяться от одного запуска программы к другому, точные обстоятельства проявления ошибки могут возникать лишь от случая к случаю.

На некоторых платформах, где СОМ использовалась первоначально (Microsoft Windows 3.x и Macintosh), вопрос потоков не возникает. Так как ни одна из этих операционных систем не поддерживает потоки, то и опасности, связанные с ними, отсутствуют. Но Microsoft Windows 9x и Microsoft Windows NT, как и другие платформы, поддерживающие СОМ, допускают создание многопоточных процессов, поэтому для эффективного использования СОМ в таких средах необходимо учитывать вопросы, связанные с потоками.

Первым подходом, применявшимся для обеспечения создания многопоточных СОМ объектов, была модель комнат (apartment model). Основная идея заключается в том, что хотя процесс и может быть многопоточным, отдельные объекты СОМ — нет. Каждый поток выступает как «комната», и каждый объект СОМ находится только в одной такой комнате (т. е. одном потоке). Методы объекта могут вызываться только этим потоком — вызовы из других потоков помещаются в очередь и затем последовательно обрабатываются потоком, в котором располагается объект.

Модель комнат, несомненно, полезна, но не лишена недостатков. Возможность наличия в процессе нескольких потоков удобна, но еще большие выгоды можно получить, обеспечив параллельный доступ к любому объекту СОМ из многих потоков. Соответствующая поддержка — свободные потоки (free threading), или просто многопоточность — появилась с выходом в 1996 году Windows NT версии 4.0. При использовании свободных потоков внутри данного СОМ объекта может выполняться несколько потоков одновременно. Программист, пишущий код для такого объекта, должен позаботиться и о многопоточной безопасности, но если это сделано, СОМ более не ограничивает выполнение методов объекта единственным потоком.

6.2.9. Создание СОМ объектов

До этого места в изложении материала предполагалось, что клиент уже каким-либо образом получил исходный указатель на один из интерфейсов исполняющегося объекта. Конкретный способ получения клиентом этого указателя не обсуждался. В действительности способов несколько. Например, указатель может быть передан другим клиентом. Тем не менее, для каждого объекта имеется некоторой клиент, создающий его и получающий самый первый указатель интерфейса. В конечном счете, данный процесс основывается на использовании функций библиотеки СОМ.

Любой процесс, использующий COM должен инициализировать и деинициализировать библиотеку COM. COM реализует некоторые важные сервисные возможности в специальной COM библиотеке. Эта библиотека представлена набором динамических библиотек и исполнительных файлов (основными файлами являются OLE32.DLL и RPCSS.EXE). В ОС Microsoft Windows библиотека COM включает следующие компоненты:

  • Небольшое количество базовых API функций, позволяющих создавать COM приложения, как клиентские, так и серверные. Для клиентских приложений COM обеспечивает базовые функции создания объектов. Для серверных приложений COM обеспечивает средства реализации объектов.

  • Службы локализации реализаций, через которые COM по уникальному идентификатору класса (CLSID) определяет какой сервер реализует данный класс и где этот сервер расположен.

  • Прозрачные для приложений механизмы вызова удаленных процедур, используемые в том случае, когда объект находится на удаленной машине.

  • Стандартный механизм, позволяющий приложению контролировать процесс распределения памяти. Обычно такая память используется совместно взаимодействующими друг с другом объектами.

Для использования базовых сервисных возможностей COM, все клиентские и серверные потоки COM, должны вызвать функцию CoInitialize или CoInitializeEx перед тем, как вызывать другие функции COM использующие распределение памяти. Однако встраиваемые в процесс COM серверы могут не вызывать функцию CoInitialize, так как это уже было сделано тем процессом, в который встроен сервер. Поэтому встраиваемые в процесс COM серверы должны указывать тип потоковой модели в ключе реестра InprocServer32.



Скачать документ

Похожие документы:

  1. Том 2 документации об аукционе для проведения открытого аукциона для субъектов малого предпринимательства

    Инструкция
    ... с некоторыми операционными системами) - Вес ... Методическое пособие по ... пособием и предназначена для использования на учебных занятиях по химии, и другим общеобразовательным дисциплинам ... выполнения лабораторных работ по биологии» ... (лота), указанным в томе ...
  2. Ищите тесты не только по названиям

    Тесты
    ... методического) уровня системы ... работой всех устройств ПК и процессом выполнения прикладных программ, называется 3. Операционные системы ... дисциплины ... , лабораторное оборудование ... пособия по ... по достижении: 108. Выполнение налогоплательщиком письменных указаний ...
  3. Постановление исполнительного комитета г казани 30 06 2009 №5258 об утверждении стандарта муниципальной услуги «предоставление общедоступного бесплатного начального общего основного общего среднего (полного) общего образования по основным

    Программа
    ... Д Д - 1.4 Методическое пособие для учителя К К - 1.5 Рабочие тетради по физике Д Д - 1.6 Хрестоматия по физике К** К** По возможности 1.7 Комплекты пособий для выполнения лабораторных ...
  4. III ПРИРОДНЫЙ ЗАКОН ПИТАНИЯ ЧЕЛОВЕКА

    Закон
    ... операционный ... указанный срок подлежат увольнению по профессиональной непригодности. Обязательно выполнение ... системы и системы обмена веществ, нарушается работа всей пищеварительной системы ... наглядные пособия, ... “Дисциплина” ... методически ... У лабораторных мышей ...
  5. Методическое пособие по по дисциплине «теоретические основы автоматизированного управления» и указания к выполнению лабораторных работ

    Методическое пособие
    ... Методическое пособие по по дисциплине «Теоретические основы автоматизированного управления» и указания к выполнению лабораторных работ Номер специальности – 230102 «Автоматизированные системы ... и под различными операционными системами. При этом ...

Другие похожие документы..