WM_PAINT и незавершенные COM-вызовы (ATO OOP Server & quot; Deadlock & quot;)

Мы разработали сервер STA ATL COM OOP, и все почти нормально работает. Мы сталкиваемся с проблемой: поскольку COM-клиент внутренне получает результат любого COM-вызова через сообщение Windows, сообщение WM_PAINT (или любое другое сообщение, которое я предполагаю) может быть обработано в ожидании ответа на COM-вызов. Само по себе это может быть проблемой, но большая проблема заключается в том, что до тех пор, пока предыдущий COM-вызов не завершит все вызовы на сервер, произойдет сбой (HRESULT = 0x80010005), и это довольно большая проблема, так как это действительно часто происходит в нашем приложении. Мы не можем удалить вызовы COM из краски.

Я много исследовал об этом и не мог найти ничего относительно этого (кроме этот Статья 2006 года, в которой говорится о проблеме и некоторых решениях, которые не могут быть применены в нашем случае), но для того, что я вижу, не только WM_PAINT будет опасно, любой вызов на сервер, который мы выполняем внутри любого события Windows (сообщения), потенциально может вызвать та же проблема.

Таким образом, в основном у нас могут быть разные решения, но мы не знаем, какие COM-методы использовать и как:
1- метод, который ожидает обработки последнего COM-вызова и возврата значения
2- Метод, чтобы узнать, есть ли ожидающий ответ на вызов на сервере, и метод для обработки COM-ответов (все вызываются с клиента)
3. Узнайте, можем ли мы реализовать класс IMessageFilter в клиенте и как с ним справиться, обработать вызовы и так далее.

Спасибо!

0

Решение

Поскольку COM-клиент внутренне получает результат любого COM-вызова через сообщение Windows, сообщение WM_PAINT (или любое другое предполагаемое сообщение) может быть обработано в ожидании ответа на COM-вызов.

Нет ничего связывающего COM-вызовы с WM_PAINT обработка. Эти две задачи существуют одновременно, но поскольку вы выбрали STA в качестве модели, обе эти задачи выполняются в одном потоке и могут блокировать друг друга.

Вы мало что можете сделать с рисованием, поскольку в конечном итоге у вас будет обработчик сообщений для рисования. Однако вы можете изменить ваш COM-сервер и ваш обработчик рисования, чтобы не мешать COM.

Вам не нужно делать COM-звонки прямо с WM_PAINT, Создайте свой сервер так, чтобы он отправлял все обновления пользовательского интерфейса асинхронно, а обработчик рисования просто использовал самые последние доступные данные.

Также вы можете переместить свой сервер в другую квартиру, STA или MTA, чтобы он не разделял поток с пользовательским интерфейсом и работал параллельно.

0

Другие решения

Мы исправили проблему с реализацией класса IMessageFilter в клиентском проекте (C ++):

MessageFilter.h:

#include <atlbase.h>
#include <atlcom.h>

namespace SDKCOMSrvInterface
{
class MessageFilter : public CComObjectRootEx<CComSingleThreadModel>, public IMessageFilter
{
BEGIN_COM_MAP(MessageFilter)
COM_INTERFACE_ENTRY(IMessageFilter)
END_COM_MAP()

// Implement IMessageFilter methods here
STDMETHODIMP_(DWORD) HandleInComingCall(
DWORD dwCallType,
HTASK threadIDCaller,
DWORD dwTickCount,
LPINTERFACEINFO lpInterfaceInfo)
{
return E_NOTIMPL;
}

STDMETHODIMP_(DWORD) RetryRejectedCall(
HTASK threadIDCallee,
DWORD dwTimeOut,
DWORD dwRejectType)
{
return SERVERCALL_RETRYLATER;
}

STDMETHODIMP_(DWORD) MessagePending(
HTASK threadIDCallee,
DWORD dwTickCount,
DWORD dwPendingType)
{
return PENDINGMSG_WAITDEFPROCESS;
}
};
}

И регистрируем его сразу после CoInitialize (NULL):

CComObject<MessageFilter>* l_MessageFilter = NULL;
CComObject<MessageFilter>::CreateInstance(&l_MessageFilter);
CComPtr<IMessageFilter> l_OldMessageFilter;
hr = CoRegisterMessageFilter(l_MessageFilter, &l_OldMessageFilter);

Это будет гарантировать, что если мы попытаемся вызвать сервер с клиента и сервер будет занят, COM-вызов будет повторяться до тех пор, пока сервер не обработает предыдущий вызов, а это именно то, что необходимо для решения проблемы параллелизма.

0

По вопросам рекламы [email protected]