询问者
WPF封装OCX问题,带Prism的……

问题
-
通过http://social.msdn.microsoft.com/Forums/zh-CN/wpfzhchs/thread/bda9dfa3-14ad-43ce-96da-f6938d2edcb8 ,已经成功的在一个类中启动了Bootstrapper并返回一个由Prism组成的Usercontrol,在WPF application中能成功调用显示,先在想将其封装成OCX,发现,必须将WPF的DLL签名为强命名程序集,然后注册到GAC中,OCX才能正确调用,否则会报“0xC015000F: 正被停用的激活上下文不是最近激活的。”错误,单个Usercontrol可以这么做,但是这个工程有很多DLL,还包含了一些C++的DLL,我该如何处理这些DLL,放在哪个目录才能让WPF的DLL找到这些DLL?包括Prism中动态加载的那些DLL?
全部回复
-
这个方向我确实经验不是很足,不过你可以试试ILMerge工具来合并DLL: http://www.codeproject.com/Articles/9364/Merging-NET-assemblies-using-ILMerge
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
-
Native的注册成COM组件,然后再调用。
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
-
我还是老老实实的把WPF的DLL一个个注册进GAC吧,但是现在又遇到问题了,求指点迷津:
直接贴代码吧,我的工程是这样的:
首先,建一个简单的Prism工程,由于最终需要放入OCX中,因此,shell是一个UserControl,Bootstrapper
public class SimpleBootstrapper : MefBootstrapper
{
public Shell GetShell()
{
return (Shell)this.Shell;
}
/// <summary>
/// Initializes Shell
/// </summary>
protected override void InitializeShell()
{
base.InitializeShell();
}
/// <summary>
/// 加载模块
/// </summary>
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(SimpleBootstrapper).Assembly));
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(SimpleModule.SimpleModule).Assembly));
}
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<Shell>();
}
}
界面上:
xmlns:cal="http://www.codeplex.com/prism"
<ItemsControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" />
然后SimpleModule模块:
[ModuleExport(typeof(SimpleModule))]
public class SimpleModule: IModule
{
private readonly IRegionViewRegistry regionViewRegistry;
[ImportingConstructor]
public SimpleModule(IRegionViewRegistry registry)
{
this.regionViewRegistry = registry;
}
public void Initialize()
{
regionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(SimpleView));
}
}
然后在外面新建一个类SimpleWrapClass,方便调用,这个方法通过GetShell返回UserControl
public class SimpleWrapClass
{
public SimpleMainUserControl.Shell BootRun()
{
SimpleMainUserControl.Shell uc;
SimpleBootstrapper bootstrapper = new SimpleBootstrapper();
bootstrapper.Run();
uc = bootstrapper.GetShell();
return uc;
}
}
这样,Prism的UserControl就完成了,由于在OCX中使用WPF 的用户控件、类需要放入GAC中,因此使用命令gacutil /i “程序集路径”来注册SimpleWrapClass、SimpleModule、SimpleMainUserControl
用WPF Application测试下,
SimpleWrapClass c = new SimpleWrapClass();
SimpleMainUserControl.Shell s= c.BootRun();
grid.Children.Add(s);
能正常显示
现在新建一个MFC Dlg工程,将工程属性中的Common Language Runtime Support 设置为Common Language Runtime Support(/clr),添加GAC中的引用SimpleWrapClass、SimpleModule、SimpleMainUserControl和WPF的程序集PresentationCore、PresentationFramework、System、system.core、system.Data、System.Xaml、System.xml、system.xml.linq、WindowsBase等。
新增加一个.h文件,将WPF 的内容添加到parent中:
HWND GetHwnd(HWND parent, int x, int y, int width, int height)
{
MonitorControl::sourceParams = gcnew System::Windows::Interop::HwndSourceParameters ("MFCWPFApp2");
MonitorControl::sourceParams->PositionX = x;
MonitorControl::sourceParams->PositionY = y;
MonitorControl::sourceParams->Height = height;
MonitorControl::sourceParams->Width = width;
MonitorControl::sourceParams->ParentWindow = IntPtr(parent);
MonitorControl::sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;
System::Windows::Interop::HwndSource^ gHwndSource = gcnew System::Windows::Interop::HwndSource(*MonitorControl::sourceParams);
MonitorControl::m_WrapClass = gcnew WrapClass::WrapClass();
MonitorControl::m_SimpleWrapClass = gcnew SimpleWrapClass::SimpleWrapClass();
FrameworkElement^ myPage = MonitorControl::m_SimpleWrapClass->BootRun();
gHwndSource->RootVisual = myPage;
gHwndSource->SizeToContent=System::Windows::SizeToContent::WidthAndHeight;
return (HWND) gHwndSource->Handle.ToPointer();
}
然后增加一个基于Cwnd的类WPFContainer,在WPFContainer的OnCreate消息中去调用上面的方法
GetHwnd(this->GetSafeHwnd(),0,0,800,600);
然后,在MFC Dlg的OnCreate消息中去创建WPFContainer
CRect rec(0,0,350,350);
container.Create(NULL,NULL,WS_CHILD|WS_VISIBLE,rec,this,0x1113);
这样就完成了调用
但是这样的做的结果是MFC 的Dlg中没有显示WPF的界面,但是如果用一个单独的usercontrol(没有Prism)去这样加载,是可以显示的,跟踪的结果是Module能Initialize,构造函数也能正常运行,但是View没有InitializeComponent,各位能帮忙看下吗? -
View 的 InitializeComponent 是由哪里调用的? 构造函数中吗? 我担心是否在 InitializeComponent 过程中有异常。
能否试着和WPF方案一样,将UserControl加入到一个Visual Panel如Grid,然后将 Grid 设为 RootVisual 。
还有就是,如果你的Shell不复杂的话,你可以不使用XAML去写,用code在构造函数中去创建你的Shell内容,可以跳过系统自动能够生成的 InitializeComponent 。
Bob Bao [MSFT]
MSDN Community Support | Feedback to us