UWSCで仮想デスクトップ切替

EnumAPIをたたいてみたくなって、やってみた。
ついでに、仮想デスクトップ切替スクリプトに仕上げてみた。



スクリプト

Desktops.uws

OPTION EXPLICIT

CALL Asm

IFB GET_UWSC_NAME = "Desktops.uws" THEN
	DIM ds = Desktops.Enum(), hDesk, i
	HASHTBL dl
	FOR i = 0 TO LENGTH(ds) - 1
		hDesk = Desktops.Open(ds[i])
		IF hDesk THEN dl[hDesk] = ds[i]
	NEXT
	DIM createD = "(新規作成)", createP = "(プロセス起動)", name
	name = SLCTBOX(SLCT_BTN OR SLCT_STR, 0, "切替先 (現在:" + Desktops.GetName() + ")", dl, createD, createP)
	SELECT name
		CASE createD
			name = INPUT("作成するデスクトップ名を入力してください")
		CASE createP
			name = SLCTBOX(SLCT_BTN OR SLCT_STR, 0, "作成先 (現在:" + Desktops.GetName() + ")", dl)
			i = EMPTY
			IFB name <> -1 THEN
				i = INPUT("プロセスを入力してください", GET_SYS_DIR + "\calc.exe")
			ENDIF
			IFB LENGTH(i) THEN
				IF !Desktops.Create(name, i) THEN MSGBOX("起動失敗:" + name + "<#CR>" + i)
			ENDIF
			name = EMPTY
		CASE -1
			name = EMPTY
	SELEND
	hDesk = 0
	IFB dl[name, HASH_EXISTS] THEN
		hDesk = dl[name]
	ELSE
		hDesk = Desktops.Open(name)
	ENDIF
	IFB hDesk THEN
		IF !Desktops.Switch(hDesk) THEN MSGBOX("切替失敗:" + name)
	ENDIF
	FOR i = 0 TO LENGTH(dl) - 1
		Desktops.Close(dl[i, HASH_KEY])
	NEXT
	Desktops.Dispose()
ENDIF


MODULE Desktops
	DEF_DLL GetProcessWindowStation(): DWORD: user32
	DEF_DLL EnumDesktopsA(DWORD,DWORD,DWORD): BOOL: user32

	DIM _addr = 0

	FUNCTION Enum(hwinsta=ERR_VALUE)
		RESULT = SPLIT(EMPTY)
		IFB _addr = 0 THEN
			DIM    code = "VYvsg+wQx0X0AQAAAItFDIlF/MdF+AAAAADrCYtN+IPBAYlN+ItVCANV+A++AoXA"
			code = code + "fgLr6ItN+IPBAYlN+ItV/IsCA0X4i038O0EEdzPHRfAAAAAA6wmLVfCDwgGJVfCL"
			code = code + "RfA7RfhzGYtN/IsRA1Xwi0UIA0Xwi038igCIRBEI69aLTfyLEQNV+ItF/IkQi0X0"
			code = code + "i+VdwggA"
			_addr = Asm.Set(code)
		ENDIF
		DIM paraSize = 9, para = Asm.Alloc(paraSize)
		IFB _addr > 0 AND para > 0 THEN
			IF hwinsta = ERR_VALUE THEN hwinsta = GetProcessWindowStation()
			IFB EnumDesktopsA(hwinsta, _addr, para) THEN
				paraSize = Asm.GetDword(para)
				Asm.Free(para)
				para = Asm.Alloc(paraSize + 8)
				IFB para > 0 THEN
					Asm.SetDword(para + 4, paraSize)
					IFB !EnumDesktopsA(hwinsta, _addr, para) THEN
						Asm.Free(para)
						para = 0
					ENDIF
				ENDIF
			ELSE
				Asm.Free(para)
				para = 0
			ENDIF
		ELSE
			IF para > 0 THEN Asm.Free(para)
			para = 0
		ENDIF
		IFB para > 0 THEN
			//Asm.Dump(para, paraSize + 8)
			DEF_DLL RtlMoveMemory(var BYTE[], DWORD, DWORD): kernel32
			DIM data[paraSize], i, j = 0, buf
			RtlMoveMemory(data, para + 8, paraSize)
			DEF_DLL RtlMoveMemory(var string, DWORD, DWORD): kernel32
			HASHTBL ds
			FOR i = 0 TO paraSize - 1
				IFB data[i] = 0 THEN
					buf = FORMAT(CHR(0), i - j)
					RtlMoveMemory(buf, para + 8 + j, i - j)
					ds[LENGTH(ds)] = buf
					j = i + 1
				ENDIF
			NEXT
			j = LENGTH(ds) - 1
			RESULT = SPLIT(" ")
			RESIZE(RESULT, j)
			FOR i = 0 TO j
				RESULT[i] = ds[i, HASH_VAL]
			NEXT
		ENDIF
	FEND

	PROCEDURE Dispose()
		IF _addr THEN Asm.Free(_addr)
		_addr = 0
	FEND

	FUNCTION Open(name, bFirstExplorer=TRUE)
		DEF_DLL OpenDesktopW(wstring, DWORD, BOOL, DWORD): DWORD: user32
		RESULT = OpenDesktopW(name, 0, FALSE, $1FF)
		IFB RESULT THEN
			bFirstExplorer = FALSE
		ELSE
			DEF_DLL CreateDesktopW(wstring,wstring,dword,DWORD,DWORD,dword): DWORD: user32
			RESULT = CreateDesktopW(name, NULL, 0, 0, $1FF, 0)
		ENDIF
		IFB RESULT > 0 AND bFirstExplorer THEN
			IF !Create(name, GET_WIN_DIR + "\explorer.exe") THEN RESULT = 0
		ENDIF
	FEND

	FUNCTION Switch(hDesk)
		//DEF_DLL SetThreadDesktop(DWORD): BOOL: user32
		DEF_DLL SwitchDesktop(DWORD): BOOL: user32
		RESULT = SwitchDesktop(hDesk)
	FEND

	FUNCTION Close(hDesk)
		DEF_DLL CloseDesktop(DWORD): BOOL: user32
		RESULT = CloseDesktop(hDesk)
	FEND

	FUNCTION GetCurrent()
		DEF_DLL GetThreadDesktop(DWORD): DWORD: user32
		DEF_DLL GetCurrentThreadId(): DWORD: kernel32
		RESULT = GetThreadDesktop(GetCurrentThreadId())
	FEND

	FUNCTION GetName(hDesk=0)
		RESULT = EMPTY
		IF hDesk = 0 THEN hDesk = GetCurrent()
		DEF_DLL GetUserObjectInformationW(DWORD,int,var wstring,DWORD,var DWORD): BOOL: user32
		DIM dwLen = 0, buf
		GetUserObjectInformationW(hDesk, 2, NULL, dwLen, dwLen)
		IFB dwLen > 0 THEN
			buf = FORMAT(CHR(0), dwLen)
			IF GetUserObjectInformationW(hDesk, 2, buf, dwLen, dwLen) THEN RESULT = buf
		ENDIF
	FEND

	FUNCTION Create(name, path, cmdline="")
		RESULT = FALSE
		DEF_DLL CreateProcessW(wstring,wstring,dword,dword,BOOL,dword,string,wstring, _
			{DWORD,var wstring,var wstring,var wstring,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,WORD,WORD,dword,DWORD,DWORD,DWORD}, _
			{DWORD,DWORD,DWORD,DWORD}): BOOL: kernel32
		DIM hProcess, hThread, dwProcessId, dwThreadId
		RESULT = CreateProcessW(path, cmdline, 0, 0, FALSE, 0, NULL, NULL, _
			68,NULL,name,NULL,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _
			hProcess, hThread, dwProcessId, dwThreadId)
		IFB RESULT THEN
			IF hProcess THEN Asm.CloseHandle(hProcess)
			IF hThread THEN Asm.CloseHandle(hThread)
		ENDIF
	FEND

ENDMODULE

Asmモジュールは、以下からどうぞ。
UWSCにできないことはない? - じゅんじゅんのきまぐれ


最初は「Default」くらいしかないと思いますが、新規作成すれば作れます。
また、プロセス起動で、他のデスクトップにプロセスを作れます。
なお、デスクトップを削除する手段はないので、消したくなったらログオフ or シャットダウンしてください。