kkAyatakaのメモ帳。

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

デスクトップを指定してプロセスを起動する

プロセスを起動する際は、通常、元のWindow Stationとデスクトップを引き継ぎますが、CreateProcessではこれらを明示的に指定できるようになっています。

STARTUPINFO si = {};
si.cb = sizeof(si);
si.lpDesktop = "WinSta0\\AltDesktop";

PROCESS_INFORMATION pa = {};

CreateProcess(
  NULL,
  "C:\\Windows\\explorer.exe",
  NULL,
  NULL,
  FALSE,
  0x00000020,
  NULL,
  NULL,
  &si,
  &pa
  );

あんまSTARTUPINFOの中身までみませんよね。ただ、これでDesktopを指定して動かすことが出来ます。

新しいデスクトップでExplorerを動かす

CreateDesktopで作成したデスクトップはまっさらで、何も表示されず、普通に使うことが出来ません。たまーにWindowsはこんな感じになりますが、これは、そのデスクトップ用のExplorerが動いていないことが起因しています。

そこで、上記を用いて、Explorerを動かしてやることで、まともに使えるデスクトップにしてやります。

また、3秒で戻ってきましょう(ただ、今回は、がんばれば戻ってこれます)。

#include <Windows.h>

int main() {
  HDESK current = OpenInputDesktop(0, FALSE, GENERIC_ALL);

  HDESK desk = CreateDesktop("AltDesktop", NULL, NULL, 0, GENERIC_ALL, NULL);

  SwitchDesktop(desk);

  STARTUPINFO si = {};
  si.cb = sizeof(si);
  si.lpDesktop = "WinSta0\\AltDesktop";

  PROCESS_INFORMATION pa = {};

  CreateProcess(
    NULL,
    "C:\\Windows\\explorer.exe", // 64-bit OSは64-bit版を
    NULL,
    NULL,
    FALSE,
    0x00000020, // NORMAL_PRIORITY_CLASS
    NULL,
    NULL,
    &si,
    &pa
    );

  Sleep(3 * 1000);

  SwitchDesktop(current);

  CloseHandle(pa.hThread);
  CloseHandle(pa.hProcess);
}

少し注意するのは64-bit OSの場合は64-bit版のExplorerを起動することです。上記のようにフルパス指定なら問題ないですが、explorer.exeと指定した場合、プロセスのアーキテクチャに依存して起動します。タスクバーが表示されないので、間違えるとやや詰みます。

Windows 7の場合、追加したデスクトップではAeroが切れます。Windows 8ではAeroも動きますが、まあ、逆に見分けづらかったりしますね。

魔法のWindow Message

Windows 8の場合、単にExplorerを起動しただけではタスクバーがうまく表示されません。ただ、動く条件はありそうだったので、Spy++で調べたりしながら試したところ、次のようにWindow Messageを送ることでうまくいきました。

HWND wnd = FindWindow("Shell_TrayWnd", NULL);
PostMessage(wnd, 0x574, 0x02, 0x00);

まあ、無理やり探し出しているので、良い方法とは言えんです。製品作ったりするならサポートにきいたほうが良いでしょうね。

参考