使用System.Windows.Forms进行MFC ActiveX控件

时间:2014-04-17 11:41:17

标签: c++ wpf mfc

我试图创建一个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

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

我觉得只有一小部分缺失,但我真的不知道在哪里搜索。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

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

首先:不要在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。