6

I would like to implement a RDP client in C++ that is able to get the color value of all pixels of the screen and dump them to a file. I know this is conceptually different from how RDP works but I need it for my application. I am trying to make use of freerdp but I am not sure how can I efficiently write a client that simply dumps all pixels in a file.

So far my best attempt is making use of the function gdi_GetPixel_32bpp but of course calling this function for each pixel in turn is far from efficient.

A solution that makes use of another library will also be greatly appreciated.

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
  • What are you really trying to do? That is, why do you need to get a screenshot. There may be easier ways than implementing RDP. – selbie Jan 06 '14 at 14:39
  • @selbie what I try to do is to translate(at least the screen part) of RDP to VNC. As VNC is quite simple I will eventually have to be able to decide the pixel values of the screen. – Ivaylo Strandjev Jan 06 '14 at 14:41
  • I assume from the question that your client should be a Windows application? Does it need to be portable? – Useless Jan 06 '14 at 14:44
  • @Useless it should be able to run on Linux and need not necessary be cross platform. Free RDP runs on Linux so this should not be a big problem. – Ivaylo Strandjev Jan 06 '14 at 14:45
  • OK, so is there a reason you can't just run the vnc X server and then run an rdp client fullscreen inside that? – Useless Jan 06 '14 at 14:48
  • @Useless I believe this will have performance penalty. I don't actually need to render the screen where I start my (VNC)server I only need to translate and tunnel it. – Ivaylo Strandjev Jan 06 '14 at 14:51
  • it will only be rendering it to a local bitmap, and forwarding that over vnc. I'd honestly give a try and see if's really too slow ... – Useless Jan 06 '14 at 15:16

4 Answers4

2

This should be fairly easy to do in a very efficient way using libfreerdp-gdi. FreeRDP can render everything to a software buffer which you can then dump to a file, and you can do this entirely in memory, without an X11 environment, if you wish. Since Linux is mentioned, one quick way to get started would be to use xfreerdp with the /gdi:sw option to make use of libfreerdp-gdi (the default is to use an X11-based implementation) and to then dump the pixels as updates come in. You can hook yourself in xf_sw_end_paint, which is called at the end of an array of updates. You have access to the invalid region and the pixel buffer (all under the rdpGdi* gdi structure). Important fields are gdi->primary_buffer, gdi->dstBpp, gdi->bytesPerPixel, gdi->width and gdi->height. In most cases you will get an XRGB32 buffer, which is easy to deal with. In doubt, take a look at gdi_init() for the initialization of the internal buffer.

awakecoding
  • 428
  • 5
  • 15
1

Well you could try to this (disclaimer untested pseudo code):

HGDI_DC memDC = gdi_CreateCompatibleDC ( hDC );
HGDI_BITMAP memBM = gdi_CreateCompatibleBitmap ( hDC, screenWidth, screenHeight );
gdi_SelectObject ( memDC, memBM );
gdi_BitBlt(memDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, GDI_SRCCOPY);

Now you should have in memBM->data the complete array of pixel data. memBM->data has the following size: memBM->width * memBM->height * memBM->bytesPerPixel

Hope that this helps you at least somewhat.

Vinzenz
  • 2,749
  • 17
  • 23
  • This answer lacks a significant part of the context. What is `hDC`? Where is this code supposed to recide? – Ivaylo Strandjev Jan 06 '14 at 14:59
  • @IvayloStrandjev Just to be sure, you're able to use gdi_GetPixel_32bpp? To clarify: If you can, you can actually dismiss the 4 calls above and directly use the data on the handle you're using. I did not realize that the function actually already operates on the BitMap object. – Vinzenz Jan 06 '14 at 15:01
  • I am not sure. I have not tried to implement the solution I mention as it seems severely flawed. – Ivaylo Strandjev Jan 06 '14 at 15:06
  • This call does not compile: `gdi_SelectObject ( memDC, memBM );` as memBM is not of type `HGDIOBJECT` – Ivaylo Strandjev Jan 10 '14 at 08:57
  • I am giving you the bounty as your answer gave me some tips on how to solve my problem. There are still some issues I have not cleared, but I now have something like a working prototype. – Ivaylo Strandjev Jan 13 '14 at 08:15
0

If you run a VNC X server and start the RDP client fullscreen inside it (with no window manager etc.), the drawing sequence should be something like:

  1. RDP client receives an update from the remote session
  2. RDP client translates update into X11 messages, most likely sent over the shared memory transport
  3. VNC server receives X11 requests and uses them to render a bitmap

so the overhead should just be the X11 protocol, which is admittedly clunky but should at least be sent through a shared memory segment.

Honestly, I'd try this zero coding approach first, and see if performance is really a problem.

Useless
  • 64,155
  • 6
  • 88
  • 132
0

WebRTC may have some code you can look at to help, like the screen capturer or window capturer.

The desktop capturer is more complicated because it does (1) diffing to capture minimal contents, and (2) captures the mouse as well. Since the desktop is just a special "window", as retrieved with ::GetDesktopWindow(), and its DC can be retrieved with that window or just GetDC(NULL), you can use the window capturer and ignore the more complicated bits. Check the window capturer's Capture function for the details, as well as some helpful hints around handling Aero and other compositing/offscreen issues.

Noah Richards
  • 6,777
  • 2
  • 31
  • 28
  • It seems to me this uses its own protocol instead of RDP. I already have RDP traffic and need to translate it "on the fly" so I don't have the option to switch to another app. – Ivaylo Strandjev Jan 07 '14 at 08:49
  • I'm not saying to use it for chrome remote desktop, if that's what you mean. The code I linked to is for what (I thought) you were asking for: capturing screen contents to memory. The actual communication format should be separate. Regardless, good luck figuring things out! – Noah Richards Jan 07 '14 at 18:15