I enumerated the desktops on my system (I’m using SysInternals Desktops, so I knew I had extras) using:
EnumDesktops(Nothing, AddressOf EnumDesktopsProc, Nothing)
with these declarations:
Private Declare Auto Function EnumDesktops Lib "User32" (ByVal hWinSta As IntPtr, ByVal edp As EnumDesktopProc, ByVal lParam As IntPtr) As Boolean
Private Declare Auto Function OpenDesktop Lib "User32" (<MarshalAs(UnmanagedType.LPTStr)> ByVal DesktopName As String, ByVal dwFlags As Integer, <MarshalAs(UnmanagedType.Bool)>ByVal fInherit As Boolean, ByVal dwDesiredAccess As AccessMask) As DesktopHandle
Private desktopNames As New List(Of String)
Private Delegate Function EnumDesktopProc(<MarshalAs(UnmanagedType.LPTStr)>ByVal DesktopName As String, ByVal lParam As IntPtr) As Boolean
Private Function EnumDesktopsProc(
ByVal DesktopName As String,
ByVal lParam As IntPtr
) As Boolean
desktopNames.Add(DesktopName)
Return True
End Function
I retrieved:
"WinSta0"
"Service-0x0-3e7$"
"Service-0x0-3e4$"
"Service-0x0-3e5$"
"SAWinSta"
"__X78B95_89_IW"
"Service-0x0-119d1e$"
"Service-0x0-4e05f$"
And when I attempted to open them with:
OpenDesktop(DesktopName, 0, False, AccessMask.DESKTOP_ENUMERATE)
(where AccessMask is a big Enum duplicating the data here and here, and DesktopHandle is a SafeHandle)
they all return NULL (Nothing) and GetLastWin32Error returns 2 "The system cannot find the file specified.". Why?
I checked alternate declarations for OpenDesktop and different AccessMask values with no effect (except when the declaration was actually wrong). I note I could get a different error when adding a “path” to the DesktopName, specifically 161 "The specified path is invalid."
The documentation for
EnumDesktopsis at least misleading, if not wrong. PassingNULL(Nothing) as the first parameter is returning the desktops of the “Session 0” window station. You need to use the result fromGetProcessWindowStation(). I.e. change the first line above to:(There is a user comment added to the
EnumDesktopsdocumentation but I missed it, so I thought others might too.)Note the documentation for
GetProcessWindowStationexplicitly says it does not need closing, so it doesn’t need wrapping in aSafeHandle.