编写一个RDP客户端,可以转储屏幕的像素

6
我想在C++中实现一个RDP客户端,能够获取屏幕上所有像素的颜色值并将它们转储到文件中。我知道这在概念上与RDP的工作方式有所不同,但这是我应用程序需要的。我正在尝试利用freerdp,但我不确定如何有效地编写一个简单转储所有像素到文件的客户端。
迄今为止,我最好的尝试是利用gdi_GetPixel_32bpp函数,但是逐个调用此函数对于每个像素显然远非高效。
也欢迎使用其他库的解决方案。

你真正想做什么?也就是说,为什么需要获取屏幕截图?可能有比实现RDP更简单的方法。 - selbie
@selbie 我尝试做的是将 RDP(至少屏幕部分)翻译成 VNC。由于 VNC 相当简单,我最终必须能够决定屏幕的像素值。 - Ivaylo Strandjev
我从问题中推断出你的客户端应该是一个Windows应用程序?它需要可移植吗? - Useless
@Useless 应该能够在Linux上运行,不一定需要跨平台。Free RDP可以在Linux上运行,所以这不应该是一个大问题。 - Ivaylo Strandjev
@Useless 我认为这会有性能损失。实际上我不需要渲染屏幕,我只需要传输和隧道化(VNC)服务器。 - Ivaylo Strandjev
显示剩余2条评论
4个回答

2

使用libfreerdp-gdi非常高效地完成此操作应该很容易。FreeRDP可以将所有内容渲染到一个软件缓冲区中,然后您可以将其转储到文件中,如果需要的话,完全可以在内存中完成此操作,而无需X11环境。由于提到了Linux,一个快速开始的方法是使用xfreerdp和/gdi:sw选项来利用libfreerdp-gdi(默认情况下使用基于X11的实现),然后随着更新的到来将像素转储出来。您可以在xf_sw_end_paint中钩取自己,这个函数会在一系列更新结束时被调用。您可以访问无效区域和像素缓冲区(都在rdpGdi * gdi结构下)。重要字段是gdi->primary_buffer、gdi->dstBpp、gdi->bytesPerPixel、gdi->width和gdi->height。在大多数情况下,您将得到一个XRGB32缓冲区,这很容易处理。如果有疑问,请查看gdi_init()以初始化内部缓冲区。


1

你可以尝试这样做(免责声明:未经测试的伪代码):

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);

现在,您应该在 memBM->data 中拥有完整的像素数据数组。 memBM->data 的大小如下: memBM->width * memBM->height * memBM->bytesPerPixel
希望这能对您有所帮助。

这个答案缺少重要的上下文部分。hDC是什么?这段代码应该放在哪里? - Ivaylo Strandjev
@IvayloStrandjev 为了确保,您能够使用gdi_GetPixel_32bpp吗?澄清一下:如果可以的话,您实际上可以忽略上面的4个调用,并直接使用您正在使用的句柄上的数据。我没有意识到该函数实际上已经在BitMap对象上运行。 - Vinzenz
我不确定。我没有尝试实现我提到的解决方案,因为它似乎存在严重缺陷。 - Ivaylo Strandjev
这个调用无法编译:gdi_SelectObject ( memDC, memBM ); 因为 memBM 不是 HGDIOBJECT 类型。 - Ivaylo Strandjev
我会给你悬赏,因为你的答案给了我一些解决问题的提示。虽然还有一些问题没有解决,但我现在有了类似于工作原型的东西。 - Ivaylo Strandjev

0

如果您运行VNC X服务器并在其中全屏启动RDP客户端(没有窗口管理器等),则绘图顺序应该如下:

  1. RDP客户端接收来自远程会话的更新
  2. RDP客户端将更新转换为X11消息,最可能通过共享内存传输发送
  3. VNC服务器接收X11请求并使用它们来渲染位图

因此,开销应该只是X11协议,尽管这种协议有点笨重,但至少应该通过共享内存段发送。

老实说,我建议您首先尝试这种零编码方法,并查看性能是否真的成为问题。


我会评估这种方法。您能否提供有关最后第三步的更多信息?我不确定如何将X11消息呈现为位图。 - Ivaylo Strandjev
我建议VNC X服务器已经为您完成了这个。 - Useless

0

WebRTC可能有一些代码可供查看,例如屏幕捕捉窗口捕捉器

桌面捕捉器更复杂,因为它执行(1)差分以捕获最小内容和(2)也捕获了鼠标。由于桌面只是一个特殊的"窗口",可以使用::GetDesktopWindow()获取其DC 与该窗口或者仅使用GetDC(NULL)来检索,您可以使用窗口捕捉器并忽略更复杂的部分。请查看窗口捕捉器的Capture函数获取详细信息,以及处理Aero和其他合成/离屏问题的一些有用提示。


对我来说,它似乎使用自己的协议而不是RDP。我已经有了RDP流量,需要实时翻译它,所以我没有切换到另一个应用程序的选项。 - Ivaylo Strandjev
我并不是说要在Chrome远程桌面中使用它,如果你是这个意思的话。我提供的代码是为了实现(我认为)你所需要的功能:将屏幕内容捕获到内存中。实际的通信格式应该是分开的。无论如何,祝你好运! - Noah Richards

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接