[托管托管控件作为CWnd时应用程序挂起

问题描述 投票:1回答:1

我的应用程序具有基于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()。显然,这是一个荒谬的技巧,但只要用户每次打开连击等等(否则他们每秒都会关闭),只要我暂停对焦,它就会起作用。

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

c# c++ com-interop atl cwnd
1个回答
0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.