Разработка службы Windows "Контроль приложений"
Проектирование, кодирование и отладка службы Windows: "Контроль приложений", осуществляющей контроль набора приложений и управление ими; разработка приложения, управляющего этой службой. Взаимодействие службы и приложения; тестирование и сопровождение.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 22.05.2013 |
Размер файла | 1,1 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Размещено на http://www.allbest.ru/
ГОУ ВПО
Сургутский государственный университет Ханты-Мансийского Автономного Округа - Югры
Факультет автоматики и телекоммуникаций
Кафедра автоматики и компьютерных систем
Пояснительная записка
к курсовому проекту по дисциплине
Системное программное обеспечение
Выполнил: Скиву А.И.
студент группы 1281
Проверил: к.т.н., доцент
Даниленко И.Н.
Сургут 2011
Содержание
- Задание на выполнение
- Введение
- 1. Анализ
- 2. Проектирование
- 3. Кодирование и отладка
- 3.1 Служба
- 3.2 Приложение
- 3.3 Взаимодействие службы и приложения
- 4. Тестирование
- 5. Сопровождение
- Заключение
- Список литературы
- Приложение А. Заголовочный файл службы
- Приложение Б. Файл реализации службы
- Приложение В. Файл реализации приложения29
Задание на выполнение
Разработка службы Windows: «Контроль приложений», осуществляющей контроль набора выполняющихся приложений и, возможно, управление ими. Кроме разработки службы, необходимо разработать приложение, которое будет осуществлять управление этой службой.
Введение
Целью данного курсового проекта является развитие и закрепление навыков разработки системных приложений.
Объект проектирования в данной работе - служба Windows: «Контроль приложений».
Для более полного понимания объекта рассмотрим определения службы.
Служба Windows (англ. Windows Service, сервисы) - приложения, автоматически запускаемые системой при запуске Windows и выполняющиеся вне зависимости от статуса пользователя [1].
Служба - это Windows-приложение, содержащая дополнительную инфраструктуру, которая позволяет ServiceControlManager (SCM) - компоненту, работающему на всех windows-машинах, - управлять этим приложением [2].
Данный программный продукт разрабатывался на языке C++ с использованием среды разработки Builder C++ XE2, позволяющей оптимизировать процесс его создания.
1. Анализ
Согласно заданию необходимо создать приложение, осуществляющие контроль приложений, но в задании не указаны конкретные требования по реализации данного приложения. Следовательно, разработчик данного программного продукта сам решает какой язык программирования выбрать и как будет выглядеть готовый программный продукт (его функции).
Для реализации данного проекта был выбран язык С++, так как в наличии имеется среда разработки, и соответствующие знания данного языка.
Реализация службы возможна в двух вариантах:
1) с использованием WIN API;
2) с использованием встроенного класса vcl TService в Builder C++ XE2.
Использование 2-го варианта наиболее оптимально, так как работа с сервисом значительно упрощается.
Рассмотрим необходимость интерактивности разрабатываемой службы. Интерактивные службы - службы, осуществляющие взаимодействие с пользователем. Службы предназначены для непрерывной работы в отсутствии пользователей, поэтому дожидаться, пока оператор (пользователь) нажмёт «OK», можно очень долго. Но, тем не менее, возможности существуют. Поэтому постараемся избежать интерактивности в разрабатываемой службе.
В задании указано, что помимо самой службы необходимо разработать приложение, которое будет осуществлять управление этой службой. Под управлением подразумевается установка, удаление, запуск и остановка непосредственно разрабатываемой службы.
Существуют два варианта реализации приложения:
1) графическое приложение с использованием визуальных компонент;
2) консольное приложение, работающее с командной строкой.
В среде разработке Builder C++ XE2 возможна реализация обоих вариантов, но исходя из соображений, что обычный пользователь редко занимается установкой служб и их запуском самостоятельно, то выберем консольный вариант реализации.
Для удобства использования будет разработана система меню, удобная в использовании и включающая в себя справку.
2. Проектирование
Основной целью данного этапа является получение проектных решений.
На первом этапе проектирования рассмотрим саму службу.
Определим функционал разрабатываемого сервиса:
1) создание лог файла, в который будут заноситься сведенья о запушенных процессах. При запуске и завершении процесса добавляется соответствующая запись;
2) при бездействии операционной системы запускать дефрагментацию основного раздела жесткого диска.
Существуют два варианта подхода в проектировании службы.
Вариант первый: стартует служба, начинает что-то делать, время от времени уведомляя систему о своём состоянии, потом служба останавливается.
Вариант второй: стартует служба, создаёт рабочие потоки. По уведомлению от системы потоки останавливаются и служба выключается.
Обычно в службах используется второй вариант, поэтому остановимся именно на этом варианте.
Для формирования лога необходимо создать структуру, в полях которой будут храниться данные о процессе (время создания/завершения, идентификатор (pid), имя процесса, указатель процесса), передаваемую в качестве параметра в функцию записи в лог файл.
Сам процесс формирования лог файла происходит в несколько этапов:
1) служба получает список запушенных процессов в данный момент;
2) сверяет со списком запущенных процессов, полученным ранее, если существуют процессы, отсутствующие в данном списке, затем происходит заполнение структуры данных о процессе и добавление в этот список и вызов функции формирования записи в лог файле о запуске процесса;
3) поиск в списке, полученном во втором пункте, процессов, которые отсутствуют в списке из первого пункта и формирование записи о завершении данного процесса, удалении его из списка.
Сам процесс записи в лог файл будет осуществляться с использованием потоков.
Для определения бездействия системы необходимо выяснить загрузку процессора, если она достаточно мала, то запускается встроенный дефрагментатор системы Windows.
На втором этапе рассмотрим управляющие приложение.
Данное приложение необходимо для установки, удаления службы и ее настройки во время установки.
Для управления сервисами в Windows существует Service Сontrol Manager (SCM). Для корректного управления службой при ее модификации или смене состояний необходимо каждый раз сначала получать указатель SCM и лишь затем указатель самой службы. Закрытие указателей происходит в обратном порядке.
Меню данного приложения можно реализовать в виде бесконечного цикла while c использованием условной конструкции switch предусматривающая возможность выхода из данного цикла. В данном меню необходимо будет реализовать 5 пунктов:
1) установка сервиса;
2) удаление сервиса;
3) запуск и завершение работы сервиса;
4) помощь по использованию приложения;
5) выход.
В первом пункте необходимо предусмотреть возможность ввода ключей для выбора функционала и проверку на правильность их ввода.
3. Кодирование и отладка
Основной целью данного этапа является реализация программного продукта.
3.1 Служба
При создании проекта службы были автоматически созданы два метода:
TServiceController __fastcall TControlProcess::GetServiceController(void)
{
return (TServiceController) ServiceController;
}
void __stdcall ServiceController(unsigned CtrlCode)
{
ControlProcess->Controller(CtrlCode);
}
Эти два метода никогда изменяться не будут, так как за ними скрывается процесс взаимодействия с SCM менеджером.
Согласно проектному решению в основном потоке службы осуществляется только взаимодействие с SCM, а функционирование службы происходит в созданном ею потоке.
Для создания потока воспользуемся встроенным в Builder C++ XE2 классом TThread. Создадим потомка данного класса TSparkyThread.
class TSparkyThread : public TThread {
private:
protected:
void __fastcall Execute();/*главным методом объекта TThread.
В теле метода должен содержаться код, который представляет собой программу потока*/
public:
__fastcall TSparkyThread(bool CreateSuspended); /*конструктор
созданого класса */ };
Win32 предоставляет несколько способов перечисления запущенных процессов:
1) с помощью библиотеки Process Status Helper (PSAPI);
2) с помощью ToolHelp32 API;
3) с помощью недокументированной функции ZwQuerySystemInformation;
4) с использованием интерфейсов Windows Management Instrumentation.
Был выбран первый вариант, т.к для перечисления процессов библиотека PSAPI предоставляет функцию EnumProcesses, которая возвращает массив идентификаторов запущенных процессов, и в отличии от других методов не извлекается избыточная информация о процессах, а необходимая информация извлекается с использованием указателей процессов.
BOOL WINAPI EnumProcesses(
__out DWORD *pProcessIds,//указатель на массив идентификаторов
__in DWORD cb,//размер pProcessIds
__out DWORD *pBytesReturned//число возвращенных байтов
);
Для хранения информации о процессах создадим структуру ProcesInfo следующего вида:
struct ProcesInfo{
DWORD PID; //идентификатор процесса
HANDLE hProcess; //указатель процесса
TCHAR szProcessName[MAX_PATH]; //имя процесса
SYSTEMTIME ST[2]; // время создания и завершения
} ;
Для сохранения списка используем ассоциативный массив (map):
typedef map <DWORD,ProcesInfo> ProcessList;
где ключом является идентификатор процесса, а хранимой информацией структура ProcesInfo.
Отслеживание запуска и завершение программы осуществляется согласно решению, полученному на этапе проектирования. Связи с этим, в потоке, создающемся при запуске службы, объявим два ассоциативных массива:
ProcessList Old и ProcessList New.
Для заполнения структуры ProcesInfo создадим функцию:
void FillingProcesInfo(ProcesInfo &PrInfo,DWORD &aProcesses);
Параметрами, передаваемыми в данную функцию, являются сама структура и идентификатор процесса(PID), который будет позже сохранен в поле структуры. Указатель процесса может быть получен при помощи стандартной функции OpenProcess
HANDLE WINAPI OpenProcess(
__in DWORD dwDesiredAccess, // флаг доступа
__in BOOL bInheritHandle, //параметр дескриптора наследования
__in DWORD dwProcessId // идентификатор процесса
);
dwDesiredAccess - устанавливает уровень доступа к объекту процесса. Этот параметр может состоять из одного нескольких прав доступа к процессу. Из всех возможных были выбраны следующие параметры:
1) PROCESS_QUERY_INFORMATION - необходим, чтобы извлечь некоторую информацию о процессе;
2) PROCESS_VM_READ - необходим, чтобы читать память в процессе, используя функцию ReadProcessMemory.
Выбраны именно эти параметры, так как для того, чтобы узнать имена процессов, нужно вызвать EnumProcessModules и GetModuleBaseName.
EnumProcessModules перечисляет все модули процесса, а GetModuleBaseName просто возвращает имя модуля. Данные права доступа необходимы функции PSAPI EnumProcessModules, с помощью которой извлекается имя процесса.
BOOL WINAPI EnumProcessModules(
__in HANDLE hProcess, //дескриптор процесса
__out HMODULE *lphModule, // Массив, который получает список//дескрипторов модуля.
__in DWORD cb, // Размер массива lphModule, в байтах.
__out LPDWORD lpcbNeeded /*Число байтов, требуемых сохранитьвсе дескрипторы модуля в массиве lphModule. количество байт*/
);
DWORD WINAPI GetModuleBaseName(
__in HANDLE hProcess,// дескриптор процесса
__in_opt HMODULE hModule, /* Дескриптор к модулю.
Если этот параметр - NULL, эта функция возвращается, имя процесса*/
__out LPTSTR lpBaseName, /* Указатель на буфер, который получает базовое имя модуля*/
__in DWORD nSize // Размер буфера lpBaseName, в символах.
);
Время создания и завершения процесса узнается при помощи функции GetProcessTimes.
Время работы процессора можно вычислить по следующей формуле:
Для получения этих временных характеристик воспользуемся
NTSTATUS WINAPI NtQuerySystemInformation (
__ in SystemInformationClass SYSTEM_INFORMATION_CLASS,
/* Одно из значений SYSTEM_INFORMATION_CLASS, которые указывают на вид информации о системе, которая будет получена.*/
__ inout PVOID SystemInformation,/* Указатель на буфер, который получает требуемую информацию. Размер и структура этой информации изменяются в зависимости от значения параметра SystemInformationClass:*/
__ in SystemInformationLength ULONG,
__ out_opt PULONG ReturnLength
);
В качестве первого параметра используем SystemProcessorPerformanceInformation, который возвращает массив структур SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, один для каждого процессора, установленного в системе.
Для второго параметра определим структуру:
struct_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
LARGE_INTEGER IdleTime; /* количество времени , которое система была неактивна */
LARGE_INTEGER KernelTime;/* количество времени , которое система потратила выполнение в Привилегированном режиме (включая все потоки во всех процессах, на всех процессорах)*/
LARGE_INTEGER UserTime;/* количество времени, которое система потратила выполнение в Непривилегированном режиме (включая все потоки во всех процессах, на всех процессорах)*/
LARGE_INTEGER Reserved1 [2];
ULONG Reserved2;
};
Таким образом, возможно определить загрузку одного процессора. В современных компьютерах не редко встречается многопроцессорная архитектура, поэтому бездействие системы можно определить как некое суммарное число бездействия каждого из процессоров.
Запускать дефрагментацию постоянно во время простоя неэффективно, так как при длительном бездействии процесс дефрагментации будет запушен несколько раз подряд, что повысит энергопотребление и загрузку центрального процессора, что не очень хорошо особенно для ноутбуков которые не были подключены к сети питания и работают от внутреннего источника - аккумуляторной батареи ресурс которой ограничен. К тому же помимо нашей службы в фоновом режиме может работать антивирус, проверяющий файловую систему во время бездействия ОС, в то время как наши действия снизят эффективность проверки и увеличит продолжительность данного действия.
Поэтому добавим в нашу службу компонент таймер. В свойствах данного компонента укажем время срабатывания 12 часов, который будет активировать флаг дефрагментации в службе, при активации которого возможен запуск дефрагментации.
3.2 Приложение
Для установки и удаления службы необходимо получать дескриптор SCM. Для этого воспользуемся OpenSCManager(
NULL, // локальная машина
NULL, // имя базы (ServicesActive)
SC_MANAGER_ALL_ACCESS); // полный доступ
Данная функция как раз и возвращает данный дескриптор.
Установка службы осуществляется вызовом функции CreateService, которая создаёт объект сервиса и добавляет его в базу данных менеджера управления сервисами (SCM).
SC_HANDLE CreateService(
SC_HANDLE hSCManager, /*Дескриптор базы данных менеджера управления сервисами (SCM)*/
LPCTSTR lpServiceName, /* Указатель на строку (завершающуюся нулём), содержащую имя создаваемого сервиса. Максимальная длина строки не должна превышать 256 символов. В имени сервиса нельзя использовать символы "/" и "\". */
LPCTSTR lpDisplayName, /* Указатель на строку (завершающуюся нулём), содержащую имя, которое будет отображаться в пользовательских приложениях */
DWORD dwDesiredAccess, /* Тип доступа к сервису. Перед тем, как разрешить запрашиваемый доступ, система проверит привелегии вызвавшего процесс*/
DWORD dwServiceType, /* Тип сервиса */
DWORD dwStartType, /* Тип запуска сервиса*/
DWORD dwErrorControl, /* Степень контроля ошибок, а так же действия, которые будут предприняты, в случае ошибки запуска сервиса. */
LPCTSTR lpBinaryPathName, /* Указатель на строку (заканчивающуюся нулём), которая содержит полный путь к исполняемому файлу сервиса. */
LPCTSTR lpLoadOrderGroup, /* Указатель на строку (заканчивающуюся нулём), которая содержит имя группы, членом которой является сервис. Если сервис не является членом группы, то можно указать NULL или пустую строку. */
LPDWORD lpdwTagId, /* казатель на переменную, в которую будет записан уникальное значение тэга, которое идентифицирует группу, указанную в параметре lpLoadOrderGroup. Если Вы не собираетесь менять существующий тэг, то укажите в этом параметре NULL. */
LPCTSTR lpDependencies, /* Указатель на массив (завершающийся двумя нулями) имён (разделённых нулями) сервисов или групп сервисов, которые система должна запустить до запуска этого сервиса. Если сервис не зависит от других сервисов, то в этом параметре нужно указать NULL или пустую строку.*/
LPCTSTR lpServiceStartName, /* Указатель на строку (завершающуюся нулём), которая содержит имя аккаунта, с правами которого будет запущен сервис. */
LPCTSTR lpPassword/* Указатель на строку (заканчивающуюся нулём), которая содержит пароль к аккаунту, указанному в параметре lpServiceStartName. Если аккаунт не имеет пароля либо если сервис запускается с правами LocalService, NetworkService, или системы, то можно указать на пустую строку*/
);
Для удобства использования, в качестве второго и третьего параметра, передадим одну и ту же строку содержащую имя сервиса.
Четвертым параметром передадим права доступа SERVICE_ALL_ACCESS, так как для работы со службой нужны права администратора.
Пятым параметром передадим значение SERVICE_WIN32_OWN_PROCESS, что означает что служба запускается в своем собственном процессе.
Следующим параметром передадим SERVICE_AUTO_START, благодаря которому сервис запускается автоматически диспетчером управления службами в ходе запуска системы.
Седьмым параметром зададим степень контроля ошибок SERVICE_ERROR_NORMAL. Программа запуска регистрирует ошибку и показывает всплывающее окно сообщения, но продолжает операцию запуска.
Восьмым параметром является путь расположения исполняемого файла службы - "C:\\PrControlProcess.exe".
Оставшимся параметрам присвоим значение NULL.
Сами действия, производимые над службой, осуществляются с помощью следующей функции:
SC_HANDLE WINAPI OpenService(
__in SC_HANDLE hSCManager,//дескритор scm
__in LPCTSTR lpServiceName,// имя службы
__in DWORD dwDesiredAccess// права доступа
);
При разработке сервиса использовались следующие права доступа:
1) SERVICE_START - требует вызвать функцию StartService, чтобы запустить службу;
2) SERVICE_STOP - требует вызвать функцию ControlService, чтобы остановить службу;
3) DELETE - требует вызвать функцию ControlService для удаления службы.
3.3 Взаимодействие службы и приложения
Перед установкой службы приложение просит пользователя ввести ключи, если пользователь ввел их корректно, тогда происходит процесс установки службы, следующим действием является передача службе этих ключей.
Так как используется vcl служба, то передать напрямую параметры не удастся, так основной поток службы скрыт в классе TService. Но существует альтернативный метод передачи ключей через реестр.
SCM хранит базу данных служб в ключе реестра:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
Удобно все параметры службы хранить в ключе:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Имя-
Службы(свойство Name)\Parameters.
Служба может считывать свои параметры оттуда при запуске, а приложение-конфигуратор -- писать в этот ключ настройки [3].
Однако на этом не остановимся, и упростим работу службы, добавив в ней флаг mode. Именно его значение мы и будем записывать в реестр в ветку:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Имя-
Службы(свойство Name)\mode.
Для этого воспользуемся следующими функциями: RegCreateKeyEx и RegSetValueEx. Первая функция предназначена для создания ветви реестра, если она отсутствует, а вторая для записи определенного значения.
LONG RegCreateKeyEx(
HKEY hKey,// дескриптор открытого ключа
LPCTSTR lpSubKey,// адрес имени подключа
DWORD Reserved,// зарезервировано
LPTSTR lpClass,// адрес строки класса
DWORD dwOptions,// флаг особых опций
REGSAM samDesired,// желаемый доступ безопасности
LPSECURITY_ATTRIBUTES lpSecurityAttributes,// адрес структуры
ключа безопасности
PHKEY phkResult,// адрес буфера для открытого ключа
LPDWORD lpdwDisposition // адрес буфера характерного значения);
LONG RegSetValueEx(
HKEY hKey,// дескриптор ключа
LPCTSTR lpValueName,// адрес имени установливаемого значения
DWORD Reserved,// зарезервировано
DWORD dwType,// тип данных
CONST BYTE *lpData,// адрес данных для установки
DWORD cbData// размер данных
);
Считывание значение реестра службой осуществляется
RegQueryValueExA.
LSTATUS RegQueryValueExA
(
HKEY hkey,// Дескриптор ключа.
LPCSTR name,//имя читаемого ключа
LPDWORD reserved, // зарезервировано
LPDWORD type, // тип данных
LPBYTE data,// адрес данных
LPDWORD count// размер данных
)
Возможны три режима работы службы:
1) создание лога и запуск дефрагментации;
2) создание лога;
3) запуск дефрагментации.
Выбор режима в службе осуществляется с помощью конструкции switch.
Помимо этого в реестре создается ключ Description, содержащий описание службы.
Описание функций были взяты с официального сервера корпорации майкрософт [4].
Кодом программы представлен в Приложениях А,Б,В.
4. Тестирование
Отладка и тестирование служб очень трудоемкий процесс. Он значительно отличается от отладки обычного приложения. Есть несколько вариантов выхода из данной ситуации. Воспользуемся наиболее простым. Суть его в том, что проверить функциональность основного кода службы можно и в приложении, если ошибок не обнаружено, то перенести его в службу и затем проверять ее функционирование. Как правило, при таком подходе на последней стадии ошибок не возникает.
Проведем планирование нашего тестирования.
На первом этапе проверим правильность работы приложения по установке и удалению службы. На втором этапе проверим ее функционирование. И на последнем проверим правильность обработки неправильного ввода пользователя.
Приступим к первому этапу тестирования:
Список служб до установки:
Рисунок 1. Список служб до установки службы
Попробуем установить службу при помощи разработанного приложения
Рисунок 2. Установка службы
Посмотрим вновь список установленных служб:
Рисунок 3. Список служб после установки сервиса
В перечне служб появилась новая служба ControlProcess- это и есть установленная служба, то есть в процессе установки ошибок обнаружено не было.
Теперь удалим нашу службу, используя консоль, и посмотрим список установленных сервисов:
Рисунок 4. Список служб после удаления
Службы ControlProcess больше нет в данном списке, что очень наглядно отображает правильность функционирования.
Установим сервис с ключом /l, что обеспечивает только запись в лог файл информации о процессах. И запустим ее при помощи консольного приложения:
Рисунок 5. Запуск службы из приложения
Проверим функционирование службы наличием лог файла в C:\WINDOWS\system32
Рисунок 6. Содержимое каталога C:\WINDOWS\system32
Просмотрим содержимое данного файла
Рисунок 7. Содержимое лог файла
Для проверки правильности работы запустим и закроем браузер internet explorer
Рисунок 8. Содержимое лог файла с записями о запуске и закрытии internet explorer-а
Как видно были добавлены соответствующие записи.
Теперь проверим правильность работы запуска дефрагментации с помощью разработанной службы. Для этого переустановим службу с параметрами запуска дефрагментации и созданием лога
Рисунок 9. Содержимое лог файла с записями о запуске и завершении дефрагментатора
Из данного рисунка отчетливо видно запуск процесса дефрагментации и его завершение.
Проверка режима дефрагментации осуществляться не будет, так как там происходит идентичный вызов функций, за исключением функций создания лог файла.
Отметим так же возможность пользователя запускать и завершать работу службы из SCM.
Проверим приложение на правильность ввода ключей
Рисунок 10. Проверка на ввод некорректных ключей
При вводе некорректных ключей выводиться соответствующее предупреждение.
5. Сопровождение
· Системные требования:
ь Windows XP
ь Права администратора
На данный момент служба не корректно ведет себя в ОС Windows 7 и Windows Vista планируется устранить данный недостаток в следующей версии.
· Инструкция по установке:
ь Скопируйте исполняемый файл PrControlProcess в корень диска С:\.
ь Запустите консольное приложение menu.exe с правами администратора.
ь Для установки службы выберете первый пункт меню. Перед установкой службы введите ключи, более подробно ключи описаны в разделе help. Если ключи не были введены, тогда служба ставиться с параметрами по умолчанию (включены все функции)
ь Для запуска или завершения работы службы воспользуйтесь третьим пунктом меню или SCM.
ь Удаление службы происходит при выборе второго пункта. После успешного удаления службы удалите исполняемый файл из корня диска С:\.
Заключение
Полученный программный продукт может использоваться в учебных заведениях, в компьютерных клубах, в местах, где пользование компьютерами общедоступно и просто на компьютере пользователя. В общественных заведениях данная служба поможет проследить какие приложения пользуются большой популярностью (для компьютерного клуба), а в учебных заведениях вести контроль за действиями пользователей. Для локального компьютера эта служба будет полезна тем, что можно выявить скрытые процессы, которые запускаются во время работы компьютера, что явно помогает обнаруживать вредоносные программы.
Недостаток разработанной службы заключается в том, что она рассчитана на работу в Windows XP и не работает в Windows 7 и Windows Vista. Это вызвано тем, что функции PSAPI не совсем корректно работают на новой платформе.
В процессе выполнения курсового проекта, были закреплены и углублены теоретические знаний, также приобретены практические умения и навыки в самостоятельном проектировании программных продуктов и составлении документов подобного рода.
Список литературы
1. Службы Windows [Электронный ресурс]
2. Рихтер, Д. Программирование серверных приложений для Microsoft Windows 2000: мастер-класс / Д. Рихтер, Д. Кларк. - М.: Русская редакция; СПб.: Питер, 2001. - 592 с.: ил.
3. Создание служб Windows в Delphi с использованием VCL [Электронный ресурс]
4. Библиотека MSDN [Электронный ресурс] - Режим доступа: http://msdn.microsoft.com/ - Загл. с экрана. Дата обращения 22.12.2011.
служба windows контроль приложение
Приложение А.
Заголовочный файл службы
1: // ---------------------------------------------------------------------------
2: #ifndef ControlProcessrH
3: #define ControlProcessrH
4: // ---------------------------------------------------------------------------
5: #include <SysUtils.hpp>
6: #include <Classes.hpp>
7: #include <SvcMgr.hpp>
8: #include <vcl.h>
9: #include <Windows.h>
10: #include <ExtCtrls.hpp>
11: #include <fstream>
12: #include <iostream>
13: #include <windows.h>
14: #include <stdio.h>
15: #pragma comment ( lib, "lib\psapi.lib" )
16: #include <psapi.h>
17: #include <map.h>
18:
19: // ---------------------------------------------------------------------------
20: class TControlProcess : public TService {
21: __published: // IDE-managed Components
22:
23: TTimer *Timer1;
24:
25: void __fastcall ServiceStart(TService *Sender, bool &Started);
26: void __fastcall ServiceStop(TService *Sender, bool &Stopped);
27: void __fastcall ServicePause(TService *Sender, bool &Paused);
28: void __fastcall ServiceContinue(TService *Sender, bool &Continued);
29: void __fastcall Timer1Timer(TObject *Sender);
30:
31: private: // User declarations
32: public : // User declarations
33:
34: bool defrag;
35: int mode;
36:
37: __fastcall TControlProcess(TComponent* Owner);
38: TServiceController __fastcall GetServiceController(void);
39:
40: friend void __stdcall ServiceController(unsigned CtrlCode);
41: };
42:
43: // ---------------------------------------------------------------------------
44: class TSparkyThread : public TThread {
45: private:
46: protected:
47: void __fastcall Execute();
48:
49: public:
50: __fastcall TSparkyThread(bool CreateSuspended);
51: };
52:
53: // ---------------------------------------------------------------------------
54: struct ProcesInfo {
55: DWORD PID;
56: HANDLE hProcess; // T
57: TCHAR szProcessName[MAX_PATH];
58: SYSTEMTIME ST[2];
59: };
60:
61: // ---------------------------------------------------------------------------
62: typedef DWORD(__stdcall
*LPFN_NtQuerySystemInformation)(DWORD, PVOID, DWORD,
63: PDWORD);
64:
65: #define SystemProcessorPerformanceInformation 0x8
66:
67: // ---------
68:
69: #pragma pack(push,8)
70:
71: typedef struct
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
72: LARGE_INTEGER IdleTime;
73: LARGE_INTEGER KernelTime;
74: LARGE_INTEGER UserTime;
75: LARGE_INTEGER DpcTime;
76: LARGE_INTEGER InterruptTime;
77: ULONG InterruptCount;
78: } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION,
79: *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
80:
81: #pragma pack(pop)
82:
83: // ---------
84: typedef map<DWORD, ProcesInfo>ProcessList;
85: bool SetDebugPrivilege();
86: // ---------------------------------------------------------------------------
87: extern PACKAGE TControlProcess *ControlProcess;
88: // ---------------------------------------------------------------------------
89: #endif
Приложение Б
Файл реализации службы
1: // ---------------------------------------------------------------------------
2: #include "ControlProcessr.h"
3: // ---------------------------------------------------------------------------
4: #pragma package(smart_init)
5: #pragma resource "*.dfm"
6: TSparkyThread *SparkyThread;
7: TControlProcess *ControlProcess;
8:
9: // ---------------------------------------------------------------------------
10: __fastcall TControlProcess::TControlProcess(TComponent* Owner) :
TService(Owner)
11: {
12: }
13:
14: TServiceController __fastcall
TControlProcess::GetServiceController(void) {
15: return (TServiceController) ServiceController;
16: }
17:
18: void __stdcall ServiceController(unsigned CtrlCode) {
19: ControlProcess->Controller(CtrlCode);
20: }
21:
22: // ---------------------------------------------------------------------------
23: void Write_Log(ProcesInfo &PrInfo, int mode) {
24:
25: SYSTEMTIME ST;
26: GetLocalTime(&ST); // получаем текущее время
27: char filename[256] = {0};
28: char Status[2][12] = {" runing\n", " terminate\n"};
29: sprintf(filename, "%d.%d.%d.log", ST.wDay, ST.wMonth, ST.wYear,
ST.wMonth);
30: std::ofstream ofs(filename, std::ios_base::out | std::ios_base::app);
31: if (!ofs.is_open()) {
32: return;
33: }
34: ofs << PrInfo.ST[mode].wHour << "." << PrInfo.ST[mode]
35: .wMinute << "." << PrInfo.ST[mode].wSecond << " " << PrInfo.PID <<
36: " " << PrInfo.szProcessName << Status[mode] << std::endl;
37:
38: ofs.close();
39: }
40:
41: // ---------------------------------------------------------------------------
42: void FillingProcesInfo(ProcesInfo &PrInfo, DWORD &aProcesses) {
43: // SetDebugPrivilege();
44: FILETIME FT[4];
45: SYSTEMTIME ST[2];
46: PrInfo.PID = aProcesses;
47: // получаем указатель процесса.
48: PrInfo.hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
49: FALSE, PrInfo.PID);
50: // Получаеи имя процесса.
51: if (NULL != PrInfo.hProcess) {
52: HMODULE hMod;
53: DWORD cbNeeded;
54: if (EnumProcessModules(PrInfo.hProcess, &hMod, sizeof(hMod),
&cbNeeded))
55: {
56: GetModuleBaseName(PrInfo.hProcess, hMod, PrInfo.szProcessName,
57: sizeof(PrInfo.szProcessName) / sizeof(TCHAR));
58: }
59: if (GetProcessTimes(PrInfo.hProcess, &FT[0], &FT[1], &FT[2],
60: &FT[3]) != 0) {
61: for (int i = 0; i < 2; i++) {
62: FileTimeToSystemTime(&FT[0], &ST[0]);
63: SystemTimeToTzSpecificLocalTime(NULL, &ST[0], &ST[1]);
64: PrInfo.ST[0] = ST[1];
65: }
66: }
67: return;
68: }
69: }
70:
71: // ---------------------------------------------------------------------------
72: void ProcessEmum(ProcessList &New) {
73: DWORD aProcesses[1024], cbNeeded, cProcesses;
74: unsigned int i;
75: ProcesInfo buff;
76: ZeroMemory(&buff, sizeof(ProcesInfo));
77: // buff.szProcessName = "unknown";
78: if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
79: return;
80: }
81: // узнаем число процессов.
82: cProcesses = cbNeeded / sizeof(DWORD);
83: // заполнение новой карты.
84: for (i = 0; i < cProcesses; i++) {
85: if (aProcesses[i] != 0 && aProcesses[i] != 4) {
86: if (New.count(aProcesses[i]) == 0) {
87: FillingProcesInfo(buff, aProcesses[i]);
88: New.insert(make_pair(aProcesses[i], buff));
89: }
90:
91: }
92: }
93: }
94:
95: // ---------------------------------------------------------------------------
96: void GenerateLog(ProcessList &New, ProcessList &Old) {
97:
98: ProcessList::iterator PID;
99: FILETIME FT[4];
100: SYSTEMTIME ST[2];
101: for (PID = New.begin(); PID != New.end(); PID++) {
102: if (Old.count((*PID).first) == 0) {
103: Old.insert(make_pair((*PID).first, (*PID).second));
104: Write_Log((*PID).second, 0);
105: }
106: }
107: for (PID = Old.begin(); PID != Old.end(); PID++) {
108: if (New.count((*PID).first) == 0) {
109: if (GetProcessTimes((*PID).second.hProcess, &FT[0], &FT[1],
110: &FT[2],&FT[3]) != 0) {
111: FileTimeToSystemTime(&FT[1], &ST[0]);
112: SystemTimeToTzSpecificLocalTime(NULL, &ST[0], &ST[1]);
113: (*PID).second.ST[1] = ST[1];
114: Write_Log((*PID).second, 1);
115: Old.erase((*PID).first);
116: }
117: }
118: }
119: }
120:
121: // ---------------------------------------------------------------------------
122: int CPUsage(void) {
123: // Определяет загрузку ЦП в % для каждого ядра
124: SYSTEM_INFO systeminfo;
125: unsigned long bytesreturned;
126: unsigned long sumary = 0;
127: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
spi_old[32];
128: memset(spi_old, 0,
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*32);
129:
130: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
spi[32];
131: memset(spi, 0,
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*32);
132:
133: LPFN_NtQuerySystemInformation ntquerysysteminformation =
134: (LPFN_NtQuerySystemInformation) GetProcAddress
135: (GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
136:
137: if (!ntquerysysteminformation) {
138: return -1;
139: }
140:
141: GetSystemInfo(&systeminfo);
142:
143: ntquerysysteminformation(SystemProcessorPerformanceInformation,
spi_old,
144:
(sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)
145: * systeminfo.dwNumberOfProcessors), &bytesreturned);
146:
147: Sleep(500);
148:
149: ntquerysysteminformation(SystemProcessorPerformanceInformation,
spi,
150:
(sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)
151: * systeminfo.dwNumberOfProcessors), &bytesreturned);
152:
153: for (int cpuloopcount = 0; cpuloopcount <
systeminfo.dwNumberOfProcessors;
154: cpuloopcount++) {
155:
156: BYTE cpuusage =
157: (BYTE)(100 - (((spi[cpuloopcount].IdleTime.QuadPart -
158: spi_old[cpuloopcount].IdleTime.QuadPart) * 100) /
159: ((spi[cpuloopcount].KernelTime.QuadPart +
160: spi[cpuloopcount].UserTime.QuadPart) -
161: (spi_old[cpuloopcount].KernelTime.QuadPart +
162: spi_old[cpuloopcount].UserTime.QuadPart))));
163:
164: sumary = sumary + cpuusage;
165: }
166: return sumary;
167: }
168:
169: // ---------------------------------------------------------------------------
170: __fastcall TSparkyThread::TSparkyThread(bool CreateSuspended)
171: : TThread(CreateSuspended) {
172: }
173:
174: // ---------------------------------------------------------------------------
175: void __fastcall TSparkyThread::Execute() {
176:
177: TCHAR * szPath =
"SYSTEM\\CurrentControlSet\\Services\\ControlProcess";
178: TCHAR szBuf[MAX_PATH];
179: DWORD dwBufLen = MAX_PATH;
180: HKEY Key;
181: char szProductType[132];
182: DWORD ktp = REG_SZ; // так работает
183: RegOpenKeyExA(HKEY_LOCAL_MACHINE, szPath, 0,
KEY_ALL_ACCESS, &Key);
184: RegQueryValueExA(Key, "mode", NULL, &ktp, (LPBYTE)szBuf,
&dwBufLen);
185: ControlProcess->mode = StrToInt(szBuf);
186: switch (ControlProcess->mode) {
187: case 0: {
188: ProcessList New, Old;
189: Old.clear();
190: ControlProcess->defrag = true;
191: while (!Terminated) {
192: New.clear();
193: ProcessEmum(New);
194: GenerateLog(New, Old);
195: if (CPUsage() > 10 && ControlProcess->defrag == true) {
196: ControlProcess->defrag = false;
197: WinExec("defrag.exe c:\\", SW_MINIMIZE);
198: }
199: Sleep(1000);
200: }
201: } break;
202: case 1: {
203: ProcessList New, Old;
204: Old.clear();
205: while (!Terminated) {
206: New.clear();
207: ProcessEmum(New);
208: GenerateLog(New, Old);
209: Sleep(1000);
210: }
211: } break;
212: case 2: {
213: ControlProcess->defrag = true;
214: while (!Terminated) {
215: if (CPUsage() > 10 && ControlProcess->defrag == true) {
216: ControlProcess->defrag = false;
217: WinExec("defrag.exe c:\\", SW_MINIMIZE);
218: }
219: Sleep(10000);
220: }
221: } break;
222: }
223: }
224:
225: // ---------------------------------------------------------------------------
226: void __fastcall TControlProcess::ServiceStart(TService *Sender, bool
&Started) {
227: SparkyThread = new TSparkyThread(false);
228: Started = true;
229: }
230:
231: // ---------------------------------------------------------------------------
232: void __fastcall TControlProcess::ServiceStop(TService *Sender, bool
&Stopped) {
233: SparkyThread->Terminate();
234: Stopped = true;
235: }
236:
237: // ---------------------------------------------------------------------------
238: void __fastcall TControlProcess::ServicePause(TService *Sender, bool
&Paused) {
239: SparkyThread->Suspend();
240: Paused = true;
241: }
242: // ---------------------------------------------------------------------------
243:
244: void __fastcall TControlProcess::ServiceContinue(TService *Sender,
245: bool &Continued)
246:
247: {
248: SparkyThread->Start();
249: Continued = true;
250: }
251: // ---------------------------------------------------------------------------
252:
253: void __fastcall TControlProcess::Timer1Timer(TObject *Sender) {
254: ControlProcess->defrag = true;
255: }
256: // ---------------------------------------------------------------------------
Приложение В
Файл реализации приложения
1: // ---------------------------------------------------------------------------
2:
3: #include <vcl.h>
4: #pragma hdrstop
5: #include <iostream>
6: #include <tchar.h>
7: #include <Windows.h>
8: #include <string.h>
9: using namespace std;
10: const int NotUsed = system("color 71");
11:
12: // ----------------------------------------------------------------------------
13: void ShowLastError(void) {
14: char RusMsg[256];
15: void * Msg;
16: FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
17: 0, GetLastError(), MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
18: (LPTSTR)&Msg, 0, 0);
19: CharToOem((char*)Msg, RusMsg);
20: printf("%s\n", RusMsg);
21: LocalFree(Msg);
22: }
23:
24: // ----------------------------------------------------------------------------
25: void ShowRegError(long s) {
26: char RusMsg[256];
27: void * Msg;
28: FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
29: 0, s, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&Msg, 0, 0);
30: CharToOem((char*)Msg, RusMsg);
31: printf("%s\n", RusMsg);
32: LocalFree(Msg);
33: }
34:
35: // ----------------------------------------------------------------------------
36: int WriteKeyMode(char mode[]) {
37: HKEY hKey;
38: long s;
39: // Строка которую будем писать в реестр
40: char szTestString[] = "";
41: // Ключ который будем создавать
42: TCHAR szPath[] =
"SYSTEM\\CurrentControlSet\\Services\\ControlProcess";
43: // Создаем ключ в ветке HKEY_LOCAL_MACHINE
44: if ((s = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szPath, 0,
NULL,
45: REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hKey, NULL))
!= ERROR_SUCCESS) {
46: ShowRegError(s);
47: return -1;
48: }
49: // Пишем режим в созданный ключ
50: strcpy(szTestString, mode);
51: if ((s = RegSetValueEx(hKey, "mode", 0, REG_SZ,
(BYTE*)szTestString,
52: sizeof(szTestString))) != ERROR_SUCCESS) {
53: ShowRegError(s);
54: return -1;
55: }
56: // Закрываем описатель ключа
57: if ((s = RegCloseKey(hKey)) != ERROR_SUCCESS) {
58: ShowRegError(s);
59: return -1;
60: }
61: return 0;
62: }
63:
64: // ---------------------------------------------------------------------------
65: int Instal_Service(LPTSTR SomeServiceName) {
66: SC_HANDLE hService; // дескриптор сервиса
67: SC_HANDLE hSCManager; // дескриптор Service Control Manager
68: char key[12] = "";
69: // Строка которую будем писать в реестр
70: char szTestString[] = "";
71: // Ключ который будем создавать
72: TCHAR szPath[] =
"SYSTEM\\CurrentControlSet\\Services\\ControlProcess";
73: TCHAR Descpription[] = "This service control application Windows";
74: HKEY hKey;
75: long s;
76:
77: cout << "imput key:";
78: cin.getline(key, 10);
79: if (strcmp(key, "/l") == 0 || strcmp(key, "/d") == 0 || strcmp(key,
80: "/l /d") == 0 || strcmp(key, "/d /l") == 0 || strcmp(key, "") == 0) {
81:
82: hSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_CREATE_SERVICE);
83: if (!hSCManager)
84: return -1;
85: // создаем сервис MyService
86: hService = CreateService(hSCManager, SomeServiceName,
SomeServiceName,
87: SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
88: SERVICE_ERROR_NORMAL, "C:\\PrControlProcess.exe", NULL,
NULL,
89: NULL,NULL, NULL);
90: if (!hService) {
91: CloseServiceHandle(hSCManager);
92: return -1;
93: }
94: if ((s = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szPath, 0,
NULL,
95: REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hKey, NULL))
96: != ERROR_SUCCESS) {
97: ShowRegError(s);
98: return -1;
99: }
100: // Пишем режим в созданный ключ
101: if ((s = RegSetValueEx(hKey, "Description", 0, REG_SZ,
102: (BYTE*)Descpription, sizeof(Descpription))) != ERROR_SUCCESS)
{
103: ShowRegError(s);
104: return -1;
105: }
106: // Закрываем описатель ключа
107: if ((s = RegCloseKey(hKey)) != ERROR_SUCCESS) {
Подобные документы
Разработка на языке C++ службы, осуществляющей контроль набора выполняющихся приложений. Проектирование, кодирование, отладка, тестирование и сопровождение службы Windows. Взаимодействие службы и приложения. Интерактивность разрабатываемой службы.
курсовая работа [964,9 K], добавлен 01.06.2013Проектирование службы Windows и приложения для управления этой службой, которое позволит контролировать данные приложения - запускать и завершать определенные процессы по желанию пользователя через определенные промежутки времени. Инструкция по установке.
курсовая работа [2,8 M], добавлен 05.01.2013Проектирование системы управления базами данных. Особенности реализации в MS SQL. Разработка пользовательского интерфейса. Тестирование и отладка приложения. Руководство пользователя и системного администратора. Анализ и методы разработки приложений.
курсовая работа [867,9 K], добавлен 16.07.2013Теоретические основы написания Windows-приложений с использованием библиотеки MFC. Основы программирования под Windows. Проектирование приложений в среде Microsoft Visual C++. Описание логической структуры приложения, его функциональное назначение.
курсовая работа [1,3 M], добавлен 12.12.2011Проектирование и отладка Windows-приложений для работы с внешними источниками данных. Функциональная блок-схема взаимодействия программных модулей. Описание связей между таблицами. Тестирование программного средства. Требования к техническому обеспечению.
курсовая работа [2,7 M], добавлен 17.05.2011Основы организации приложения в Windows. Посылка и передача сообщений для окон. Создание и отображение главного окна приложения. Деактивация приложения, его фазы. Сообщения клавиатуры и функции для работы с ней. Определение состояния отдельных клавиш.
лекция [65,7 K], добавлен 24.06.2009Реализация программы, созданной средствами языка C#. Предназначение Windows-приложения для решения комплекса задач. Определение состава форм с графиком функции. Вычисление коэффициентов полинома. Создание текстового поля для введения корней многочлена.
курсовая работа [234,8 K], добавлен 13.11.2016Структура базы данных web-приложения предприятия ООО "Седово"; автоматизация процесса передачи документов. Разработка технического задания, проектирование БД, функциональное назначение web-приложений, тестирование, отладка и размещение в сети Internet.
дипломная работа [5,3 M], добавлен 24.06.2011Основы работы с многооконным графическим пользовательским интерфейсом операционной системы Windows95/NT. Основы работы с прикладными программами Windows и DOS. Разработка простого приложения для Windows при помощи средства разработки приложений DELPHI.
контрольная работа [281,0 K], добавлен 15.01.2009Общая характеристика операционных систем и приложений Windows. Разделение ресурсов, работа с окнами, назначение диска, видов памяти, системы сохранения и передачи данных. История возникновения приложений, их виды и особенности, порядок написания.
курс лекций [321,0 K], добавлен 24.06.2009