kkAyatakaのメモ帳。

誰かの役に立つかもしれない備忘録。

Window Stationとデスクトップ

Windowsのデスクトップはそもそも一つではありません。デスクトップはWindow Stationによって管理されており、既定でDefault、WinLogon、ScreenSaverがあることになっています。

プロセスはWindow Stationに、スレッドはデスクトップにひも付く感じになっており、それぞれ制御用の関数で切り替えが可能です。

f:id:kkAyataka:20141010213758j:plain

こんな感じなんで、1プロセスで複数のデスクトップに関連付いたアプリを書くことが出来ます。まあ、デスクトップを切り替えるアプリ以外不要でしょうけど...

スレッドはSetThreadDesktopで動作するデスクトップを切り替え可能ですが、UIスレッド(メッセージループが動いているもの)は切り替えることが出来ません(関数が失敗する)。ただし、切り替えが出来ないだけであり、新しく作ることはできるため、複数のデスクトップで動作するウィンドウを制御することは可能です。

Windows Formsで(いろいろはしょってますが)書くと、次のような感じになります。スレッドを生成後、デスクトップを指定して、メッセージループを回すことで、複数のデスクトップにウィンドウを表示できます。

var th = new Thread(
  () =>
  {
  var desk = OpenDesktop("AltDesktop", 0, false, 0x10000000);
  SetThreadDesktop(desk);

  var form = new Form();

  Application.Run(form);
  });

th.SetApartmentState(ApartmentState.STA);
th.Start();

これを利用して、複数のデスクトップで常駐する(通知領域にアイコンを登録する)、設定画面を表示するといったことが可能になります。

通常のアプリに比べて設計が複雑になりますが、これはこれで面白いです。

なお、WPFではうまくいきませんWPFレンダリングの仕組みと、デスクトップ間でWindow Messageがやり取り出来ないことが起因していると思われます。あまり詳細に調べられなかったのですが、デスクトップが異なる場合、レンダリングスレッドの指示が届いて無いのかなーという感じでした。ウィンドウの枠とかは表示されるんですが、中身は全然ダメです。

参考