У меня есть многопоточная dll для стороннего приложения. Моя 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 застрять в фоновом волокне, которое отключается или что-то в этом роде? на волокне прямо перед тем, как оно станет неактивным или что-то в этом роде, и только при принудительном переключении контекста это волокно когда-либо сможет обрабатывать свои сообщения? Я действительно не понимаю, как нити и волокна взаимодействуют друг с другом, поэтому я как бы хватаюсь за соломинку.
Что может привести к тому, что сообщения останутся без обработки? Что еще более важно, есть ли способ предотвратить возникновение этой ситуации? Или, по крайней мере, как мне отладить такую ситуацию?