Есть у меня парочка вопросов к всезнающему All
Итак, имеется у меня прога. Прога отсылает какие-то запросы и получает ответы. Все усложняется тем, что этот процесс происходит асинхронно. А при такой специфике возникает так много нюансов и особенностей, что я уже задолбался
Вводная:
~~~~~~
Запросы бывают разных типов. Некоторые выглядят как "запросить текущее время сервера", с их обработкой проблем не возникает, надо просто обрабатывать их при получении.
Однако есть и другие запросы. К примеру, в основной форме есть команда меню "Изменить список категорий". При ее выборе открывается дочерняя форма, в которой отображается этот самый список и имеется интерфейс для его редактирования.
Сложность тут в том, что при выборе команды "Изменить список категорий" нельзя сразу открыть дочернюю форму. Надо вначале отправить соответствующий запрос, а только по приходу ответа открыть эту форму (с заполненным списком).
Решение:
~~~~~~
На данный момент у меня это реализовано подобным образом.
Имеется такой фрагмент (код чуть упрощен, на практике он больше для оптимизации поиска):
- Код: Выделить всё
Public Enum Actions
Action1
Action2
...
End Enum
Private Const msgMax As Long = 10
Private Type MsgBuffer
Clock As Long
Timeout As Long
Action As Actions
MsgID As String
MsgQuery As String
End Type
Private msg(1 To msgMax) As MsgBuffer
Public Sub AddMsgBuffer(MsgID As String, Query As String, Optional ByVal Action As Actions, Optional ByVal Timeout As Long)
If msgCount >= msgMax Then Exit Sub
msgCount = msgCount + 1
With msg(msgCount)
.Clock = GetTickCount()
.Timeout = Timeout
.Action = Action
.MsgID = MsgID
.MsgQuery = Query
End With
End Sub
Public Sub RemoveMsgBuffer(MsgID As String)
Dim I As Long, I0 As Long
If Len(MsgID) = 0 Then
msgStart = 1
msgCount = 0
Exit Sub
End If
For I = 1 To msgCount
If msg(I).MsgID = MsgID Then
I0 = I
Exit For
End If
Next I
If I0 = 0 Then Exit Sub
For I = I0 To msgCount - 1
msg(I) = msg(I + 1)
Next I
msgCount = msgCount - 1
End Sub
Когда приложение формирует запрос, то вызывается процедура ClientRequest, в которую передается действие (Actions), запрос и параметры для запроса. В этой процедуре формируется строка запроса и одновременно вызывается AddMsgBuffer. MsgID является уникальным идентификатором сообщения.
Когда приходит ответ, в ответе передается идентификатор MsgID (идентификатор того сообщения, на которое и был сформирован запрос). По этому MsgID определяется Action и MsgQuery. После получения и обработки ответа выполняется RemoveMsgBuffer.
Во всех дочерних формах имеются Friend-процедуры ExtControl(...), через которые основная форма передает полученные ответы. К примеру, в дочерней форме был добавлен новый элемент в список. Эта форма вызывает ClientRequest(Action:=AddListItem,...) с необходимыми параметрами и блокируется (Enabled=False, MousePointer=...). Когда приходит ответ от сервера, соответствующая процедура делает парсинг ответа и определяет, на какой запрос (вернее, на какой Action) пришел ответ. Если это AddListItem, то ответ передается в frmListEditor.ExtControl(Action, ResultCode, Data). В процедуре ExtControl этот ответ обрабатывается (элемент добавляется в список или показывается сообщение об ошибке) и форма снова в режиме ожидания.
Все это в настоящий момент работает, но слишком громоздко и ненадежно. Да и глубину стека мне порой бывает просто страшно представить.
Лучше всего было бы обойтись вообще без очереди запросов, но как это сделать при асинхронной передаче данных, я не представляю. Правда можно попытаться включить на сокете режим синхронной передачи данных, но это крайний случай.
Кто уже сталкивался с подобными задачами, может вы что посоветуете? А то моя реализация работает, но даже мне она кажется слишком усложненной и ненадежной.
Заранее спасибо