User32 SendMessage зависает, когда насос сообщений находится в режиме ожидания

У меня многопоточная DLL для стороннего приложения. My dll вызывает сообщения в основной поток пользовательского интерфейса, вызывая SendMessage с пользовательским типом сообщения:

typedef void (*CallbackFunctionType)();
DWORD _wm;
HANDLE _hwnd;
DWORD threadId;

Initialize()
{
_wm = RegisterWindowMessage("MyInvokeMessage");
WNDCLASS wndclass = {0};
wndclass.hInstance = (HINSTANCE)&__ImageBase;
wndclass.lpfnWndProc = wndProcedure;
wndclass.lpszClassName = "MessageOnlyWindow";
RegisterClass(&wndclass);
_hwnd = CreateWindow(
"MessageOnlyWindow",
NULL,
NULL,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
(HINSTANCE)&__ImageBase,
NULL);
threadId = GetCurrentThreadId();
}

void InvokeSync(CallbackFunctionType funcPtr)
{
if (_hwnd != NULL && threadId != GetCurrentThreadId())
SendMessage(_hwnd, _wm, 0, (LPARAM)funcPtr);
else
funcPtr();
}
static LRESULT CALLBACK wndProcedure(
HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == _wm)
{
CallbackFunctionType funcPtr = (CallbackFunctionType)lParam;
(*funcPtr)();
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}

Приложение является MDI, и я выполняю открытый документ / извлекаю содержимое / обрабатываю в фоновом режиме / сохраняю кучу документов, поэтому оно постоянно переключает активные документы и открывает и закрывает новые.

Моя проблема в том, что иногда обработка застревает при попытке вызвать сообщения в главном потоке, используя вышеупомянутую функцию InvokeSync ().

Когда я приостанавливаю его в отладчике, я вижу, что основной поток имеет этот стек вызовов:

user32.dll!_NtUserGetMessage@16() + 0x15 bytes
user32.dll!_NtUserGetMessage@16() + 0x15 bytes
mfc42.dll!CWinThread::PumpMessage() + 0x16 bytes
// the rest is normal application stuff

И у фонового потока, который заблокирован, есть стек вызовов как это:

user32.dll!_NtUserMessageCall@28() + 0x15 bytes
user32.dll!_NtUserMessageCall@28() + 0x15 bytes
mydll!InvokeSync(funcPtr)
// the rest is expected dll stuff

Похоже, что он застревает в вызове «SendMessage ()», но, насколько я вижу, насос сообщений в главном потоке бездействует.

Однако если я вручную нажму на неактивный документ (чтобы сделать его активным), каким-то образом это все разбудит, и событие SendMessage () наконец пройдет и возобновит обработку.

Основное приложение использует Microsoft Fibers, 1 волокно на документ. Может ли мой SendMessage застрять в фоновом волокне, которое переключается или что-то в этом роде? в оптоволокне перед тем, как оно станет неактивным или что-то в этом роде, и только путем принудительного переключения контекста это волокно когда-нибудь сможет обрабатывать свои сообщения? Я действительно не понимаю, как нити и волокна взаимодействуют друг с другом, поэтому я как бы цепляюсь за соломинку.

Что может привести к тому, что сообщения останутся необработанными? Что еще более важно, есть ли способ предотвратить возникновение этой ситуации? Или, по крайней мере, как мне отладить такую ​​ситуацию?

0

Решение

Проверьте аргументы GetMessage, Третье и четвертое — это диапазон идентификаторов сообщений. Ваше сообщение с радостью будет находиться в очереди, если его идентификатор находится вне этого диапазона.

0

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

Я реализовал собственную очередь сообщений и формат сообщений, в котором семафор используется для уведомления о получении сообщения, а другой — после его завершения, а затем повторяет PostMessage каждую 1 секунду, пока сообщение «сообщение не получено» не будет сигнализировано , затем дождитесь «сообщения завершено» с бесконечным таймаутом.

Любые дополнительные сообщения PostMessages игнорируются, поскольку они больше не содержат полезной нагрузки для выполнения, они просто сообщают основному потоку проверить очередь на наличие входящих событий.

Поскольку я внес эти изменения, я больше не сталкивался с ситуацией. Насколько я могу судить, отправленное сообщение должно заканчиваться в очереди коммутируемого волокна и забываться до тех пор, пока это волокно не будет снова включено. Повторно отправляя сообщение, оно может просто повторять попытки, пока активное волокно не заметит находящееся там сообщение.

0

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