capturing a screen from a non-interactive service

hello all.

I'm trying to write an exe that will capture a screen on windows and save it into a bitmap file.
I'm using GDI, and I've managed to do it now using the GetDC function. in a nutshell, it is something like that:
HDC desktopDC   = GetDC(NULL);
HDC memDC       = CreateCompatibleDC (desktopDC);
HBITMAP ScreenBitmap = CreateCompatibleBitmap(desktopDC,DesktopWidth,DesktopHeight);

of course, this kind of code is good only if I run my program in interactive mode, and it capture the desktop that I can see. however, I need to run this program as a service, which means it will be in the context of the LOCAL SYSTEM user, and won't have a desktop. what I want it to do, is to find the desktop of a specified user session (which I know that it is connected), and capture it.

is that possible? (programmtically, not from the security point of view)
does anyone know how it can be done? how can I get a DC of a different session that myself?

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Cyber-EEAuthor Commented:
thanks for the answer, ChristianWimmer.

are you sure this approach will also fail in case the other session is connected using RDP?
I read a bit about using WTSRegisterSessionNotification & WTSGetActiveConsoleSessionId and such. If the user is connected to the terminal service, isn't it somehow possible to get its session from a service, and then use things like SetProcessWindowStation & SetThreadDesktop in order to get the desktop of the interactive user?

I didn't understand these function pefectly yet, but does the security problems you mentioned in your answer still problematic with this approach?
There is no difference with RDP. You can't get a handle with OpenDesktop for a desktop in another session because there is an if case for this situation (If (Process.Session != Desktop.Session) return 5)
The only way is a second process that is spawned into the target session.

You can run a new system process in any session you like. However you should not use this system process to show any windows to the user. A shatter attack could use your GUI to infiltrate the system.
These steps are necessary to create a system process in any session
* OpenProcessToken in a service
* DuplicateToken
* SetTokenInformation with TokenSessionId to set the target session ID for the new process. Needs TCB privilege!
* CreateProcessAsUser with the duplicated token. Set also parameter bInheritHandles to FALSE !

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Cyber-EEAuthor Commented:
Thanks for the help
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.