首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >托管WPF和本机代码互操作。托管在ServicedComponent中的WPF

托管WPF和本机代码互操作。托管在ServicedComponent中的WPF
EN

Stack Overflow用户
提问于 2014-06-15 11:14:58
回答 1查看 226关注 0票数 3

我正在努力在ServicedComponent中托管WPF应用程序。我有一个WPF库,我需要从本机代码中使用它。为了实现这个目标,我创建了一个outproc COM+组件,将所有的WPF调用放入其中,并从本机代码中调用该组件,如下所示:

代码语言:javascript
复制
// Managed
[ComVisible(true)]
public class HpPcKeyboardSrv : ServicedComponent, ISrv
{
    ...
}

// Native
CComPtr<ISrv> spISrv;
hr = spISrv.CoCreateInstance(__uuidof(MySrv), nullptr, CLSCTX_SERVER);
ATLVERIFY(SUCCEEDED(hr));

hr = spISrv->WPFCommand();
ATLVERIFY(SUCCEEDED(hr));

它作为一个原型完美地工作,但当我添加实际的WPF功能时,一切都开始瓦解。

由于臭名昭著的WPF异常"The calling thread must be STA, because many UI components require this",我无法在COM+ ServicedComponent中创建WPF窗口。其中一个解决方案是使用Dispatcher。问题是WPF调度程序Dispatcher.CurrentDispatcher不会调用BeginInvoke()中函数

代码语言:javascript
复制
    public void WPFCommand()
    {
        Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate
        {
            System.Threading.ApartmentState aptStateLocal = Thread.CurrentThread.GetApartmentState();
            Debug.WriteLine("Spawned thread apartment: {0}", aptStateLocal);

            _Window = new Window();
        });
    }

另一种选择是使用Application.Current.Dispatcher。这种方法的问题是,在此调用中,Application.Current为空,因此没有可用的调度程序。

好的。接下来要尝试的是在STA模型中产生威胁,如下所示:

代码语言:javascript
复制
public void WPFCommand()
{
    if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
    {
        Thread thread = new Thread(() =>
        {
            System.Threading.ApartmentState aptState = Thread.CurrentThread.GetApartmentState();
            Debug.WriteLine("Spawned thread apartment: {0}", aptState); // <- Still MTA

            // !!! If _Window is the member of the class, the thread will be MTA
            // !!! otherwise STA
            _Window = new Window();

            System.Windows.Threading.Dispatcher.Run();
        });

        Debug.WriteLine("Thread apartment state1: {0}", thread.GetApartmentState());
        thread.SetApartmentState(ApartmentState.STA);     // <- even though set as STA
        Debug.WriteLine("Thread apartment state2: {0}", thread.GetApartmentState());

        thread.IsBackground = true;
        thread.Start();
        thread.Join();
    }
}

这段代码在一定程度上有所帮助。因为已经设置为STA模型的生成线程,如果_Window是类成员(但如果不是,它就是STA ),则无论如何都会在MTA中被调用,因此new Window()会抛出相同的“必须是STA”异常。

在这一点上,我完全卡住了。如何在ServicedComponent中实际创建WPF元素?或者如何在本机代码和WPF之间进行交互?任何想法都是值得感谢的。

更新:奇怪的是,赋值(_Window =新窗口())会影响线程模型。如果_Window是类的成员,则踏步模型仍然是MTA。如果它是一个局部变量,则线程模型将更改为MTA。似乎应该以其他方式将_Window指定为类的成员。

EN

回答 1

Stack Overflow用户

发布于 2015-01-20 15:45:54

我可能在寻找解决方案的轨道上,或者完全偏离了轨道-

http://drwpf.com/blog/2007/10/05/managing-application-resources-when-wpf-is-hosted/

基本上,上述方法加载所有资源字典并创建WPF环境。请勾选“在代码中管理资源字典集合并在元素级别合并它们”。

因此,在此之后,您可以直接从WPFCommand调用您的窗口,而不必担心STA。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24226231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档