带有System.Windows.Forms的MFC ActiveX控件

MFC ActiveX control with System.Windows.Forms

本文关键字:MFC ActiveX 控件 Forms System Windows 带有      更新时间:2023-10-16

我正在尝试创建一个ActiveX控件,该控件包含一个System.Windows.Forms.Integration.ElementHost控件以承载控件中的WPF内容。

我可以使用MFC创建ActiveX控件,也可以在其中加载MFC CDialog。但是,一旦我尝试创建托管控件,它就会在上崩溃,并出现AccessViolationException

return CreateControl(info,dwStyle,&pt,&size,pParentWnd,nID);

这在afxwinforms.inl:122中。

我的MainDialog.cpp文件如下:

// MainDialog.cpp : implementation file
//
#include "stdafx.h"
#include "MFCAX.h"
#include "MainDialog.h"
#include "afxdialogex.h"

// CMainDialog dialog
IMPLEMENT_DYNAMIC(CMainDialog, CDialog)
CMainDialog::CMainDialog(CWnd* pParent /*=NULL*/)
    : CDialog(CMainDialog::IDD, pParent)
{
}
CMainDialog::~CMainDialog()
{
}
void CMainDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //DDX_ManagedControl(pDX, IDC_BUTTON1, m_elementHost);
}
BOOL CMainDialog::OnInitDialog()
{
    CDialog::OnInitDialog();
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    System::Windows::Forms::MessageBox::Show(gcnew System::String("init"));
    return m_elementHost.CreateManagedControl(WS_CHILD | WS_VISIBLE, IDC_BUTTON1, this);
}
BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
END_MESSAGE_MAP()

// CMainDialog message handlers

此时会显示消息框,但随后会出现上述崩溃。

我觉得只少了一小块,但我真的不知道该去哪里找。感谢您的帮助。

我终于弄明白了,所以我会在这里快速概述一下有类似问题的人该怎么做:

首先:不要走WinForms ElementHost中的WPF路线,它比这容易得多!

要加载WPF控件并将其显示在ActiveX控件上,请使用以下方法:

HWND CMFCAXCtrl::GetUserControl1Hwnd(HWND parent, int x, int y, int width, int height)
{
   System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew System::Windows::Interop::HwndSourceParameters("MFCWPFApp");
   sourceParams->PositionX    = x;
   sourceParams->PositionY    = y;
   sourceParams->Height       = height;
   sourceParams->Width        = width;
   sourceParams->ParentWindow = System::IntPtr(parent);
   sourceParams->WindowStyle  = WS_VISIBLE | WS_CHILD;
   m_hwndSource = gcnew System::Windows::Interop::HwndSource(*sourceParams);
   EventReceiver^ recv = gcnew EventReceiver(this);
   m_wpfUC = gcnew WpfExample::TestControl();
   m_wpfUC->Clicked += gcnew System::EventHandler(recv, &EventReceiver::Handler);
   m_hwndSource->RootVisual = m_wpfUC;
   return (HWND) m_hwndSource->Handle.ToPointer();
}

您必须设置一个HwndSource来在中绘制WPF控件。您还可以连接事件处理程序等来处理C++中的WPF事件(请参阅Clicked事件处理程序)。

相应的成员定义如下:

gcroot<System::Windows::Interop::HwndSource^> m_hwndSource;
gcroot<WpfExample::TestControl^> m_wpfUC;
HWND m_hwndWPF;

现在是棘手的部分:加载这样的程序集时似乎出现了问题,找不到任何未安装在GAC中的程序集。因此,您必须连接自己的汇编解析器。在那里,你必须确保一个程序集只加载一次,否则你会得到奇怪的错误和异常。一个快速而肮脏的实现可能是这样的:

ref class Resolved {
public:
    // just needed to store the assembly that was loaded.
    static  System::Reflection::Assembly^   assembly;
};
System::Reflection::Assembly^ ResolveHandler(System::Object^ Sender, System::ResolveEventArgs^ args)
{
    return Resolved::assembly;
}

以及在控件的OnCreate方法中:

Resolved::assembly = System::Reflection::Assembly::LoadFile(gcnew System::String("Path:\To\My\assembly\WpfExample.dll"));
System::AppDomain::CurrentDomain->AssemblyResolve += gcnew System::ResolveEventHandler(ResolveHandler); 
// To create the main dialog 
m_hwndWPF = GetUserControl1Hwnd(this->GetSafeHwnd(), 0, 0, 500, 500);

现在您已经准备好了,应该能够在任何支持ActiveX的遗留项目中使用WPF。