Приложение зависает при хостинге управляемого управления как CWnd

Мое приложение имеет графический интерфейс на основе ATL (CWnd, CDialog,...) и состоит из нескольких страниц (CDialog). В противном случае одна из этих страниц пуста, но имеет рамку-заполнитель (CWnd), размер которой изменяется вместе с диалогом. Все построено как x64.

Когда страница загружается, она запрашивает дескриптор элемента управления из управляемой (C#) стороны приложения, используя COM-взаимодействие, и добавляет элемент управления в диалог как CWnd, созданный из этого дескриптора:

Управляемая реализация упрощена:

// Class "ManagedControlProvider"
private Control myUserControl;
public long CreateControl()
{
  myUserControl = /*Create some new inheritant of UserControl */
  myUserControl.Dock = DockStyle.Fill;
  return myUserControl.Handle.ToInt64();
}

Родная сторона упрощена:

// Call the managed class. Lifetime of m_pManagedControlProvider
// is ensured elsewhere.
LONGLONG lHandle = m_pManagedControlProvider->CreateControl();

// m_pUserCtrlAsCWnd is CWnd*
m_pUserCtrlAsCWnd = CWnd::FromHandle((HWND)lHandle);
m_pUserCtrlAsCWnd->SetParent(this);

// m_ControlFrame is just a native helper-CWnd the dialog that 
// resizes with it a so gives us the size we want to set for the
// managed control. This code is also call in every resize -event.
RECT winRect;
m_ControlFrame.GetWindowRect(&winRect); 
ScreenToClient(&winRect);

m_pUserCtrlAsCWnd->SetWindowPos(NULL, 
    winRect.left, winRect.top, winRect.right - winRect.left,
    winRect.bottom - winRect.top, 0);

Я делал это несколько раз, и это обычно работает точно так, как должно. Но иногда, как и сейчас, я испытываю зависания приложений без какой-либо явной причины. С моим текущим контролем это, кажется, происходит примерно через 5 секунд после того, как фокус установлен на какое-то другое настольное приложение.

Я проверил, что проблема не в жизненном цикле управляемого элемента управления или GC. Кроме того, это воспроизводимо в отладочной сборке, так что оптимизации не виноваты. Когда происходит зависание, я могу подключить отладчик и увидеть, что какой-то цикл ATL продолжает работать, но это единственный фрагмент кода, который я могу видеть в стеке (imo это означает, что цикл сообщений каким-то образом попал в бесконечный цикл, не взаимодействуя с мой код).

Теперь для исправления грязи: я добавил отдельный поток в свой управляемый элемент управления, который вызывает this.Focus() каждую секунду в потоке пользовательского интерфейса. Очевидно, это нелепый хак, но он работает до тех пор, пока я приостанавливаю фокусировку каждый раз, когда пользователь открывает комбо и т. Д. (В противном случае они закрываются каждую секунду).

Что я делаю не так или что может вызвать это несколько непредсказуемое поведение?

0 ответов

Я не знаю, почему и какое это имеет отношение к чему-либо, но зависание приложения каким-то образом возникло из WM_ACTIVATE. Таким образом, решение состояло в том, чтобы переопределить WINPROC в основном диалоге CDialog и заблокировать пересылку этого сообщения. С тех пор все работает без проблем.

Я не буду отмечать это как ответ, потому что не знаю, почему это решение работает.

Другие вопросы по тегам