none
WPF封装OCX问题,带Prism的…… RRS feed

  • 问题

  • 通过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?
    2012年4月1日 9:28

全部回复

  • 这个方向我确实经验不是很足,不过你可以试试ILMerge工具来合并DLL: http://www.codeproject.com/Articles/9364/Merging-NET-assemblies-using-ILMerge



    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年4月1日 10:08
    版主
  • ILMerge 似乎只能整合C#的DLL ,C++的不行……
    2012年4月1日 11:30
  • Native的注册成COM组件,然后再调用。

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年4月1日 15:49
    版主
  • 我还是老老实实的把WPFDLL一个个注册进GAC,但是现在又遇到问题了,求指点迷津:

    直接贴代码吧,我的工程是这样的:

    首先,建一个简单的Prism工程,由于最终需要放入OCX中,因此,shell是一个UserControlBootstrapper

    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;

            }

        }

    这样,PrismUserControl就完成了,由于在OCX中使用WPF 的用户控件、类需要放入GAC中,因此使用命令gacutil /i “程序集路径来注册SimpleWrapClassSimpleModuleSimpleMainUserControl

    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中的引用SimpleWrapClassSimpleModuleSimpleMainUserControlWPF的程序集PresentationCorePresentationFrameworkSystemsystem.coresystem.DataSystem.XamlSystem.xmlsystem.xml.linqWindowsBase等。

    新增加一个.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,在WPFContainerOnCreate消息中去调用上面的方法

    GetHwnd(this->GetSafeHwnd(),0,0,800,600)

    然后,在MFC DlgOnCreate消息中去创建WPFContainer

    CRect rec(0,0,350,350);

    container.Create(NULL,NULL,WS_CHILD|WS_VISIBLE,rec,this,0x1113);

    这样就完成了调用

    但是这样的做的结果是MFC Dlg中没有显示WPF的界面,但是如果用一个单独的usercontrol(没有Prism)去这样加载,是可以显示的,跟踪的结果是ModuleInitialize,构造函数也能正常运行,但是View没有InitializeComponent,各位能帮忙看下吗?
    2012年4月10日 2:18
  • View 的 InitializeComponent 是由哪里调用的? 构造函数中吗? 我担心是否在 InitializeComponent 过程中有异常。

    能否试着和WPF方案一样,将UserControl加入到一个Visual Panel如Grid,然后将 Grid 设为 RootVisual 。

    还有就是,如果你的Shell不复杂的话,你可以不使用XAML去写,用code在构造函数中去创建你的Shell内容,可以跳过系统自动能够生成的 InitializeComponent 。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年4月18日 6:30
    版主