Форум: "Начинающим";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Вниз[named pipes] Как? Найти похожие ветки
← →
vegarulez (2012-04-24 00:26) [0]Всем дорбого времени суток!
Уважаемые мастреа, подскажите как сделать тоже самое что написано в статье
http://www.delphimaster.ru/articles/named_pipes/index.html
только в обычном окне на форме - чтобы при нажатии кнопки на форме происходил коннект к именованному каналу а при нажатии другой кнопки происходила отправка данных в канал к примеру из мемо1 и чтение ответа к примеру в мемо2. Прочитав пример - и запустив приложение которе прилагается к статье - понял что это то что нужно. но вот не задача - там всё сделано на диалоговом окне как я понимаю... и у меня не хватает знаний чтобы перенести это всё на форму [тут он краснеет потупив взгляд в пол], там очень много непонятных мне моментов. Прошу помочь с переносом на обычную форму.
← →
vegarulez (2012-04-24 00:49) [1]Основная функция которая отвечает за отправку сообщений в pipe ClientDlgProc для кнопки коннект к каналу я так полагаю нужно то что находится в
case Message of
WM_COMMAND:
подскаэитье что это за значения case Message???
WM_COMMAND:
WM_INITCLIENT:
и т.д.
что это за case с чем с равнение идёт? где выдаются эти ... сообщения или как правильно назвать? т.е. я так полагаю в это диалоговое окно формирует эти состояния, или сообщения... подскажите плиз где про это прочитать?
← →
CRLF (2012-04-24 07:52) [2]Кусок из WM_INITCLIENT переносишь в обработчик события OnClick первой кнопки, для начала диалог убери и имя сервера задавай константой. Кусок из IDB_SEND перенеси в обработчик OnClick второй кнопки.
← →
vegarulez (2012-04-24 10:25) [3]Аха так и сделал. Пока тестирую... вопросы накапливаются. как соберу - напишу вопросы которые появились.
← →
vegarulez (2012-04-24 13:05) [4]пара вопросов:
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 13:07) [5]Вот весь код используемый
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;
← →
Сергей М. © (2012-04-24 13:47) [6]
> CreateThread
> Form1.Memo2.Lines.Add(inBuf);
ждут тебя грабли малыя и великия)
← →
CRLF (2012-04-24 13:52) [7]
> Как при передаче передать значение memo1.Text?
> rc := WriteFile (hPipe, ClntName, MAX_WRITE, bytesWritten,
> @OverLapWrt);
rc := WriteFile (hPipe, PChar(Memo1.Text), Length(Memo1.Text), bytesWritten,
@OverLapWrt); для делфи 2009 и выше
← →
vegarulez (2012-04-24 13:53) [8]))) как бы их обойти? :) и так весь лоб в шишках )
← →
vegarulez (2012-04-24 14:00) [9]CRLF (24.04.12 13:52) [7] >
не, у мну ругается (
D7
← →
vegarulez (2012-04-24 14:17) [10]
var
tmp:PAnsiChar;
begin
tmp:=PAnsiChar(Form1.Memo1.Text);
WriteFile (hPipe, tmp, Length(tmp), bytesWritten,@OverLapWrt);
но что-то абракадабра приходит:
䳄•㉷@
← →
Сергей М. © (2012-04-24 15:04) [11]
> как бы их обойти?
1. Использовать BeginThread вместо CreateThread
2. Не допускать обращений к визуальным vcl-контролам из доп.потоков.
← →
vegarulez (2012-04-24 21:37) [12]
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;
← →
vegarulez (2012-04-24 21:47) [13]вот так вроде работает xml запихивается в канал...сервер вроде получает - отправляет клиентам - обмен происходит.
теперь вопрос - как мне передать в канал пакет "нулевой длины"?
← →
Сергей М. © (2012-04-24 22:57) [14]
> CreateThread
Мало, видать, тебе по балде грабли долбили - еще хочешь)
← →
Cobalt © (2012-04-25 09:20) [15]> как мне передать в канал пакет "нулевой длины"?
для этого уже нужно обзавестись протоколом.
Т.е. не "банально передавать все данные что есть", а вначале передавать длину пакета данных (целое число строго определенной разрядности), а потом сами данные.
← →
vegarulez (2012-04-25 09:48) [16]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) это же будет наверно тоже не правильно - она является тоже переменной главного потока а не дополнительного. Как быть?
← →
vegarulez (2012-04-25 09:49) [17]всмысле если описание переменно помещу в public или private
← →
vegarulez (2012-04-25 09:51) [18]получается чтобы её обновлять (если она будет описна в public или private) надо тоже синхронизацию делать с главным потоком.
← →
Сергей М. © (2012-04-25 22:02) [19]самое простое решение - воспользоваться сообщением wm_copydata
← →
vegarulez (2012-05-09 22:26) [20]хм... странно сначала не обратил внимания...
но оказывается при создании потока
через
BeginThread (nil, 0, @ReadPipe, @hPipe, 0, Dummy)
при вызове процедуры
procedure ReadPipe (hPipe: PHANDLE); stdcall;
hPipe=$DBFFDC
и ничего при этом не работает - вываливает ошибку - неверный дескриптор.
а при
CreateThread (nil, 0, @ReadPipe, @hPipe, 0, Dummy);
hPipe=$455C0C
и всё нормально пашет ошибка не появляется... хотя смотрю переменную прям перед вызовом функций CreateThread или BeginThread - она одна и таже (hpipe=1880).
Вопрос почему тогда в при запуски потока проверяя в нём значение приходящей переменной они разняться???? функция CreateThread или BeginThread же передаёт в поток только адрес переменной(указатель) правильно я понимаю???
← →
Сергей М. © (2012-05-09 22:34) [21]
stdcall
ты от балды напмсал, когда BeginThread() объявлял ?
← →
vegarulez (2012-05-09 22:43) [22]аха убрал - ошибки нет... спасибо.
что значит stdcall ???
← →
vegarulez (2012-05-09 22:59) [23]а... всё... вроде почитал...
это типа когда используются функции не апишные а из внешних библиотек... а так как CreateThread скорее всего не апишная в примере и стоит stdcall...
Gо умолчанию делфи использует fastcall.
Надо теперь только догнать почему оно не работает с этим вызовом.
← →
Dennis I. Komarov © (2012-05-09 23:21) [24]
> vegarulez (09.05.12 22:59) [23]
Овсянка, Сэр...
← →
Германн © (2012-05-09 23:45) [25]
> vegarulez (09.05.12 22:59) [23]
>
> а... всё... вроде почитал...
> Надо теперь только догнать почему оно не работает с этим
> вызовом.
Теперь это называется почитал?
← →
vegarulez (2012-05-10 07:40) [26]просто много чего не понятно там... слов всяких незнакомых... не совсем понятен смысл. в общих чертах описал, как я понял.
← →
Inovet © (2012-05-10 09:12) [27]> [26] vegarulez (10.05.12 07:40)
> в общих чертах
вызовы функций с различными модификаторами различаются последовательностью передачи параметров и местом их расположения: стек и/или регистры. Соответсвенно формируется различный вход в функцию, обращение к параметрам в ней, и освобождение стека при выходе. Также различается скорость вызова функции. Также возможность/невозможность передать в функцию заранее неизвестное количество параметров - освобождать стек в самой функции или же в месте её вызова.
← →
Сергей М. © (2012-05-11 14:24) [28]
> CreateThread скорее всего не апишная в примере и стоит stdcall.
Самая что ни на есть "апишная" она)
Потому и stdcall в примере фигурирует.
А BeginThread, напротив, не "апишная", а нативная дельфийская.
И писана она с дифолтным дельфийским соглашением fastcall
Потому и stdcall для нее НЕприменим.
← →
vegarulez (2012-05-11 21:23) [29]оки. спасибо большое.
ребят теперь следующая проблема - вроде всё работает - на тестовом сервере который вместе с примером идёт.
делаю с тем приложением с которым программа и должна взаимодействовать - приходит в ответ на запрос :
?????????•??????????????????????????????????????????????????????????????????? ???????????????
логи программы поднимаю - она в канал вроде всё правильно шлёт. подскажите что не так делаю при чтении из канала. У меня подозрением что это utf8. Как правильно перекодировать чтобы читабельно было?
← →
vegarulez (2012-05-11 21:24) [30]хотя может и не в utf8 вовсе дело.
← →
Сергей М. © (2012-05-11 22:01) [31]
> приходит в ответ на запрос
И нафих нужно любоваться этими вопросами ?
Ты гекс-дамп ответа приведи - тогда наверняка что-то проояснится ..
← →
vegarulez (2012-05-11 22:05) [32]пытаюсь в анси стринг запихнуть... там же аррэй оф вайдчар... но что-то он ошибку выдаёт когда делаю
for i:=0 to sizeof(inBuf)
s:=s+inBuf[i];
как правильно приведение типов данных произвести??? чтобы в стринге всё содержалось?
← →
Anatoly Podgoretsky © (2012-05-11 22:07) [33]
> vegarulez (11.05.12 21:23) [29]
Это не utf8
← →
vegarulez (2012-05-11 22:11) [34]ну это в мемо у меня такая картина наблюдается. хотя до этого с тестовым сервером делал - там нормально всё отображалось.
а что это может быть?
← →
vegarulez (2012-05-11 22:23) [35]
s:="";
for i:=0 to Length(inBuf)-1 do
s:=s+inBuf[i];
Form1.Memo2.Lines.Add(s);
в строку пытаюсь запихнуть и посомтреть - но тоже самое получаю... в мемо... как мне hex содержимое именно в меме получить???
← →
Сергей М. © (2012-05-11 22:36) [36]
> там же аррэй оф вайдчар
"там же" это где ?
> как мне hex содержимое именно в меме получить?
ты уже выяснил что из чебя представляет тип widechar
← →
vegarulez (2012-05-11 22:42) [37]в процедуре приведённой выше
для чтения из каналаprocedure ReadPipe (hPipe: PHANDLE);
var
inBuf: array[0..IN_BUF_SIZE] of WideChar;
"WideChar Тип переменной содержащий отдельный Интернациональный символ"
но просто при тестовом сервере у меня там содержались символы сразу в нормальном виде а не в hex виде... т.е. когда в компиляторе смотрел что в переменной.
← →
vegarulez (2012-05-11 22:51) [38]по логам по идее сервер на мой запрос должен отвечать:
<Acv version="3.04">
<file>
<reqReadfile/>
</file>
</Acv>
ну т.е. в логах якобы он это в канал плюёт... но приходят вопросики (((
← →
Сергей М. © (2012-05-11 23:19) [39]
> но просто при тестовом сервере
А теперь, т.е. в ситуации с "вопросами", это не "просто тестовый сервер" - это другой сервер, который вовсе не обязан отвечать на запросы текстом вообще и юникодовым текстом в частности.
И неизвестно на каком основании клиента одного сервера ты пытаешься присобачить для работы совсем с другим сервером.
← →
Сергей М. © (2012-05-11 23:21) [40]
> в логах якобы он это в канал плюёт
Так он же вовсе не обязан "плевать" юникодом)
Может он ansi-текст выплевывает)...
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.071 c