![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
[named pipes] Как? [D7, XP]
vegarulez © (2012-04-24 00:26:00)Всем дорбого времени суток!
Уважаемые мастреа, подскажите как сделать тоже самое что написано в статье
http://www.delphimaster.ru/articles/named_pipes/index.html
только в обычном окне на форме - чтобы при нажатии кнопки на форме происходил коннект к именованному каналу а при нажатии другой кнопки происходила отправка данных в канал к примеру из мемо1 и чтение ответа к примеру в мемо2. Прочитав пример - и запустив приложение которе прилагается к статье - понял что это то что нужно. но вот не задача - там всё сделано на диалоговом окне как я понимаю... и у меня не хватает знаний чтобы перенести это всё на форму [тут он краснеет потупив взгляд в пол], там очень много непонятных мне моментов. Прошу помочь с переносом на обычную форму.
Сергей М. (2012-04-25 22:02:00) [41]самое простое решение - воспользоваться сообщением wm_copydata
vegarulez (2012-04-25 09:51:00) [42]получается чтобы её обновлять (если она будет описна в public или private) надо тоже синхронизацию делать с главным потоком.
vegarulez (2012-04-25 09:49:00) [43]всмысле если описание переменно помещу в public или private
vegarulez (2012-04-25 09:48:00) [44]1. BeginThread аха поменял.
2. Вопрос как сделать syncronize(updatememo)в процедуре:
procedure ReadPipe (hPipe: PHANDLE); stdcall;
var
inBuf: array[0..IN_BUF_SIZE] of WideChar;
bytesRead: DWORD;
rc: Boolean;
lastError: DWORD;
hEventRd: THANDLE;
OverLapRd: OVERLAPPED;
bytesTrans: DWORD;
begin
inBuf[0] := #0;
hEventRd := CreateEventW (nil, true, false, nil);
FillChar (OverLapRd, sizeof(OVERLAPPED), 0);
OverLapRd.hEvent := hEventRd;
// Бесконечный цикл чтения из канала, до тех пор,пока не разорвется соединение
// Чтение происходит асинхронно, с ожиданием по событию. После того, как сооб-
// щение прочитано, оно помещается в элемент редактирования.
while true do begin
rc := ReadFile (hPipe^, inBuf, IN_BUF_SIZE*sizeof(WideChar), bytesRead,
@OverLapRd); // перменная булеан , пытаемся прочитать из pipe
if not rc then begin
lastError := GetLastError;
// Проверка на три вида ошибки:
// IO_PENDING (ожидать завершения операции), BROKEN_PIPE (выйти из цикла)
// и остальные (выдать сообщение, выйти из цикла и умереть)
if lastError = ERROR_IO_PENDING then begin
WaitForSingleObject (hEventRd, INFINITE);
end else begin
if lastError = ERROR_BROKEN_PIPE then
MessageBoxW (hWndClient,
'The connection to this client has been broken.', '', MB_OK)
else
ShowLastErrorMessage(hWndClient,
PAnsiChar('Client: Debug():ReadFile'));
Break;
end;
end;
GetOverlappedResult (hPipe^, OverLapRd, bytesTrans, false);
inBuf[bytesTrans div SizeOf(WideChar)] := #0; // Завершить полученную строку
SendMessageW (GetDlgItem (hWndClient, IDD_EDITREAD), EM_REPLACESEL,
0, LPARAM(@inBuf));
// Перевести курсор на следующую строку в элементе редактирования :)
SendMessageW (GetDlgItem (hWndClient, IDD_EDITREAD), EM_REPLACESEL,
0, LPARAM(PWideChar(CrLf)));
Form1.Memo2.Lines.Add(inBuf);
Form1.Memo2.Lines.Add(CrLf);
end;
// Если соединение с каналом разорвано, завершить программу
PostMessageW (hWndClient, WM_GO_AWAY, 0,0);
ExitThread(0);
end;
если переменная inBuf определена только для этой процедуры. если же я её сделаю доступной для всего приложения чтобы использовать её в syncronize (updatememo) это же будет наверно тоже не правильно - она является тоже переменной главного потока а не дополнительного. Как быть?
Cobalt (2012-04-25 09:20:00) [45]> как мне передать в канал пакет "нулевой длины"?
для этого уже нужно обзавестись протоколом.
Т.е. не "банально передавать все данные что есть", а вначале передавать длину пакета данных (целое число строго определенной разрядности), а потом сами данные.
Сергей М. (2012-04-24 22:57:00) [46]
> CreateThread
Мало, видать, тебе по балде грабли долбили - еще хочешь)
vegarulez (2012-04-24 21:47:00) [47]вот так вроде работает xml запихивается в канал...сервер вроде получает - отправляет клиентам - обмен происходит.
теперь вопрос - как мне передать в канал пакет "нулевой длины"?
vegarulez (2012-04-24 21:37:00) [48]
procedure TForm1.bt_sendClick(Sender: TObject);
var
rc:boolean;
bytesWritten: DWORD;
Dummy: DWORD;
tmp:PAnsiChar;
outBuf: array[0..OUT_BUF_SIZE] of WideChar;
sendBuf: array[0..OUT_BUF_SIZE] of WideChar;
begin
tmp:=PAnsiChar(Form1.Memo1.Text);
// Сообщить серверу свое имя
ClntName[0]:='A';
GetWindowTextW (Form1.Memo1.Handle, outBuf,
MAX_WRITE);
//Form1.Memo1.Handle
lstrcpyw(sendBuf, ClntName);
lstrcatw(sendBuf, ':');
lstrcatw(sendBuf, outBuf);
// перменная типа булеан смотрим есть ли запись в pipe или произошла ошибка при записи
WriteFile (hPipe, outBuf, MAX_WRITE, bytesWritten,@OverLapWrt);
if not rc then // Если IO_PENDING, ожидать звершения операции
if GetLastError = ERROR_IO_PENDING then
WaitForSingleObject (hEventWrt, INFINITE);
// Создать поток чтения из канала.
CreateThread (nil, 0, @ReadPipe, @hPipe, 0, Dummy);
end;
Сергей М. (2012-04-24 15:04:00) [49]
> как бы их обойти?
1. Использовать BeginThread вместо CreateThread
2. Недопускать обращений к визуальным vcl-контролам из доп.потоков.
vegarulez (2012-04-24 14:17:00) [50]
var
tmp:PAnsiChar;
begin
tmp:=PAnsiChar(Form1.Memo1.Text);
WriteFile (hPipe, tmp, Length(tmp), bytesWritten,@OverLapWrt);
но что-то абракадабра приходит:
䳄㉷@
vegarulez (2012-04-24 14:00:00) [51]CRLF (24.04.12 13:52) [7] >
не, у мну ругается (
D7
vegarulez (2012-04-24 13:53:00) [52]))) как бы их обойти? :) и так весь лоб в шишках )
CRLF (2012-04-24 13:52:00) [53]
> Как при передаче передать значение memo1.Text?
> rc := WriteFile (hPipe, ClntName, MAX_WRITE, bytesWritten,
> @OverLapWrt);
rc := WriteFile (hPipe, PChar(Memo1.Text), Length(Memo1.Text), bytesWritten,
@OverLapWrt); для делфи 2009 и выше
Сергей М. (2012-04-24 13:47:00) [54]
> CreateThread
> Form1.Memo2.Lines.Add(inBuf);
ждут тебя грабли малыя и великия)
vegarulez (2012-04-24 13:07:00) [55]Вот весь код используемый
procedure ReadPipe (hPipe: PHANDLE); stdcall;
var
inBuf: array[0..IN_BUF_SIZE] of WideChar;
bytesRead: DWORD;
rc: Boolean;
lastError: DWORD;
hEventRd: THANDLE;
OverLapRd: OVERLAPPED;
bytesTrans: DWORD;
begin
inBuf[0] := #0;
hEventRd := CreateEventW (nil, true, false, nil);
FillChar (OverLapRd, sizeof(OVERLAPPED), 0);
OverLapRd.hEvent := hEventRd;
// Бесконечный цикл чтения из канала, до тех пор,пока не разорвется соединение
// Чтение происходит асинхронно, с ожиданием по событию. После того, как сооб-
// щение прочитано, оно помещается в элемент редактирования.
while true do begin
rc := ReadFile (hPipe^, inBuf, IN_BUF_SIZE*sizeof(WideChar), bytesRead,
@OverLapRd); // перменная булеан , пытаемся прочитать из pipe
if not rc then begin
lastError := GetLastError;
// Проверка на три вида ошибки:
// IO_PENDING (ожидать завершения операции), BROKEN_PIPE (выйти из цикла)
// и остальные (выдать сообщение, выйти из цикла и умереть)
if lastError = ERROR_IO_PENDING then begin
WaitForSingleObject (hEventRd, INFINITE);
end else begin
if lastError = ERROR_BROKEN_PIPE then
MessageBoxW (hWndClient,
'The connection to this client has been broken.', '', MB_OK)
else
ShowLastErrorMessage(hWndClient,
PAnsiChar('Client: Debug():ReadFile'));
Break;
end;
end;
GetOverlappedResult (hPipe^, OverLapRd, bytesTrans, false);
inBuf[bytesTrans div SizeOf(WideChar)] := #0; // Завершить полученную строку
SendMessageW (GetDlgItem (hWndClient, IDD_EDITREAD), EM_REPLACESEL,
0, LPARAM(@inBuf));
// Перевести курсор на следующую строку в элементе редактирования :)
SendMessageW (GetDlgItem (hWndClient, IDD_EDITREAD), EM_REPLACESEL,
0, LPARAM(PWideChar(CrLf)));
Form1.Memo2.Lines.Add(inBuf);
Form1.Memo2.Lines.Add(CrLf);
end;
// Если соединение с каналом разорвано, завершить программу
PostMessageW (hWndClient, WM_GO_AWAY, 0,0);
ExitThread(0);
end;
procedure TForm1.bt_connectClick(Sender: TObject);
var
rc:boolean;
bytesWritten: DWORD;
Dummy: DWORD;
APipeName: string;
fileName: array[0..LINE_LEN+NAME_SIZE+sizeof(WideChar)*2] of WideChar;
begin
//APipeName:= Format('\\%s\pipe\test', [WideCharToString(ShrName)]);
APipeName:=Edit1.Text;
// Соединиться с сервером
hPipe := CreateFileW ('\\.\pipe\test',
GENERIC_WRITE or // Доступ на чтение/запись
GENERIC_READ,
FILE_SHARE_READ or // Разделенный доступ
FILE_SHARE_WRITE,
nil,
OPEN_EXISTING, // Канал должен существовать
FILE_FLAG_OVERLAPPED, // Использовать асинхронный ввод/вывод
0);
hEventWrt := CreateEvent (nil, true, false, nil);
OverLapWrt.hEvent := hEventWrt;
end;
procedure TForm1.bt_sendClick(Sender: TObject);
var
rc:boolean;
bytesWritten: DWORD;
Dummy: DWORD;
begin
// Сообщить серверу свое имя
ClntName[0]:='A';
rc := WriteFile (hPipe, ClntName, MAX_WRITE, bytesWritten,
@OverLapWrt); // перменная типа булеан смотрим есть ли запись в pipe или произошла ошибка при записи
if not rc then // Если IO_PENDING, ожидать звершения операции
if GetLastError = ERROR_IO_PENDING then
WaitForSingleObject (hEventWrt, INFINITE);
// Создать поток чтения из канала.
CreateThread (nil, 0, @ReadPipe, @hPipe, 0, Dummy);
end;
vegarulez (2012-04-24 13:05:00) [56]пара вопросов:
1.ClntName: array [0..NAME_SIZE] of WideChar; // Имя клиента
Это переменная массив чаров. Вопрос он используется для передачи имени клиента на сервер:
rc := WriteFile (hPipe, ClntName, MAX_WRITE, bytesWritten,
@OverLapWrt);
Вопрос получается что там просто набор [t],[e],[s],[t] как мне обычный стринг перегнать в эту переменную? И вопрос почему нельзя просто стринговую переменную использовать при передачи имени?
Ну да ладно это как нибудь разложу в массив for i:=0 to length(s)-1 do и т.д.
Просто интересно как стринг сразу использовать.
2. Как при передаче передать значение memo1.Text?
rc := WriteFile (hPipe, ClntName, MAX_WRITE, bytesWritten,
@OverLapWrt);
Получается мне его также перегонять в array of char?
BOOL WriteFile(
HANDLE hFile, // handle to file to write to
LPCVOID lpBuffer, // pointer to data to write to file
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O
);
и подставлять вместо ClntName? Просто у меня там лежит xml довольно большой. Судя из описания WriteFile там требуется лишь указатель на данные. Подскажите как мне просто создать указатель на данные из TMemo?
vegarulez (2012-04-24 10:25:00) [57]Аха так и сделал. Пока тестирую... вопросы накапливаются. как соберу - напишу вопросы которые появились.
CRLF (2012-04-24 07:52:00) [58]Кусок из WM_INITCLIENT переносишь в обработчик события OnClick первой кнопки, для начала диалог убери и имя сервера задавай константой. Кусок из IDB_SEND перенеси в обработчик OnClick второй кнопки.
vegarulez (2012-04-24 00:49:00) [59]Основная функция которая отвечает за отправку сообщений в pipe ClientDlgProc для кнопки коннект к каналу я так полагаю нужно то что находится в
case Message of
WM_COMMAND:
подскаэитье что это за значения case Message???
WM_COMMAND:
WM_INITCLIENT:
и т.д.
что это за case с чем с равнение идёт? где выдаются эти ... сообщения или как правильно назвать? т.е. я так полагаю в это диалоговое окно формирует эти состояния, или сообщения... подскажите плиз где про это прочитать?