Screen capture with C# and Remote Desktop problems
Asked Answered
C

1

16

I have a C sharp console application that captures a screenshot of a MS Word document several times. It works great, but when I place this application on a remote windows XP machine it works fine whilst I am remoted in i.e. my remote desktop is visible but if I run my app and leave remote desktop (minimize it, not even log off which I want to do) the screenshots it takes are blank!

The Screenshot app is being run by a service that runs as SYSTEM user.

How can I keep the GUI alive for windows even when there are no users connected?

Here is the code I use:

public Image CaptureWindow(IntPtr handle)
{
    // get te hDC of the target window
    IntPtr hdcSrc = User32.GetWindowDC(handle);
    // get the size
    User32.RECT windowRect = new User32.RECT();
    User32.GetWindowRect(handle, ref windowRect);
    int width = windowRect.right - windowRect.left;
    int height = windowRect.bottom - windowRect.top;
    // create a device context we can copy to
    IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
    // create a bitmap we can copy it to,
    // using GetDeviceCaps to get the width/height
    IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
    // select the bitmap object
    IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
    // bitblt over
    GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
    // restore selection
    GDI32.SelectObject(hdcDest, hOld);
    // clean up 
    GDI32.DeleteDC(hdcDest);
    User32.ReleaseDC(handle, hdcSrc);

    // get a .NET image object for it
    Image img = Image.FromHbitmap(hBitmap);
    // free up the Bitmap object
    GDI32.DeleteObject(hBitmap);

    return img;
}

Update

I am currently making use of PrintWindow which is the only thing that has come the closest as it manages to capture the window frame (i.e the minimise, maximise and close buttons) but the inner part is black.

Although it hasn't fully worked, its proved to me that it is possible to create an image from a window handle whilst the application isn't even visible to a user.

Cobwebby answered 11/4, 2011 at 10:39 Comment(0)
C
7

Some time ago we were doing something similar, and we found that when RDC is minimized, the remote desktop session is not redrawn or accept keys or mouse events. Everything was working fine until we minimized the RDC screen. A colleague found out that this is done for performance reasons.

Some days ago I stumbled upon this, but I haven't had the chance to try it. If you try and it works, please let me know :)

Interacting with remote desktop when RDC is minimized

Regarding your comments: I think this is another kind of issue... I understand that you need your application to work even if no one is logged into the machine. I've implemented services that are allowed to interact with the desktop, for example, to launch an application and automate it. Even no one is logged in the machine, you can still manipulate the UI, for example, with an UI automation library (or your code, I assume).

After starting the machine, when my service and automated application are running everything works fine. Later on, the UI being automated will appear on the desktop of the first person who logs in (I was a machine administrator, I don't know what will happen when somebody with less privileges logs in).

I don't know what will happen if the first login is done through RDC. Maybe you could try changing those RDC settings id this affects the behavior of your application. Another option is:

  1. Disable RDC and configure windows to Autologin with an specified account
  2. Connect to this machine using another remote desktop application (e.g. TightVNC)

Does this help?

Crazed answered 11/4, 2011 at 11:15 Comment(18)
This is interesting and it looks like it will work but I need it to work such that I don't even have to remote in and my application can continue running as a SYSTEM user and still take screenshots. I'm sure there must be a setting on the remote machine to allow applications to make use of the GUI even when no user is connected!Cobwebby
@Kay- Regarding my edition: We have some 'worker' virtual machines to perform this kind of work, like UI automation. I have been interacting with the UI even no one logged in. However, you have to take care with people logging into the workstation. My RDC disabling and autologin is a proposed solution for this. However, as the VM we use are under our control, we don't need to implement anything strategy to control people logins, as no one is able to use these machines. If you are in the same situation probably you don't need to do anything else than creating the service and launching you app.Crazed
Normally you should be able to create new desktops beside desktop-0 (The login one) and the user or RDC ones to do this. But I don't know how GDI drawing code will act there.Martella
@Crazed - I am hoping that I can still login via RDC and still have the app continue working. @VirtualBlackFox - It seems then that the changes I make must be at the code level of my application rather than a setting.Cobwebby
@Cobwebby - if I remember correctly, connecting through RDC and then logging off will close your applications even they were launched from a system service, but then the service will be able to detect the shutdown and launch it again. If think that if your code handles these situations, there will be no issues. Still, you will have to try what happens with RDC and then minimizing the RDC window... maybe you have to change those RDC settingsCrazed
@Cobwebby - just wanted to confirm... You can connect with RDC, and when closing the session the UI application will close. However, I handle the process closing (or crash) from the service, so I can restart it. This will work. Regarding what VirtualBlackFox said, in theory it is possible but it was a mess to launch a new desktop from a service, I tried a lot but didn't succeeded ( I could get the frame of the windows showing on the desktop, but not the content... it was quite strange, and I couldn't find any help)Crazed
@Crazed - my service is running as a different user SYSTEM to the one that is logged in. If I logg off, my application is still alive and doesn't need to be restarted. Its just that windows switches to GUI-less mode as there are no real users logged in.Cobwebby
@Cobwebby - If I launch the application from the windows service, when a user logs in the window shows in his desktop. When logging off, the window gets CLOSED. Then my service detects it and launches it again, I presume that in another desktop session. But I'm still able to interact with it after it's launched again. Sorry I cannot help more!Crazed
@Crazed - no worries! :) I want to give up but I really need this to work. Thank you for your help though.Cobwebby
@Cobwebby - one last thing, though :) You say that your app only works when you are logging and watching it. However my service/app works even no one is logged in. You say that you have a service running as SYSTEM. If you log off, your word app should be closed. Why is it that your SYSTEM service cannot restart it and continue working, as I do??Crazed
@Crazed - since my service is running as SYSTEM any other applications it spawns i.e. word will also run as SYSTEM and therefore doesn't require me to be still logged in. My service never dies, it is always running and uninterrupted, it just doesn't have GUI annoyingly!Cobwebby
@Cobwebby - my service runs as SYSTEM, and when I launch an app with GUI Windows creates a desktop session, although is not shown, as anybody is logged in. Still, I can manipulate the UI. If I have time later, I will make a test with your code, to verify that I can take a screenshot.Crazed
@Kay, is your problem that your application can't take a screen shot, of, for example, a logon screen? We have a monitoring software that we develop that has no problem accessing any screen, either it is a user screen, or logon. Are you saying that when now one is logged in, you need to create a session programmatically, run an app in it, make screen shot, but the system should think that there is no one logged in? Please clarify the final required scenario so I can help.Resent
@Maxim - thanks for your comment. What I am essentially trying to do is to grab an image from certain applications via a window handle. The images should be captured when a user is logged in, when they are not logged in, when remote desktop is minimised i.e. not to rely on windows GUI mode. I have started making use of PrintWindow but it also fails (although it manges to capture the window frame and not the content, it appears as black) when remote desktop is minimised. I would like my app to work even when no users are logged in. It can run as any user whether system or a normal/admin userCobwebby
@Maxim - I have also updated my question. "Are you saying that when no one is logged in, you need to create a session programmatically, run an app in it, make screen shot," - up to that point you are correct.Cobwebby
@Cobwebby - Just wanted to know.. have you tried to change the RDC settings I indicated in the link in my answer? Does it change the behavior of the screen capture (at least in the RDC minimized situation)?Crazed
@Crazed - I haven't tried this yet, the thing is I won't always be using RDC. This was just an example to highlight that windows goes in GUI-less mode and I can't capture images relying on windows GUI to be on. If it does work, it won't solve my problem in all cases.Cobwebby
VNC seems to have worked, thanks! I am going to try and find out how VNC works and attempt to do the same in C#!Cobwebby

© 2022 - 2024 — McMap. All rights reserved.