FreeBASIC в России

   

 Главная   Исходники   Русскоязычный форум   Полезные файлы   Пользователи   Поиск

 

 FB Wiki   Уроки   Скачать FreeBASIC   Проекты   Ссылки   Загрузить   Каталог ссылок

 
 

 Замечания и предложения по работе сайта оставляйте здесь.

Сейчас на сайте:

Вы вошли как: Guest   Регистрация   

Логин:     Пароль:     

Создай бесплатно WebMoney кошелёк на своём мобильном всего за 5 минут

 

Делаем dll своими руками

Хэндл окна

Графические средства языка

Точка пересечения отрезков

Окна без рамки

Физика поведения ядра

Win32 API Введение

►Урок 1 Win32 API

►Урок 2 Win32 API

►Урок 3 Win32 API

►Урок 4 Win32 API

►Урок 5 Win32 API

►Урок 6 Win32 API

►Урок 7 Win32 API

►Урок 8 Win32 API

►Урок 9 Win32 API

►Урок 10 Win32 API

►Урок 11 Win32 API

►Урок 12 Win32 API

►Урок 13 Win32 API

►Урок 14 Win32 API

►Урок 15 Win32 API

►Урок 16 Win32 API

►Урок 17 Win32 API

►Урок 18 Win32 API

►Урок 19 Win32 API

►Урок 20 Win32 API

►Урок 21 Win32 API

►Урок 22 Win32 API

►Урок 23 Win32 API

►Урок 24 Win32 API

Ассоциация файлов

Определить OS

Выводит имя компьютера

 

 

 

Win32 API. Урок 14. Процесс.

Опытом поделился и оптимизировал под FreeBASIC:   15.01.2011

 

Реклама:

фильмы 2012 года новинки

 

Здесь мы изучим, что такое процесс и как его создать и прервать.


Вступление:

Что такое процесс? Я процитирую определение из справочника по Win32 ApI.

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

Как вы можете видеть из вышеприведенного определения, у процесса есть несколько объектов: адресное пространство, выполняемый модуль (модули) и все, что эти модули создают или открывают. Как минимум, процесс должен состоять из выполняющегося модуля, личного адресного пространства и ветви. У каждого процесса по крайней мере одна ветвь. Что такое ветвь? Фактически, ветвь - это выполняющаяся очередь. Когда Windows впервые создает процесс, она делает только одну ветвь на процесс. Эта ветвь обычно начинает выполнение с первой инструкции в модуле. Если в дальнейшем понадобится больше ветвей, он может сам создать их.

Когда Windows получает команду для создания процесса, она создает личное адресное пространство для процесса, а затем она загружает исполняемый файл в пространство. После этого она создает основную ветвь для процесса.

Под Win32 вы также можете создать процессы из своих программ с помощью функции Createprocess. Она имеет следующий синтаксис:

function CreateProcess _
(byval lpApplicationName as LPCSTR, _
byval lpCommandLine as LPSTR, _
byval lpprocessAttributes as LPSECURITY_ATTRIBUTES, _
byval lpThreadAttributes as LPSECURITY_ATTRIBUTES, _
byval bInheritHandles as BOOL, _
byval dwCreationFlags as DWORD, _
byval lpEnvironment as PVOID, _
byval lpCurrentDirectory as LPCSTR, _
byval lpStartupInfo as LPSTARTUPINFO, _
byval lpprocessInformation as LPPROCESS_INFORMATION) as BOOL

Не пугайтесь количества параметров. Большую их часть мы можем игнорировать.

• lpAplicationName --> Имя исполняемого файла с путем или без пути, который вы хотите запустить. Если параметр равен нулю, вы должны предоставить имя исполняемого файла в параметре lpCommandLine.
• lpCommandLine --> Аргументы командной строки к программе, которую вам требуется запустить. Заметьте, что если lpAplicationName равен нулю, этот параметр должен содержать также имя исполняемого файла. Например так: "notepad.exe readme.txt".
• lpprocessAttributes и lpThreadAttributes --> Укажите атрибуты безопасности для процесса и основной ветви. Если они равны NULL'ам, то используются атрибуты безопасности по умолчанию.
• bInheritHandles --> Флаг, который указывает, хотите ли вы, чтобы новый процесс наследовал все открытые хэндлы из вашего процесса.
• dwCreationFlags --> Несколько флагов, которые определяют поведение процесса, который вы хотите создать, например, хотите ли вы, чтобы процесс был создан, но тут же приостановлен, чтобы вы могли проверить его или изменить, прежде, чем он запустится. Вы также можете указать класс приоритета ветви(ей) в новом процессе. Этот класс приоритета используется, чтобы определить планируемый приоритет ветвей внутри процесса. Обычно мы используем флаг NORMAL_PRIORITY_CLASS.
• lpEnviromment --> Указатель на блок памяти, который содержит несколько переменных окружения для нового процесса. Если этот параметр равен NULL, новый процесс наследует их от родительского процесса.
• lpCurrentDirectory --> Указатель на строку, которая указывает текущий диск и директорию для дочернего процесса. NULL - если вы хотите, чтобы дочерний процесс унаследовал их от родительского процесса.
• lpStartupInfo --> Указывает на структуру STARTUPINFO, которая определяет, как должно появиться основное окно нового процесса. Эта структура содержит много членов, которые определяют появление главного окна дочернего процесса. Если вы не хотите ничего особенного, вы можете заполнить данную структуру значениями
родительского процесса, вызвав функцию GetStartupInfo.
• lpprocessInformation --> Указывает на структуру PROCESS_INFORMATION, которая получает идентификационную информацию о новом процессе. Структура PROCESS_INFORMATION имеет следующие параметры:

type PROCESS_INFORMATION
hProcess as HANDLE ' хэндл дочернего процесса
hThread as HANDLE ' хэндл основной ветви дочернего процесса
dwProcessId as DWORD ' ID дочернего процесса
dwThreadId as DWORD ' ID основной ветви
end type

Хэндл процесса и ID процесса - это две разные вещи. ID процесса - это уникальный идентификатор процесса в системе. Хэндл процесса - это значение, возвращаемое Windows для использования другими API-функциями, связанными с процессами. Хэндл процесса не может использоваться для идентификации процесса, так как он не уникален.

После вызова функции CreateProcess, создается новый процесс и функция сразу же возвращается. Вы можете проверить, является ли еще процесс активным, вызвав функцию GetExitCodeProcess, которая имеет следующий синтаксис:

function GetExitCodeProcess (byval hprocess as HANDLE, byval lpExitCode as PDWORD) as BOOL

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

Вы можете принудительно прервать процесс, вызвав функцию Terminateprocess. У нее следующий синтаксис:

function TerminateProcess (byval hprocess as HANDLE, byval uExitCode as UINT) as BOOL

Вы можете указать желаемый код выхода для процесса, любое значение, какое захотите. TerminateProcess - не лучший путь прервать процесс, так как любые используемые им dll не будут уведомлены о том, что процесс был прерван.

Пример:

Следующий пример создаст новый процесс, когда юзер выберет пункт меню "create process". Он попытается запустить "msgbox.exe". Если пользователь захочет прервать новый процесс, он может выбрать пункт меню "terminate process". Программа будет сначала проверять, уничтожен ли уже новый процесс, если нет, программа вызовет TerminateProcess для этого.

файл process.bas

Скопировать данный код в буфер обмена

файл process.bi

Скопировать данный код в буфер обмена

файл process.rc

Скопировать данный код в буфер обмена

Анализ:

Программа создает основное окно и получает хэндл меню для последующего использования. Затем она ждет, пока пользователь выберет команду в меню. Когда пользователь выберет "Process", мы обрабатываем сообщение WM_INITMENUPOPUP, чтобы изменить пункты меню.

case WM_INITMENUPOPUP
if GetExitCodeProcess _
(processInfo.hProcess, _
@ExitCode) = TRUE then
if ExitCode = STILL_ACTIVE then
EnableMenuItem _
(hMenu, _
IDM_CREATE_PROCESS, _
MF_GRAYED)
EnableMenuItem _
(hMenu, _
IDM_TERMINATE, _
MF_ENABLED)
else
EnableMenuItem _
(hMenu, _
IDM_CREATE_PROCESS, _
MF_ENABLED)
EnableMenuItem _
(hMenu, _
IDM_TERMINATE, _
MF_GRAYED)
end if
else
EnableMenuItem _
(hMenu, _
IDM_CREATE_PROCESS, _
MF_ENABLED)
EnableMenuItem _
(hMenu, _
IDM_TERMINATE, _
MF_GRAYED)
end if

Почему мы обрабатываем это сообщение? Потому что мы хотим изменить пункты в выпадающем меню прежде, чем пользователь их увидит. В нашем примере, если новый процесс еще не стартовал, мы хотим разрешить "start Process" и запретить доступ к пункту "terminate Process". Мы делаем обратное, если программа уже запущена.

Вначале мы проверяем, активен ли еще новый процесс, вызывая функцию GetExitCodeProcess и передавая ей хэндл процесса, полученный при вызове CreateProcess.
Если GetExitCodeProcess возвращает FALSE, это значит, что процесс еще не был запущен, поэтому запрещаем пункт "terminate process". Если GetExitCodeProcess возвращает TRUE, мы знаем, что новый процесс уже стартовал, мы должны проверить, выполняется ли он еще. Поэтому мы сравниваем значение в ExitCode со значением STILL_ACTIVE, если они равны, процесс еще выполняется: мы должны запретить пункт меню "start process", так как мы не хотим, чтобы запустилось несколько совпадающих процессов.

case IDM_CREATE_PROCESS
if processInfo.hProcess <> 0 then
CloseHandle _
(processInfo.hProcess)
processInfo.hProcess = 0
end if
GetStartupInfo (@startInfo)
CreateProcess _
(programname, _
NULL, _
NULL, _
NULL, _
FALSE, _
NORMAL_PRIORITY_CLASS, _
NULL, _
NULL, _
@startInfo, _
@processInfo)
CloseHandle _
(processInfo.hThread)

Когда пользователь выбирает пункт "start Process", мы вначале проверяем, закрыт ли уже параметр hProcess структуры PROCESS_INFORMATION. Если это в первый раз, значение hProcess будет всегда равно нулю, так как мы определяем структуру PROCESS_INFORMATION в начале программы. Если значение параметра hProcess не равно нулю, это означает, что дочерний процесс вышел, но мы не закрыли его хэндл. Поэтому пришло время сделать это.

Мы вызываем функцию GetStartupInfo, чтобы заполнить структуру STARTUPINFO, которую передаем функцию CreateProcess. После этого мы вызываем функцию CreateProcess.
Заметьте, что я не проверил возвращаемое ей значение, потому что это усложнило бы пример. Вам следует проверять это значение. Сразу же после CreateProcess,
мы закрываем хэндл основной ветви, возвращаемой в структуре processInfo. Закрытие хэндла не означает, что мы прерываем ветвь, только то, что мы не хотим использовать хэндл для обращения к ветви из нашей программы. Если мы не закроем его, это вызовет потерю ресурсов.

case IDM_TERMINATE
GetExitCodeProcess _
(processInfo.hProcess, _
@ExitCode)
if ExitCode = STILL_ACTIVE then
Terminateprocess _
(processInfo.hprocess, _
0)
end if
CloseHandle _
(processInfo.hprocess)
processInfo.hprocess = 0

Когда пользователь выберет пункт меню "terminate Process", мы проверяем, активен ли еще новый процесс, вызвав функцию GetExitCodeProcess. Если он еще активен, мы вызываем функцию TerminateProcess, чтобы убить его. Также мы закрываем хэндл дочернего процесса, так как он больше нам не нужен.

[C] Iczelion, пер. Aquila.

 

 

Прокомментировать

Ваше имя:  

Ваш e-mail:  

Сообщение:



Введите код: 

 

 

   Спасибо можно сказать, посетив любую ссылку:

 

 

© 2010-2012

DEPOzit (Попов Денис Владимирович)

WebMoney кошелёк: WMID#302963000004

ICQ:279786014 или R549103331586   Z116647355686