платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 21 - пайп
Участников: 2
Страница 1 из 1
платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 21 - пайп
Win32 API. Урок 21. Пайп
В этом туториале мы исследуем пайп (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) , что это такое и для чего мы можем использовать его. Чтобы сделать этот процесс более интересным, я покажу, как можно изменить бэкграунд и цвет текста 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
- Код:
' Пайп
#define WIN_INCLUDEALL
#include "windows.bi"
#include "pipe.bi"
#include "colors.bi"
Declare Sub _RtlZeroMemory Lib "kernel32" Alias "RtlZeroMemory" _
(byval Destination As Any ptr, ByVal Length As Long)
declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
byval szCmdLine as LPSTR, _
byval iCmdShow as integer ) as integer
' начало программы
dim shared hModule as HINSTANCE ' Хэндл нашей программы
dim shared hwndEdit as HWND ' хэндл edit control'а
hModule = GetModuleHandle( NULL ) ' Взять хэндл программы
end WinMain( hModule,NULL,GetCommandLine(), SW_SHOWNORMAL ) ' вызвать основную функцию
' здесь заканчивается программа
' процедура окна
function WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений
dim hRead as HANDLE ' хэндл конца чтения пайпа
dim hWrite as HANDLE ' хэндл на конец записи пайпа
dim bytesRead as uInteger ' число действительно прочитанных байт
dim startupinfo as STARTUPINFO ' структура STARTUPINFO
dim pinfo as PROCESS_INFORMATION ' структура PROCESS_INFORMATION
dim sat as SECURITY_ATTRIBUTES ' структура SECURITY_ATTRIBUTES
dim buffer as zstring * 1024
function = 0
select case uMsg 'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_CREATE ' если сообщение WM_CREATE
hwndEdit = CreateWindowEx _ ' создадим Edit Box
(WS_EX_CLIENTEDGE, _ ' дополнительные стили
EditClass, _ ' класс edit box'а
0, _
WS_CHILD+WS_VISIBLE+ES_MULTILINE+ES_AUTOHSCROLL+ES_AUTOVSCROLL, _ ' стили окна
0, _ ' x
0, _ ' y
0, _ ' ширина
0, _ ' высота
hWnd, _ ' хэндл родительского окна
NULL, _
hModule, _ ' хэндл программы
NULL)
SetFocus(hwndEdit ) ' установим фокус в Edit Box
case WM_CTLCOLOREDIT ' изменение цвета
SetTextColor(cPtr(HDC,wparam),Yellow) ' поменяем цвет текста на желтый
SetBkColor(cPtr(HDC,wparam),Black) ' изменим цвет фона текста на черный
function = cPtr(LRESULT,GetStockObject(BLACK_BRUSH)) ' вернем windows, хэндл черной кисти
exit function
case WM_SIZE ' если сообщение WM_SIZE
MoveWindow _ ' изменим размеры edit box'а
(hwndEdit, _ ' хэндл edit box'а
0, _
0, _
loword(lParam), _ ' ширина
hiword(lParam), _ ' высота
TRUE)
case WM_COMMAND ' если получили сообщение WM_COMMAND
if lParam = 0 then ' если lParam = 0, значит идет сообщение от меню
select case loword(wParam) ' начинаем обрабатывать элементы меню
case IDM_FBC
' заполним члены структуры безопасности. "SECURITY_ATTRIBUTES"
sat.nLength = sizeof(SECURITY_ATTRIBUTES) ' размер структуры
sat.lpSecurityDescriptor = NULL ' назначить дескриптор безопасности поумолчанию
sat.bInheritHandle = TRUE ' новый процесс наследует дескриптор
if Createpipe _ ' если создание пайпа
(@hRead, _ ' указатель на хэндл чтения
@hWrite, _ ' указатель на хэндл записи
@sat, _ ' указатель на структуру безопасности SECURITY_ATTRIBUTES
NULL) _
= NULL then ' завершилось не удачно
MessageBox(hWnd, CreatepipeError, AppName, MB_ICONERROR+MB_OK)
else
startupinfo.cb = sizeof(STARTUPINFO) ' размер структуры STARTUPINFO
GetStartupInfo (@startupinfo) ' заполним структуру STARTUPINFO
startupinfo.hStdOutput = hWrite ' передадим в стандартный вывод хэндл пайпа
startupinfo.hStdError = hWrite ' передадим в стандартный вывод ошибок хэндл пайпа
startupinfo.dwFlags = STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES ' эти члены структуры будут использоваться
startupinfo.wShowWindow = SW_HIDE ' скроем консольное окно
if CreateProcess _ ' если создание процесса
(NULL, _ ' имя исполняемой программы
CommandLine, _ ' параметры командной строки
NULL, _ ' атрибуты безопасности для процесса
NULL, _ ' атрибуты безопасности основной ветви
TRUE, _ ' наследовать открытые хэндлы
NULL, _ ' поведение процесса
NULL, _ ' переменные окружения
NULL, _ ' указатель на строку которая указывает текущий диск и директорию
@startupinfo, _ ' указатель на структуру STARTUPINFO
@pinfo) _' указатель на структуру PROCESS_INFORMATION
= NULL then ' завершилось не удачно
MessageBox(hWnd,CreateprocessError,AppName,MB_ICONERROR+MB_OK)
else
CloseHandle(hWrite) ' закроем хэндл записи пайпа
while TRUE ' цикл
' обнулим буфер
_RtlZeroMemory(@buffer,1024)
if ReadFile _ ' если при чтении пайпа
(hRead, _ ' хэндл чтения пайпа
@buffer, _ ' указатель на буфер
1023, _ ' число читаемых байт
@bytesRead, _ ' указатель на переменную, число действительно прочитанных байт
NULL) _
= 0 then ' данные закончились
exit while ' выходим из цикла
else
SendMessage _ ' пошлем сообщение
(hwndEdit, _ ' хэндл edit box'а
EM_SETSEL, _ ' двигаем курсор к концу текста edit control'а
-1, _
0)
SendMessage _ ' пошлем сообщение
(hwndEdit, _ ' хэндл edit box'а
EM_REPLACESEL, _ ' присоединяем данные
FALSE, _
cPtr(lParam,@buffer)) ' указатель на буфер
end if
wend
end if
CloseHandle(hRead) ' закроем хэндл чтения пайпа
end if
end select
end if
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function
'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _ 'указатель на командную строку
byval iCmdShow as integer ) as integer ' состояние окна при первом появлении
dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG ' структура сообщений
dim hWnd as HWND ' хэндл окна
'структура класса окна wc
' заполняем структуру wc
wc.cbSize = SIZEOF( WNDCLASSEX ) ' размер структуры WNDCLASSEX
wc.style = CS_HREDRAW or CS_VREDRAW ' Стиль окна
wc.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
wc.cbClsExtra = NULL ' резервирование дополнительных байт за концом структуры
wc.cbWndExtra = NULL
wc.hInstance = hInst ' хэндл модуля
wc.hbrBackground = cast(HGDIOBJ, COLOR_ApPWORKSPACE) ' Цвет фона
wc.lpszMenuName = cptr(lpcstr,IDR_MAINMENU) ' IDR_MAINMENU идентификатор меню
wc.lpszClassName = @ClassName ' класс окна
wc.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
wc.hIconSm = wc.hIcon 'Хэндл маленькой иконки
wc.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора
' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if
' Создадим окно
hwnd = CreateWindowEx _
(WS_EX_CLIENTEDGE, _ ' дополнительные стили
@ClassName, _ ' указатель на строку с именем класса окна
@AppName, _ ' указатель на строку с именем окна
WS_OVERLAPPEDWINDOW+WS_VISIBLE, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
400, _ ' ширина окна
200, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных
while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE ) 'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function
файл pipe.bi
- Код:
#define ClassName "pipeWinClass" ' Имя нашего класса окна
#define AppName "One-way pipe Example" ' Имя нашего окна
#define EditClass "EDIT" ' класс edit box'а
#define CreatepipeError "Error during pipe creation"
#define CreateprocessError "Error during process creation"
#define CommandLine "fbc.exe"
#define IDR_MAINMENU 101
#define IDM_FBC 40001
- Код:
#include "pipe.bi"
IDR_MAINMENU MENU DISCARDABLE
{
POPUP "&Action"
{
MENUITEM "&FreeBasic",IDM_FBC
}
}
Последний раз редактировалось: electrik (Вт Май 23, 2017 5:14 pm), всего редактировалось 2 раз(а)
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 21 - пайп
Win32 API. Урок 21. Пайп - продолжение
файл 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.
файл colors.bi
- Код:
#define Black &h000000
#define Blue &h0FF0000
#define Green &h00FF00
#define Cyan &h0FFFF00
#define Red &h0000FF
#define Magenta equ &h0FF00FF
#define Yellow &h00FFFF
#define White &h0FFFFFF
#define Gray &h080808
#define LtGray &HC0C0C0???
Анализ:
Пример вызовет 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.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 21 - пайп
Как мы выясняли freebasic умеет работать с пайпами без костылей.
Надо бы это умение подробнее изучить.
Надо бы это умение подробнее изучить.
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения