Quote Originally Posted by TTn View Post
I don't think you can see another desktop without a Windows Service or by registering your application as an accessibility app in the registry/ease of access. If you can find your code, try it out and let me know. I doubt it.
It is actually a Windows Service that runs under the LocalSystem account which I believe is the most powerful account on a Windows system, even more powerful than Administrator accounts. It's used as part of a system I created to implement my own home grown version of Team Viewer. One of the problems I ran into early in it's design was not being able to screen capture and transmit input to and from the WinLogon desktop. I had to dive into the world of Window Stations and Desktops to implement that functionality. Once I got it, I never really explored what other possiblities there were with these series of APIs. Here is a small piece of code I used to capture the screen of the console session:-
Code:
Public Class ScreenCapture

    Private Shared gshr_objSync As New Object

    Public Shared Function GetScreenshot() As Bitmap

        'Makes this method threadsafe. Multiple threads can call it at the same time and it would be ordered.
        SyncLock gshr_objSync

            Dim windowStation As Win32.SafeWindowStationHandle = Nothing
            Dim originalWindowStation As Win32.SafeWindowStationHandle = Nothing
            Dim originalDesktop As IntPtr = IntPtr.Zero

            Dim inputdesktopHdc As IntPtr
            Dim inputDesktopHwnd As IntPtr

            Dim ptrInputDesktop As IntPtr = IntPtr.Zero
            Dim bmp As Bitmap

            windowStation = Win32.OpenWindowStation("WinSta0", False, Win32.ACCESS_MASK.GENERIC_ALL)

            Try
                If windowStation.IsInvalid Then
                    Throw New ScreenCaptureException("Failed to open window station", ScreenCaptureErrorCodes.FailedToOpenWinSta)

                Else
                    originalWindowStation = Win32.GetProcessWindowStation()
                    If originalWindowStation.IsInvalid Then
                        Throw New ScreenCaptureException("Failed to get process window station", ScreenCaptureErrorCodes.FailedToGetProcWinSta)
                    Else

                        If Not Win32.SetProcessWindowStation(windowStation) Then
                            Throw New ScreenCaptureException("Failed to change current process's window station", ScreenCaptureErrorCodes.FailedToChangeWinSta)
                        Else

                            ptrInputDesktop = Win32.OpenInputDesktop(0, False, Win32.ACCESS_MASK.GENERIC_ALL)

                            If ptrInputDesktop = IntPtr.Zero Then
                                Throw New ScreenCaptureException("Failed to open input desktop", ScreenCaptureErrorCodes.FailedToOpenInputDskTop)
                            Else
                                originalDesktop = Win32.GetThreadDesktop(Win32.GetCurrentThreadId())

                                If originalDesktop = IntPtr.Zero Then
                                    Throw New ScreenCaptureException("Unable to get original desktop", ScreenCaptureErrorCodes.FailedToGetOriginalDesktop)
                                Else
                                    If Not Win32.SetThreadDesktop(ptrInputDesktop) Then
                                        Throw New ScreenCaptureException("Unable to change the current threads desktop", ScreenCaptureErrorCodes.FailedToChangeCurrentThreadDskTop)
                                    Else
                                        inputDesktopHwnd = Win32.GetDesktopWindow()

                                        If inputDesktopHwnd <> IntPtr.Zero Then
                                            inputdesktopHdc = Win32.GetDC(inputDesktopHwnd)

                                            If inputdesktopHdc = IntPtr.Zero Then
                                                Throw New ScreenCaptureException("Unable to get desktop DC", ScreenCaptureErrorCodes.FailedToAcquireDskTopDC)
                                            Else

                                                Try
                                                    bmp = CopyDC(inputdesktopHdc, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
                                                    Return bmp
                                                Catch ex As Exception

                                                    Throw New ScreenCaptureException("Failed to copy device context", ScreenCaptureErrorCodes.CopyDCFailed, ex)
                                                End Try


                                            End If

                                        End If

                                    End If

                                End If

                            End If

                        End If

                    End If

                End If

            Finally

                Win32.ReleaseDC(inputDesktopHwnd, inputdesktopHdc)
                Win32.CloseDesktop(ptrInputDesktop)
                Win32.SetThreadDesktop(originalDesktop)
                Win32.SetProcessWindowStation(originalWindowStation)


                windowStation.Close()

            End Try

            Return Nothing
        End SyncLock
    End Function

    Private Shared Function CopyDC(ByVal hdc As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer) As Bitmap

        Dim memDC As IntPtr = Win32.CreateCompatibleDC(hdc)
        Dim memhBitmap As IntPtr = Win32.CreateCompatibleBitmap(hdc, width, height)
        Dim stockBitmap As IntPtr = Win32.SelectObject(memDC, memhBitmap)

        Try

            If Not Win32.StretchBlt(memDC, x, y, width, height, hdc, x, y, width, height, Win32.TernaryRasterOperations.SRCCOPY) Then
                Throw New Exception("Failed to copy device context")
            Else
                memhBitmap = Win32.SelectObject(memDC, stockBitmap)

                Dim returnBitmap As Bitmap = Bitmap.FromHbitmap(memhBitmap)

                Return returnBitmap
            End If

        Finally
            Win32.DeleteObject(memhBitmap)
            Win32.DeleteDC(memDC)
        End Try



    End Function


End Class
Here's another important piece of code that allows me to execute any function as if it were being executed in the console session itself.
Code:
Private Shared Sub ExecuteOnInputDesktop(ByVal proc As Action)
        Dim windowStation As Win32.SafeWindowStationHandle = Nothing
        Dim originalWindowStation As Win32.SafeWindowStationHandle = Nothing
        Dim originalDesktop As IntPtr = IntPtr.Zero

        'Dim inputdesktopHdc As IntPtr
        'Dim inputDesktopHwnd As IntPtr

        Dim ptrInputDesktop As IntPtr = IntPtr.Zero

        'Open the interactive Window Station of the current session. This is the only Window Station that can
        'contain Desktops to be displayed.
        windowStation = Win32.OpenWindowStation("WinSta0", False, Win32.ACCESS_MASK.GENERIC_ALL)

        Try
            If windowStation.IsInvalid Then
                Throw New WindowsMessagePlayerException("Failed to open window station", ScreenCaptureErrorCodes.FailedToOpenWinSta)

            Else
                originalWindowStation = Win32.GetProcessWindowStation()
                If originalWindowStation.IsInvalid Then
                    Throw New WindowsMessagePlayerException("Failed to get process window station", ScreenCaptureErrorCodes.FailedToGetProcWinSta)
                Else

                    If Not Win32.SetProcessWindowStation(windowStation) Then
                        Throw New WindowsMessagePlayerException("Failed to change current process's window station", ScreenCaptureErrorCodes.FailedToChangeWinSta)
                    Else

                        'Open the Input Desktop. The Input Desktop is the one currently being
                        'displayed and used by the user. There can only be one at a time for obvious reasons.
                        ptrInputDesktop = Win32.OpenInputDesktop(0, False, Win32.ACCESS_MASK.GENERIC_ALL)

                        If ptrInputDesktop = IntPtr.Zero Then
                            Throw New WindowsMessagePlayerException("Failed to open input desktop", ScreenCaptureErrorCodes.FailedToOpenInputDskTop)
                        Else
                            originalDesktop = Win32.GetThreadDesktop(Win32.GetCurrentThreadId())

                            If originalDesktop = IntPtr.Zero Then
                                Throw New WindowsMessagePlayerException("Unable to get original desktop", ScreenCaptureErrorCodes.FailedToGetOriginalDesktop)
                            Else
                                If Not Win32.SetThreadDesktop(ptrInputDesktop) Then
                                    Throw New WindowsMessagePlayerException("Unable to change the current threads desktop", ScreenCaptureErrorCodes.FailedToChangeCurrentThreadDskTop)
                                Else
                                    proc.Invoke()
                                End If

                            End If

                        End If

                    End If

                End If

            End If

        Finally

            'Win32.ReleaseDC(inputDesktopHwnd, inputdesktopHdc)
            Win32.CloseDesktop(ptrInputDesktop)
            Win32.SetThreadDesktop(originalDesktop)
            Win32.SetProcessWindowStation(originalWindowStation)


            windowStation.Close()

        End Try

    End Sub
A lot of API functions like SendInput are sensitive to what Desktop/WindowStation/Session they are called from. The above function can in a sense project the function call from one session like where a Windows Service is executed to the session/Window Station/Desktop of the currently logged in user or even in WinLogon(no user logged in).