将托管控件托管为CWnd时,应用程序挂起

时间:2018-09-21 08:46:49

标签: c# c++ com-interop atl cwnd

我的应用程序具有基于ATL的GUI(CWnd,CDialog等),它包含多个页面(CDialog)。这些页面之一否则为空,但具有占位符框架(CWnd),该占位符框架随对话框调整大小。一切都以x64构建。

页面加载时,它将使用COM-interop从应用程序的托管(C#)端请求控件句柄,并将控件作为从该句柄创建的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这表明消息循环以某种方式陷入了无限循环中,而没有与之交互)我的代码)。

现在已经解决了肮脏的问题:我向托管控件中添加了一个单独的线程,该线程在UI线程上每秒调用一次this.Focus()。显然,这是一个荒谬的技巧,但是只要我每次用户打开连击等等(否则他们每秒都关闭)时我就停止聚焦,它就可以工作。

我在做错什么,或者可能导致这种无法预测的行为?

1 个答案:

答案 0 :(得分:0)

我不知道为什么或与它有什么关系,但是该应用程序以某种方式挂起源自WM_ACTIVATE。因此,解决方案是在主CDialog上重写WINPROC并阻止该消息的转发。从那时起,一切一直没有任何问题。

我不会将此答案标记为答案,因为我不知道为什么该解决方案有效。