Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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.083 c
2-1347519862
MsGuns
2012-09-13 11:04
2013.03.22
Колонка для "птичек" в гриде.


15-1328642557
Юрий Зотов
2012-02-07 23:22
2013.03.22
И снова нужен человек


15-1343742743
qetuo
2012-07-31 17:52
2013.03.22
Чем бы потестить внешний хард


15-1347654603
Юрий
2012-09-15 00:30
2013.03.22
С днем рождения ! 15 сентября 2012 суббота


15-1342899092
без имени
2012-07-21 23:31
2013.03.22
Настройка в Delphi 7





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский