Есть компонент (ATL), а в нем отдельный 'worker thread', который время от времени рождает события, об которых надо сообщать клиенту на VB. Для этого посылает WM_MY окну компонента, оно зажигает событие. Зажигать Еvent из 'worker thread' нельзя (он не должен тормозиться)
Проблема : Если во время обработки одного события в VB (висмт MsgBox) на компонент падает второе WM_MY, он зажигает событие, но это второе просто 'проглатывается' в VB
Вопрос : Есть какой-нибудь простой метод дождаться, пока первый Event отработает, и только потом бросать на клиента второй ? Или делать это надо как-то иначе ?
Здравствуйте bnk, Вы писали:
bnk>Есть компонент (ATL), а в нем отдельный 'worker thread', который время от времени рождает события, об которых надо сообщать клиенту на VB. Для этого посылает WM_MY окну компонента, оно зажигает событие. Зажигать Еvent из 'worker thread' нельзя (он не должен тормозиться) bnk>Проблема : Если во время обработки одного события в VB (висмт MsgBox) на компонент падает второе WM_MY, он зажигает событие, но это второе просто 'проглатывается' в VB bnk>Вопрос : Есть какой-нибудь простой метод дождаться, пока первый Event отработает, и только потом бросать на клиента второй ? Или делать это надо как-то иначе ?
Event обрабатывается синхронно. Т.е. пока твой конрол и VB не обработали первый, второй евент не возникнет. Может как второй WM_MY не доходит до окна контрола?
Здравствуйте Максим Алексейкин, Вы писали:
МА>Event обрабатывается синхронно. Т.е. пока твой конрол и VB не обработали первый, второй евент не возникнет. Может как второй WM_MY не доходит до окна контрола?
Максим, проблема в том что второй евент возникает. Я проверял в дебаггере, ситуация следующая: Входит в обработчик WM_MY, запускается Fire_MY(..), после чего, не выходя из этого обработчика , входит в него повторно ха-ха и снова делает Fire_MY()
Происходит енто, я думаю, потому, что WM_MY's посылаются компоненту той самой 'worker thread' (асинхронно), а когда компонент ожидает 'окончания евета' в Fire_MY(), он радостно диспатчит все WM_xx, и входит в обработчик повторно.
В чем и вопрос, с какой стороны это безобразие можно объехать
Здравствуйте bnk, Вы писали:
bnk>Здравствуйте Максим Алексейкин, Вы писали:
МА>>Event обрабатывается синхронно. Т.е. пока твой конрол и VB не обработали первый, второй евент не возникнет. Может как второй WM_MY не доходит до окна контрола?
bnk>Максим, проблема в том что второй евент возникает. Я проверял в дебаггере, ситуация следующая: Входит в обработчик WM_MY, запускается Fire_MY(..), после чего, не выходя из этого обработчика , входит в него повторно ха-ха и снова делает Fire_MY() bnk>Происходит енто, я думаю, потому, что WM_MY's посылаются компоненту той самой 'worker thread' (асинхронно), а когда компонент ожидает 'окончания евета' в Fire_MY(), он радостно диспатчит все WM_xx, и входит в обработчик повторно. bnk>В чем и вопрос, с какой стороны это безобразие можно объехать
Попробуй ограничить доступ к Fire_MY() при помощи критической секции. Т.е. пока не вернулся из первого евента не делать следующие.
Удачи.
Здравствуйте bnk, Вы писали:
bnk>Максим, проблема в том что второй евент возникает. Я проверял в дебаггере, ситуация следующая: Входит в обработчик WM_MY, запускается Fire_MY(..), после чего, не выходя из этого обработчика , входит в него повторно ха-ха и снова делает Fire_MY()
bnk>В чем и вопрос, с какой стороны это безобразие можно объехать
Поставь критсекцию на вызов Fire_MY():
CComAutoCriticalSection cs; // global
...
cs.Lock();
Fire_MY();
cs.Unlock();
Либо то же самое через объект, лочащий при создании и т.п.
Здравствуйте George_Seryakov, Вы писали:
GS>Здравствуйте bnk, Вы писали:
GS>Поставь критсекцию на вызов Fire_MY():
Спасибо за совет, но это не проходит, т.к. ниточка, входящая в обработчик WM_MY, одна и та же при первом и при втором вхождении :). Так что при попытке войти в CS во второй раз все просто повисает.
Насчет
GS> CComAutoCriticalSection cs; // global
Мне думается, что CComAutoCriticalSection + Single-thread-appartament = Nothing
Мне пока удалось изобрести вот какой объезд на эту проблему :-
list<pair<WPARAM, LPARAM> > m_queue;
LRESULT CCmdShell::OnMY(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_queue.push_back(make_pair(wParam,lParam));
if (m_messages.size() == 1) // inside only at 'first' entry
{
while (m_queue.size() > 0) // size may be added with 'recursive' calls
{
pair<WPARAM,LPARAM> p = m_queue.front();
Fire_MY(...); // <-- 'recursive' call from here
m_queue.pop_front();
}
}
}
Здравствуйте bnk, Вы писали:
bnk>Есть компонент (ATL), а в нем отдельный 'worker thread', который время от времени рождает события, об которых надо сообщать клиенту на VB. Для этого посылает WM_MY окну компонента, оно зажигает событие. Зажигать Еvent из 'worker thread' нельзя (он не должен тормозиться) bnk>Проблема : Если во время обработки одного события в VB (висмт MsgBox) на компонент падает второе WM_MY, он зажигает событие, но это второе просто 'проглатывается' в VB bnk>Вопрос : Есть какой-нибудь простой метод дождаться, пока первый Event отработает, и только потом бросать на клиента второй ? Или делать это надо как-то иначе ?
Проблемма состоит в том, что вы АБСОЛЮТНО ИЗВРАЩЁННО реализуете механизм событий. Для таких вещей есть ConnectionPoint..., причём я решал задачу полностью похожую на вашу при помощи ConnectionPoint. (особых проблемм там быть не должно) Если решитесь переделать, то могу помочь кодом (стандартная реализация механизма точек стыковки из ATL вам не подойдёт, так как вы будете вызывать события не из того потока, в котором VB будет "садится" на события и придётся воспользоваться маршалингом, но это довольно просто)
Здравствуйте Tom, Вы писали:
Tom>Проблемма состоит в том, что вы АБСОЛЮТНО ИЗВРАЩЁННО реализуете механизм событий. Для таких вещей есть ConnectionPoint...,
Многоуважаемый Tom, я думаю, что знаю, что такое ConnectionPoint, и с чем ее едят. В письме я подразумевал под 'зажечь event' именно вызов через ConnectionPoint. Я понимаю, что можно зажечь event из второй thread, и знаю, как отмаршалить InterfacePointer для этого. Проблема в том, что Зажигать Event из этой thread нельзя, т.к., повторяю, этот thread Не должен тормозиться, а именно это и произойдет, если сделать вызов на ConnectionPoint оттуда.
Здравствуйте bnk, Вы писали:
bnk>Есть компонент (ATL), а в нем отдельный 'worker thread', который время от времени рождает события, об которых надо сообщать клиенту на VB. Для этого посылает WM_MY окну компонента, оно зажигает событие. Зажигать Еvent из 'worker thread' нельзя (он не должен тормозиться) bnk>Проблема : Если во время обработки одного события в VB (висмт MsgBox) на компонент падает второе WM_MY, он зажигает событие, но это второе просто 'проглатывается' в VB bnk>Вопрос : Есть какой-нибудь простой метод дождаться, пока первый Event отработает, и только потом бросать на клиента второй ? Или делать это надо как-то иначе ?
Здравствуйте Ivan, Вы писали:
I>ЭТО Q178078 случайно не про твою ситуацию ?
Нет, к сожалению Здесь компонент создается из MSAccessa. Но события действительно _НЕ_ случаются, как и должно быть, согласно Q178078. Да я и не хочу, чтобы они случались, пока висит этот чертов MsgBox, но я хочу, чтобы они случились после того, как он ичезнет, черт побери, а не пропали неизвесто где.
Здравствуйте bnk, Вы писали:
bnk>Здравствуйте Ivan, Вы писали:
I>>ЭТО Q178078 случайно не про твою ситуацию ?
bnk>Нет, к сожалению Здесь компонент создается из MSAccessa. Но события действительно _НЕ_ случаются, как и должно быть, согласно Q178078. Да я и не хочу, чтобы они случались, пока висит этот чертов MsgBox, но я хочу, чтобы они случились после того, как он ичезнет, черт побери, а не пропали неизвесто где.
А при выполенении VB кода как exe-шника (не из IDE) они тоже пропадают ?
Здравствуйте Ivan, Вы писали:
I>А при выполенении VB кода как exe-шника (не из IDE) они тоже пропадают ?
Нет, в этом случае они НЕ пропадают , но, согласно тому же Q178078, это не есть хорошо, это есть БАГ у VB, ха-ха.
У меня ситуация близка скорее к описанной в Q196026, но только там не написано, что будет, если worker thread вздумает послать не одно, а несколько сообщений. А будет, похоже, то самое, что они исчезнут, яко тени в полдень, если об этом специально не позаботиться. Я что-то изобрел по этому поводу (см. Re[4] на George_Seryakov), это в общем-то работает, но я не уверен, наколько это есть хорошо...
Здравствуйте bnk, Вы писали:
bnk>Здравствуйте Ivan, Вы писали:
bnk>Нет, в этом случае они НЕ пропадают , но, согласно тому же Q178078, это не есть хорошо, это есть БАГ у VB, ха-ха.
Позволю себе не согласиться. В статье написано , что это поведение by design. Так себя ведет VB IDE.
Ничего страшного в этом нет, главное, что готовое приложение будет работать нормально, а на IDE можно не обращать внимание ( или убрать messagebox из обработчика события)
bnk>У меня ситуация близка скорее к описанной в Q196026, но только там не написано, что будет, если worker thread вздумает послать не одно, а несколько сообщений.
А эта статья ИМХО совсем о другом — когда ты файришь события из другого потока, не замаршалив указатель на синк.К твоей ситуации это неприменимо, так как ты, я так понимаю, файришь события из основного потока.
Здравствуйте Ivan, Вы писали:
I>Позволю себе не согласиться. В статье написано , что это поведение by design. Так себя ведет VB IDE.
К сожалению в статье Q178078 ('98) написано, что это EXE файл ведет себя неправильно(!): 'The behavior in the EXE is incorrect; events should not occur while a Message box is displayed', а в IDE все "хорошо".
А к статье Q196026 это имеет отношение в части того, как предлагается решать проблему маршалинга — сделать окно и послать на него сообщение. Так вот, моя проблема будет, если послать не одно, а несколько сообщений. Во время того, как в VB отрабатывается первый ConnectinoPoint, почему-то диспатчатся остальные посланные сообщения, и начинает отрабатывать второй, который и игнорируется в VB.
Странно, в моей статье (которая на сайте www.microsoft.com) написано вот что
Symptoms
Running a project in the IDE that displays a message box prevents events from occurring. However, when you compile and run the same project as an executable file (EXE), the events occur while the message box is displayed.
Cause
The behavior in the EXE has changed with Microsoft Visual Basic 5.0 and 6.0 so that it is different from earlier versions of Microsoft Visual Basic.
Здравствуйте bnk, Вы писали:
bnk>А к статье Q196026 это имеет отношение в части того, как предлагается решать проблему маршалинга — сделать окно и послать на него сообщение. Так вот, моя проблема будет, если послать не одно, а несколько сообщений. Во время того, как в VB отрабатывается первый ConnectinoPoint, почему-то диспатчатся остальные посланные сообщения, и начинает отрабатывать второй, который и игнорируется в VB.
Здравствуйте Ivan, Вы писали:
I>Про "incorrect" там ничего нет
Странно, но факт. В моем MSDN написано вот что:
Last reviewed: November 20, 1998
SYMPTOMS
Running a project in the IDE that displays a message box prevents events from occurring. However, when you compile and run the same project as an executable file (EXE), the events occur while the message box is displayed.
CAUSE
The behavior in the EXE is incorrect; events should not occur while a Message box is displayed (as with earlier versions of Microsoft Visual Basic).
На www.microsoft.com стоит дата публикации 'First Published: Dec 15 1997'
Может быть, они там редко обновляют статьи ?
Здравствуйте bnk, Вы писали:
bnk>На www.microsoft.com стоит дата публикации 'First Published: Dec 15 1997' bnk>Может быть, они там редко обновляют статьи ? :-
У меня MSDN — April 2002 и там то же самое, что и на www.microsoft.com
Я сталкивался с такой проблемой — VB "глотает" события, когда в обработчике вызывается MessageBox и, действительно, это происходит только в IDE, а при запуске как exe — не "глотает". Ну а "by design", так "by design". Советую не обращать внимания на эту странность IDE