Имя: Пароль:
1C
1С v8
Асинхронный сокет внутри компоненты. ☑
0 Gugatar
 
29.03.15
✎
14:08
Добрый день .  Стоит задача реализовать компоненту для  1С  которая могла бы выполнять функции  клиента. Т.е. есть удаленный сервер, к которому  подключаемся из 1С, режим работы обязательно асинхронный. Почитав немного на эту тему, понял что реализация должна быть через сообщения Windows и через создание окна, которое будет обрабатывать сообщения.  На Delphi видел в интернете пару примеров, но они написаны с использованием TClientSocket  в режиме ctNonBlocking. Мне нужно написать на C++.  В компоненте  при вызове функции CallAsProc создаю окно, опиcываю оконную процедуру. Пока все происходит внутри dll – все работает. Как только код возвращается в 1С – выскакивает ошибка. Необработанное исключение по адресу 0x0F10113B в 1cv8.exe: 0xC0000005: нарушение прав доступа при исполнении по адресу 0x0F10113B. Кто сталкивался с решением подобной проблемы подскажите, может вообще не в ту сторону копаю?
1 romix
 
29.03.15
✎
16:07
Так а встроенные средства работы из 1С 8.3 HTTP вроде и есть асинхронные?
2 Gugatar
 
29.03.15
✎
16:19
Может быть и так, но должно работать на 8.2. HTTP не подойдет, нужна работа на уровне сокета.
3 H A D G E H O G s
 
29.03.15
✎
16:36
(0) Ты копаешь не в ту строну.
4 Gugatar
 
29.03.15
✎
16:46
Подскажи направление.
5 H A D G E H O G s
 
29.03.15
✎
16:50
(4) "понял что реализация должна быть через сообщения Windows и через создание окна, которое будет обрабатывать сообщения. "

Что за ересь?

Создаем поток, который ждет сообщения от сервера, записывает в буфер данные сообщения и отправляет сообщение в 1С через
iEvent.ExternalEvent('TCPClient', 'УСПЕХ', Inttostr(GetCurrentThreadId));

1C во ВнешнемСобытии вызывает метод ВК, который читает из буфера ВК накопленные данные (скорее всего ComSafeArray, либо ДвоичныеДанные).
6 Gugatar
 
29.03.15
✎
17:32
(5) Отлично, спасибо тебе огромное, а мог бы ты раскрыть ту первую часть по которой ты пробежал весьма поверхностно немного поглубже. "Создаем поток, который ждет сообщения от сервера," и как бы это все сделать в асинхронном режиме с неблокирующим сокетом...? Если тебе не сложно мог бы ты привести пример.
7 H A D G E H O G s
 
29.03.15
✎
17:37
(6) Вот тебе пример асинхронного чтения COM-порта, то же самое:

Procedure T_vk_object.ReadThread(); stdcall;
var
  tmp: Cardinal;
  Buffer: Pointer;
  StaticBuffer: array [0 .. 80000] of Byte;
  BytesRead: Cardinal;
  ExtendedResultList: TStructureList;
  RetStructure: TStructure;
  ResultArray: OleVariant;
begin
  tmp := EV_RXCHAR;
  repeat
    WaitCommEvent(hPort, tmp, nil);
    if not ReadFile(hPort, StaticBuffer, 80000, BytesRead, nil) then
    begin
      ErrorCode := GetLastError;
      ErrorDescription := _GetErrorMsg(ErrorCode);
      ExtendedResultList := self.ExtendedResultList;
      RetStructure := TStructure.Create;
      ExtendedResultList.Add(RetStructure);
      RetStructure.Insert('ID', ID);
      self.ExtendedResultList := ExtendedResultList;
      iEvent.ExternalEvent('COMPORT', 'ОШИБКА', Inttostr(GetCurrentThreadId));
      Continue;
    end;
    if BytesRead = 0 then
      Continue;
    ResultArray := VarArrayCreate([0, 0], VarOfType);
    VarArrayRedim(ResultArray, Round(BytesRead / DataType) - 1);
    Buffer := VarArrayLock(ResultArray);
    CopyMemory(Buffer, @StaticBuffer, BytesRead);
    VarArrayUnLock(ResultArray);
    ExtendedResultList := self.ExtendedResultList;
    RetStructure := TStructure.Create;
    ExtendedResultList.Add(RetStructure);
    RetStructure.Insert('Данные', ResultArray);
    RetStructure.Insert('ID', ID);
    self.ExtendedResultList := ExtendedResultList;
    iEvent.ExternalEvent('COMPORT', 'УСПЕХ', Inttostr(GetCurrentThreadId));
  until false;

end;
8 Gugatar
 
29.03.15
✎
18:13
Спасибо конечно, но решение которое ты предложил заставляет крутить в цикле и постоянно проверять, не пришли ли тебе данные, тем самым куча времени теряется в никуда. Мне хотелось уйти от этого принципа и воспользоваться функциями  из асинхронного расширения Windows. WSAAsyncSelect ...
9 H A D G E H O G s
 
29.03.15
✎
18:28
(8) плохо.

Функция WaitCommEvent ожидает какое-то событие, которое произойдет для заданного коммуникационного устройства. Пакет событий, которые проверяются этой функцией, содержится в маске события, связанной с дескриптором устройства.
10 Gugatar
 
29.03.15
✎
23:41
(9) Странно, не понимаю какое отношение сюда имеет WaitCommEvent, и как ей можно подсунуть сокет. Через CreateFile нельзя получить сокет... Пожалуйста!!! если то что ты пишешь это не так лишь бы было, потрать 5-ть минут своего времени напиши реальный пример, не думаю что он будет больше 10 строк. Спасибо!!!
11 Torquader
 
30.03.15
✎
00:27
(10) Очень просто - читаем WSAEventSelect и чешем репу.
Всё достаточно просто - только вот главный вопрос - а зачем ?
Не проще ли из вашей поделки на Delphi вызвать 1С через внешнее соединение ?
12 Gugatar
 
30.03.15
✎
11:11
(11) 1)Еще чуть чуть и у меня будет плешь.
2)Ответ в (0)
3)У меня нет ничего на Delphi кроме примеров других людей,  задача стоит писать не на Delphi, а на C++. Мне кстати очень хотелось бы узнать как реализован TClientSocket.
2 + 2 = 3.9999999999999999999999999999999...