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. Урок 21.  Пайп.

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

 

Реклама:

обучение adobe flash cs5 в Москве;Школа будущих мам

В этом туториале мы исследуем пайп (pipe) , что это такое и для чего мы можем использовать его. Чтобы сделать этот процесс более интересным, я покажу, как можно изменить бэкграунд и цвет текста edit control'а.

Теория:

Пайп - канал или дорога с двумя концами. Вы можете использовать пайп, чтобы обмениваться данными между двумя различными процессами или внутри одного процесса. Это что-то вроде "уоки-токи". Вы даете другому участнику конец канала и он может использовать его для того, чтобы взаимодействовать с вами.

Есть два типа пайпов: анонимные и именованные. Анонимный пайп анонимен - вы можете использовать его не зная его имени. Для того, чтобы использовать именованный пайп, вам обязательно нужно знать его имя.

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

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

В этом туториале мы подробно рассмотрим анонимные пайпы. Главная цель таких пайпов - служить каналом между родительским и дочерним процессом или между дочерними процессами.

Анонимный пайп действительно полезен, когда вы взаимодействуете с консольным приложением. Консольное приложение - это вид win32-программ, которые используют консоль для своего ввода и вывода. Консоль - это вроде DOS-box'а. Тем не менее, консольное приложение - это полноценное 32-битное приложение. Оно может
использовать любую GUI-функцию, так же как и другие GUI-программы. Она отличается только тем, что у нее есть консоль.

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

Консольное приложение может получить эти три стандартных значения, вызвав функцию GetStdHandle, указав хэндл, который она хочет получить. GUI-приложение не имеет консоли. Если вы вызываете GetStdHandle, она возвратит ошибку. Если вы действительно хотите использовать консоль, вы можете вызвать AllocConsole, чтобы зарезервировать новую консоль. Тем не менее, не забудьте вызвать FreeConsole, когда вы уже не будете в ней нуждаться.

Анонимный пайп очень часто используется для перенаправления ввода и/или вывода дочернего консольного приложения. родительский процесс может быть консоль или GUI-приложение, но дочернее приложение должно быть консольным, чтобы это сработало. Как вы знаете, консольное приложение использует стандартные хэндлы для ввода и вывода. Если вы хотите перенаправить ввод/вывод консольного приложения, мы можем заменить один хэндл другим хэндлом одного конца пайпа. Консольное приложение не будет знать, что оно использует один конец пайпа. Оно будет считать, что это стандартный хэндл. Это вид полиморфизма на ООП-жаргоне. Это мощный подход, так как нам не нужно модифицировать родительский процесс никаким образом.

Другая вещь, которую вы должны знать о консольном приложении - это откуда оно берет стандартный хэндл. Когда консольное приложение создано, у родительского приложения есть следующий выбор: оно может создать новую консоль для дочернего приложения или позволить тому наследовать собственную консоль. Чтобы второй метод работал, родительский процесс должен быть консольным, либо, если он GUI'евый, создать консоль с помощью AllocConsole.

Давайте начнем работу. Чтобы создать анонимный пайп, вам требуется вызывать CreatePipe. Эта функция имеет следующий прототип:

function CreatePipe _
(byval pReadHandle as PHANDLE, _
byval pWriteHandle as PHANDLE, _
byval ppipeAttributes as LPSECURITY_ATTRIBUTES, _
byval nBufferSize as DWORD) as BOOL

• pReadHandle - это указатель на переменную типа PHANDLE, которая получит хэндл конца чтения пайпа.
• pWriteHandle - это указатель на переменную типа PHANDLE, которая получит хэндл на конец записи пайпа.
• pPipeAttributes указывает на структуру SECURITY_ATTRIBUTES, которая определяет, наследуется ли каждый из концов дочерним процессом.
• nBufferSize - это предполагаемый размер буфера, который пайп зарезервирует для использования. Это всего лишь предполагаемый размер. Вы можете передать NULL, чтобы указать функции использовать размер по умолчанию.

Если вызов прошел успешно, возвращаемое значение не равно нулю, иначе оно будет нулевым.

После успешного вызова Createpipe вы получите два хэндла, один к концу чтения, а другой к концу записи. Теперь я вкратце изложу шаги, необходимые для перенаправления стандартного вывода дочерней консольной программы в ваш процесс. Заметьте, что мой метод отличается от того, который изложен в справочнике по WinAPI от Borland. Тот метод предполагает, что родительский процесс - это консольное приложение, поэтому дочерний процесс должен наследовать стандартные хэндлы от
него. Но большую часть времени нам будет требоваться перенаправить вывод из консольного приложения в GUI'евое.

• Создаем анонимный пайп с помощью Createpipe. Не забудьте установить параметр bInheritable структуры SECURITY_ATTRIBUTES в TRUE, чтобы хэндлы могли наследоваться.
• Теперь мы должны подготовить параметры, которые передадим CreateProcess (мы используем эту функцию для загрузки консольного приложения). Среди аргументов этой функции есть важная структура STARTUPINFO. Эта структура определяет появление основного окна дочернего процесса, когда он запускается. Эта структура жизненно важна для нас. Вы можете спрятать основное окно и передать хэндл пайпа дочерней консоли вместе с этой структурой.
• Ниже находятся поля, которые вы должны заполнить:

• cb : размер структуры STARTUPINFO
• dwFlags : двоичные битовые флаги, которые определяют, какие члены структуры будут использоваться, также она управляет состоянием основного окна. Нам нужно указать комбинацию STARTF_USESHOWWINDOW and STARTF_USESTDHANDLES.
• hStdOutput и hStdError : хэндлы, которые будут использоваться в дочернем процессе в качестве хэндлов стандартного ввода/вывода. Для наших целей мы передадим хэндл пайпа в качестве стандартного вывода и вывода ошибок. Поэтому когда дочерний процесс выведет что-нибудь туда, он фактически передаст информацию через пайп родительскому процессу.
• wShowWindow управляет тем, как будет отображаться основное окно. Нам не нужно, чтоб окно консоли отображалось на экране, поэтому мы приравняем этот параметр к SW_HIDE.

• Вызов CreateProcess, чтобы загрузить дочернее приложение. После того, как вызов прошел успешно, дочерний процесс все еще находится в спящем состоянии. Он загружается в память, но не запускается немедленно.
• Закройте конец хэндл конца записи пайпа. Это необходимо, так как родительскому процессу нет нужды использовать этот хэндл, а пайп не будет работать, если открыть более чем один конец записи. Следовательно, мы должны закрыть его прежде, чем считывать данные из пайпа. тем не менее, не закрывайте этот конец до вызова CreateProcess, иначе ваш пайп будет сломан. Вам следует закрыть конец записи после того, как будет вызвана функция Createprocess, и до того,
как вы считаете данные из конца чтения пайпа.
• Теперь вы можете читать данные из конца чтения с помощью ReadFile. С ее помощью вы запускаете дочерний процесс, который начнет выполняться, а когда он запишет что-нибудь в стандартный хэндл вывода, данные будут посланы на конец чтения пайпа. Вы должны последовательно вызывать ReadFile, пока она не возвратит ноль, что будет означать, что больше данных нет. С полученной информацией вы можете делать все, что хотите, в нашем случае я вывожу их в edit control.
• Закроем хэндл чтения пайпа.

Пример:

файл pipe.bas

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

файл pipe.bi

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

файл pipe.rc

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

файл colors.bi

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

Анализ:

Пример вызовет fbc.exe, и перенаправит вывод в edit control. Когда программа загружена, она регистрирует класс окна и создает, как обычно, основное окно.

Теперь наступает самая интересная часть. Мы изменим цвет текста и бэкграунда edit control'а. Когда edit control подойдет к моменту отрисовки его клиентской области, он пошлет сообщение WM_CTLCOLOREDIT родительскому окну.

wParam содержит хэндл device context'а, который edit control будет использовать для отрисовки его клиентской области. Мы можем использовать эту возможность для изменения характеристик HDC.

case WM_CTLCOLOREDIT
SetTextColor(cPtr(HDC,wparam),Yellow)
SetBkColor(cPtr(HDC,wparam),Black)
function = cPtr(LRESULT,GetStockObject(BLACK_BRUSH))
exit function

SetTextColor изменяет цвет текста на желтый. SetBkColor изменяет цвет фона текста на черный. И, наконец, мы получаем хэндл черной кисти, которую мы возвратим Windows. Обрабатывая сообщение WM_CTLCOLOREDIT, мы должны возвратить хэндл кисти, которую Windows использует для отрисовки бэкграунда edit control'а. В нашем примере, я хочу, чтобы бэкграунд был черным, поэтому я возвращаю хэндл черной кисти Windows.

Когда пользователь выберет пункт меню 'FreeBasic', программа создаст анонимный пайп.

case IDM_FBC
sat.nLength = sizeof(SECURITY_ATTRIBUTES)
sat.lpSecurityDescriptor = NULL
sat.bInheritHandle = TRUE

Перед вызовом CreatePipe мы должны заполнить структуру SECURITY_ATTRIBUTES. Заметьте, что мы можем передать NULL, если нас не интересуют настройки безопасности.
И параметр bInheritHandle должен быть равен нулю, поэтому хэндл пайпа наследуется дочерним процессом.

if Createpipe _
(@hRead, _
@hWrite, _
@sat, _
NULL) _
= NULL then
MessageBox(hWnd, CreatepipeError, AppName, MB_ICONERROR+MB_OK)

После этого мы вызываем CreatePipe, которая заполнит переменные hRead и hWrite хэндлами концов чтения и записи. если возвращается 0, мы выдаем соответствующее сообщение об ошибке.

startupinfo.cb = sizeof(STARTUPINFO)
GetStartupInfo (@startupinfo)
startupinfo.hStdOutput = hWrite
startupinfo.hStdError = hWrite
startupinfo.dwFlags = STARTF_USESHOWWINDOW+STARTF_USESTDHANDLESиспользоваться
startupinfo.wShowWindow = SW_HIDE

Затем мы заполним структуру STARTUPINFO. Мы вызовем GetStartupInfo, чтобы заполнить ее значениями родительского процесса. Вы должны заполнить эту структуру, если хотите, чтобы ваш код работал и под win9x и под NT. После вы модифицируете члены структуры. Мы копируем хэндл конца записи в hStdOutput и hStdError, так как мы хотим, чтобы дочерний процесс использовал их вместо соответствующих стандартных хэндлов. Мы также хотим спрятать консольное окно дочернего процесса, поэтому в wShowWindow мы помещаем значение SW_HIDE. И, наконец, мы должны подтвердить, что модифицированные нами поля нужно использовать, поэтому мы указываем флаги STARTF_USESHOWWINDOW и STARTF_USESTDHANDLES.

if CreateProcess _
(NULL, _
CommandLine, _
NULL, _
NULL, _
TRUE, _
NULL, _
NULL, _
NULL, _
@startupinfo, _
@pinfo) _
= NULL then
MessageBox(hWnd,CreateprocessError,AppName,MB_ICONERROR+MB_OK)

Теперь мы создаем дочерний процесс функцией Createprocess. Заметьте, что параметр bInheritHandles должен быть установлен в TRUE, чтобы хэндл пайпа работал. если создание процесса завершается неудачей, мы выдаем соответствующее сообщение об ошибке.

CloseHandle(hWrite)

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

while TRUE ' цикл
_RtlZeroMemory(@buffer,1024)
if ReadFile _
(hRead, _
@buffer, _
1023, _
@bytesRead, _
NULL) _
= 0 then
exit while
else
SendMessage _
(hwndEdit, _
EM_SETSEL, _
-1, _
0)
SendMessage _
(hwndEdit, _
EM_REPLACESEL, _
FALSE, _
cPtr(lParam,@buffer))
end if
wend

Теперь мы готовы читать данные. Мы входим в бесконечный цикл, пока все данные не будут считанны. Мы вызываем RtlZeroMemory, чтобы заполнить буфер нулями,
потом вызываем ReadFile и вместо хэндла файла передаем хэндл пайпа. Заметьте, что мы считываем максимум 1023 байта, так данные, которые мы получим, должны быть ASCIIZ-строкой, которую можно будет передать edit control'у.

Когда ReadFile вернет данные в буфере, мы выведем их в edit control. Тем не менее, здесь есть несколько проблем. Если мы используем SetWindowText, чтобы поместить данные в edit control, новые данные перезапишут уже считанные! Нам нужно, чтобы новые данные присоединялись к старым.

Для достижения цели мы сначала двигаем курсор к концу текста edit control'а, послав сообщение EM_SETSEL с wParam'ом равным -1. Затем мы присоединяем данные с помощью сообщения EM_REPLACESEL.

CloseHandle(hRead)

Когда ReadFile возвращает NULL, мы выходим из цикла и закрываем конец чтения.

[C] Iczelion, пер. Aquila.

 

 

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

Ваше имя:  

Ваш e-mail:  

Сообщение:



Введите код: 

 

 

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

 

 

© 2010-2012

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

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

ICQ:279786014 или R549103331586   Z116647355686