尝试创建一个WPF校准微应用程序,创建一个单独的桌面并在那里显示其主窗口。
问题:创建桌面并在此处切换后,不会显示任何窗口。
namespace WpfThreads
{
class AppBootstrapper : Bootstrapper<WpfThreads.ViewModels.WpfThreadsViewModel>
{
protected override void OnStartup(object sender, StartupEventArgs e)
{
var desktop = Native.CreateDesktop("NewDesktop", 0, 0, 0, DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP, 0);
Native.SetThreadDesktop(desktop);
Native.SwitchDesktop(desktop);
base.OnStartup(sender, e);
}
}
}
SetThreadDesktop()失败,其他调用成功。 OnStartup()方法确实在主线程(也是UI线程)上运行。
答案 0 :(得分:2)
如果调用线程在当前桌面上有任何窗口或挂钩,
SetThreadDesktop
函数将失败。
C#UI线程没有任何窗口是非常不寻常的,因为项目向导用Main()
标记[STAThreadAttribute]
,这会导致在任何代码之前创建一个窗口运行。然后,此窗口为您的线程提供与当前桌面的永久关联,从而阻止您切换。
使用STA线程模型和使用安全桌面需要做的是手动激活STA。
首先,创建桌面并使用SetThreadDesktop
激活它。这不使用COM或创建任何窗口。
然后,将COM线程模型设置为STA:
Threading.Thread.CurrentThread.TrySetApartmentState(Threading.ApartmentState.STA);
这会创建一个窗口,将您的UI线程永久绑定到刚刚切换到的桌面。
执行这两个步骤后,您可以安全地开始使用其他UI类,如WinForms和WPF窗口和小部件。
不幸的是,这只能在.NET 1.x中实现,在您设置线程模型之前,它会在新线程中保持COM未初始化。从2.0开始,STAThreadAttribute
上缺少Main()
被解释为对MTA的请求,虽然这不会创建一个干扰SetThreadDesktop
的窗口,但它确实阻止了更改为STA后来。新线程从进程创建选项继承其桌面,而不是从生成它们的线程继承它们,因此您无法使用MTA线程来创建和设置桌面,然后生成STA线程来执行UI工作 - - STA线程不会在新桌面中结束。