【发布时间】:2010-02-03 11:55:08
【问题描述】:
我想创建一个 Windows 窗体控件,该控件显示一个 MFC 控件,例如 CIPAddressCtrl,带有一个正常工作的 Text 属性和 TextChanged 事件。如何在 Windows 窗体应用程序中显示 MFC 控件?如有必要,我很乐意使用 C++/CLI。
注意:我不是在问如何创建一个全新的窗体控件。我想在 Windows 窗体应用中托管旧版控件。
【问题讨论】:
我想创建一个 Windows 窗体控件,该控件显示一个 MFC 控件,例如 CIPAddressCtrl,带有一个正常工作的 Text 属性和 TextChanged 事件。如何在 Windows 窗体应用程序中显示 MFC 控件?如有必要,我很乐意使用 C++/CLI。
注意:我不是在问如何创建一个全新的窗体控件。我想在 Windows 窗体应用中托管旧版控件。
【问题讨论】:
This article 提供了一个解决方案,它将包装您的 MFC 控件。巧妙的技巧是在 Control::OnHandleCreated 的覆盖中使用 SubclassWindow。其余代码涉及使用 .NET 属性手动包装 MFC 控件的属性。
【讨论】:
在我的类似情况下,OnHandleCreated 中的SubclassWindow 由于某种原因无法正常工作。经过一番努力,我得到了它(没有 C++/CLI):
首先,从Form#Handle 获取 HWND 并将其传递给您的 MFC DLL。
class GuestControl : Control
{
private IntPtr CWnd { get; set; }
public GuestControl()
{
CWnd = attach(Handle);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
detach(CWnd);
}
base.Dispose(disposing);
}
[DllImport("your_mfc_dll")]
private static extern IntPtr attach(IntPtr hwnd);
[DllImport("your_mfc_dll")]
private static extern void detach(IntPtr hwnd);
}
然后,在你的 DLL 中,CWnd::Attach 到获得的 HWND 并初始化控件。在 Dispose 上使用CWnd::Detach 进行清理。
/** Attach to C# HWND and initialize */
extern "C" __declspec(dllexport) CWnd* PASCAL attach(HWND hwnd) {
auto w = std::make_unique<CWnd>();
if (!w->Attach(hwnd)) { return nullptr; }
// ... initialize your MFC control ...
return w.release();
}
/** Detach and delete CWnd */
extern "C" __declspec(dllexport) void PASCAL detach(CWnd *cwnd) {
auto w = std::unique_ptr<CWnd>(cwnd);
w->Detach();
}
有关完整示例,请参阅 GuestControl.cs / guest.cpp*。
编辑:this related question 中的代码也使用Attach/Detach。
* The example 是我的作品。 (麻省理工学院许可证)
【讨论】: