应用程序在单独的桌面上运行

时间:2015-03-03 23:27:15

标签: c# wpf winapi desktop caliburn.micro

尝试创建一个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线程)上运行。

1 个答案:

答案 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线程不会在新桌面中结束。