You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows截图.NET API因缩放问题异常:RDP下截图被截断

问题

使用以下代码可将当前窗口截图保存为Bitmap对象:

Function ScreenShotWindow() As Bitmap
    Dim bmpScreenshot As Bitmap = New Bitmap(Me.Width, Me.Height)

    Using g = Graphics.FromImage(bmpScreenshot)
        g.CopyFromScreen(Me.Location.X, Me.Location.Y, 0, 0, Me.Size)
        Return bmpScreenshot
    End Using
End Function

(上述示例为简化重写版本,可能存在一两个语法错误)

该方法在本地控制台运行时正常,但通过RDP执行时,生成的位图比窗口小,底部和右侧内容缺失,截图被截断。推测需考虑缩放因素调整实现方式,相关参数均为像素值,但实际表现不符。已搜索缩放相关文档未找到有效信息,求助正确实现方案及参考文档方向。


正确实现方案

1. 适配RDP会话的DPI缩放逻辑

RDP会话中系统的DPI缩放会导致Me.Width/Height、Me.Location这类控件属性返回逻辑像素,而非屏幕实际物理像素,这是截图截断的核心原因。需要通过Win32 API获取窗口对应DPI,将逻辑单位转换为物理像素:

Imports System.Runtime.InteropServices

Public Class Form1
    <DllImport("user32.dll")>
    Private Shared Function GetDpiForWindow(hWnd As IntPtr) As Integer
    End Function

    <DllImport("gdi32.dll")>
    Private Shared Function MulDiv(nNumber As Integer, nNumerator As Integer, nDenominator As Integer) As Integer
    End Function

    Function ScreenShotWindow() As Bitmap
        Dim dpi As Integer = GetDpiForWindow(Me.Handle)
        ' 以96DPI为基准,将逻辑尺寸转换为物理像素
        Dim physicalWidth As Integer = MulDiv(Me.Width, dpi, 96)
        Dim physicalHeight As Integer = MulDiv(Me.Height, dpi, 96)
        Dim physicalX As Integer = MulDiv(Me.Location.X, dpi, 96)
        Dim physicalY As Integer = MulDiv(Me.Location.Y, dpi, 96)

        Dim bmpScreenshot As New Bitmap(physicalWidth, physicalHeight)
        Using g = Graphics.FromImage(bmpScreenshot)
            g.DpiX = dpi
            g.DpiY = dpi
            g.CopyFromScreen(physicalX, physicalY, 0, 0, New Size(physicalWidth, physicalHeight))
            Return bmpScreenshot
        End Using
    End Function
End Class

2. 备选方案:用PrintWindow API直接捕获窗口内容

如果DPI转换仍有问题,可改用PrintWindow API,它直接从窗口绘制缓存中获取内容,不受RDP缩放影响:

Imports System.Runtime.InteropServices

Public Class Form1
    <DllImport("user32.dll")>
    Private Shared Function PrintWindow(hWnd As IntPtr, hdcBlt As IntPtr, nFlags As UInteger) As Boolean
    End Function

    Function ScreenShotWindow() As Bitmap
        Dim bmpScreenshot As New Bitmap(Me.Width, Me.Height)
        Using g = Graphics.FromImage(bmpScreenshot)
            Dim hdc As IntPtr = g.GetHdc()
            PrintWindow(Me.Handle, hdc, 0)
            g.ReleaseHdc(hdc)
        End Using
        Return bmpScreenshot
    End Function
End Class

参考文档方向

  • 微软官方Windows DPI缩放文档,重点理解逻辑像素与物理像素的转换规则
  • GetDpiForWindow、PrintWindow的Win32 API官方说明,掌握参数用法与适用场景
  • .NET WinForms高DPI适配官方指南,了解控件属性在不同DPI下的取值逻辑

内容的提问来源于stack exchange,提问作者Ian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:52:43