Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vb.net 使用Bitblt进行屏幕截图_Vb.net_Winapi - Fatal编程技术网

Vb.net 使用Bitblt进行屏幕截图

Vb.net 使用Bitblt进行屏幕截图,vb.net,winapi,Vb.net,Winapi,我正在寻找打印屏幕的最快方式,我发现使用Bitblt是我更好的选择,但是,它只适用于设备上下文句柄,这意味着要从中检索位图,我必须使用多个API,包括CreateCompatibleBitmap,最终,它可能需要与使用托管方式相同的时间,比如graphics.CopyFromScreen(对我来说这有点慢,而且还消耗大量CPU,在2.3ghz四核处理器上占7-10%。) 但是,我仍然在寻找一种更干净的方法从中检索位图,因此我产生了以下代码: <DllImport("user32.dll")

我正在寻找打印屏幕的最快方式,我发现使用Bitblt是我更好的选择,但是,它只适用于设备上下文句柄,这意味着要从中检索位图,我必须使用多个API,包括CreateCompatibleBitmap,最终,它可能需要与使用托管方式相同的时间,比如graphics.CopyFromScreen(对我来说这有点慢,而且还消耗大量CPU,在2.3ghz四核处理器上占7-10%。)

但是,我仍然在寻找一种更干净的方法从中检索位图,因此我产生了以下代码:

<DllImport("user32.dll")> _
Public Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
End Function

<DllImport("user32.dll")> _
Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer
End Function

<DllImport("gdi32.dll")> _
Public Shared Function BitBlt(ByVal hdcDest As IntPtr, ByVal xDest As Integer, ByVal yDest As Integer, ByVal wDest As Integer, ByVal hDest As Integer, ByVal hdcSource As IntPtr, _
ByVal xSrc As Integer, ByVal ySrc As Integer, ByVal rop As TernaryRasterOperations) As Boolean
End Function

    Dim hwNd As IntPtr = Nothing

    hwNd = GetDC(GetDesktopWindow)

    picHandle = GetDC(Me.PictureBox1.Handle)

    BitBlt(picHandle, 0, 0, PictureBox1.Width, PictureBox1.Height, hwNd, 0, 0, TernaryRasterOperations.SRCCOPY)

    ReleaseDC(hwNd, picHandle)
_
公共共享函数GetDC(ByVal hWnd作为IntPtr)作为IntPtr
端函数
_
公共共享函数ReleaseDC(ByVal hWnd作为IntPtr,ByVal hDC作为IntPtr)作为整数
端函数
_
公共共享函数BitBlt(ByVal hdcDest作为IntPtr,ByVal xDest作为Integer,ByVal yDest作为Integer,ByVal wDest作为Integer,ByVal hdcSource作为IntPtr_
ByVal xSrc为整数,ByVal ySrc为整数,ByVal rop为TernaryRasterOperations)为布尔值
端函数
Dim hwNd As IntPtr=无
hwNd=GetDC(GetDesktopWindow)
picHandle=GetDC(Me.PictureBox1.Handle)
BitBlt(picHandle,0,0,PictureBox1.Width,PictureBox1.Height,hwNd,0,0,TernalyRasterOperations.SRCCOPY)
释放DC(hwNd,picHandle)
用这个我可以达到每秒30帧。。。但正如我上面所说,它有两个问题:

即使我在上面所做的操作中将其显示在picturebox上实现了我想要的效果,它也不会调整为picturebox控件的大小,即使我将这些“0”值更改为picturebox和y坐标。 我进一步搜索并发现有一个StretchBit API用于此,它确实会拉伸,但它也会降低质量(即使使用参数“半色调”必要地调用SetStretchBltMode,这样它就不会“损坏”像素),它也会降低性能,至少10+fps

但是,由于我需要将其作为位图对象,再加上其他必要的API,我的性能几乎只有graphics.CopyFromScreen的一半(每秒15帧)

那么,我在问,有没有其他方法可以在不损失性能的情况下使用Bitblt或类似工具从屏幕上获取位图


如果没有.Net的方法,我恳请您提供任何语言方法。

如果您想要原始性能,您将不得不远离托管代码。使用VisualStudio,使用C++非常容易。您可以直接调用Windows API,绕过.NET运行时、应用程序的托管代码以及.NET中p/invokes的开销

如果你熟悉C语言,你可以把C代码转换成C++(应该是简单的,有很多工作来代替CLI)。 使用只有图片盒和标签的表单。相应地设置picbox的锚定。在picbox关闭事件中:

Private Sub PictureBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    Dim Ctr1, Ctr2, Freq As Long
    Dim dbl As Double

    QueryPerformanceCounter(Ctr1)


    Dim desktopDC As IntPtr = Nothing
    Dim picboxDC As IntPtr = Nothing

    desktopDC = GetDC(New IntPtr(0))

    picboxDC = GetDC(PictureBox1.Handle)

    BitBlt(picboxDC, 0, 0, PictureBox1.Width, PictureBox1.Height, desktopDC, 0, 0, SRCCOPY)

    QueryPerformanceCounter(Ctr2)
    QueryPerformanceFrequency(Freq)

    dbl = (Ctr2 - Ctr1) / Freq

    dbl *= 1000000

    Label1.Text = dbl.ToString 'it is in microseconds

    ReleaseDC(New IntPtr(0), desktopDC)
    ReleaseDC(PictureBox1.Handle, picboxDC)

End Sub 

最大化您的表单并单击picturebox。

您的表现非常奇怪。30fps使用的是GDI+而不是GDI。使用bitblt,您可以获得大约600-800 fps的速度,stretchblt的速度要快一些倍。你找到解决方案了吗?600-800 fps?什么意思?我问这个是因为这似乎不可能。。。您可以测试代码以确认我所说的,我只想要一种稳定的方式,至少达到25 fps。我仍然没有找到一个使用.net的解决方案。好的,800 fps是当你bitblt一个兼容的dc时,因为这个dc在视频内存中。以你为例,我得到的半色调和stretchblt大约为250 fps,因为它涉及软件。我用
QueryPerformanceCounter
来测量时间。我甚至没有图形卡。如果我这样做,那么性能会爆炸得更多,但是你使用C++是正确的吗?我使用一个带有1s刻度的计时器来重置FPS计数器,它的顶部是31……嗯,我从来没有用C++工作过,我可以把它作为一个DLL或者一些我可以从.NET调用它的东西,这是否足够快,因为我仍然需要导入它?你基本上和P/INVIKE调用Windows API做了同样的事情。我刚意识到你正在进入一个图片盒。您还可以将blt插入表单本身(删除picturebox),这将为您提供一些额外的fps。您必须重写on paint事件(可能是on draw,我已经有一段时间没有在该级别进行图形处理了)。我的目标是如上所述(我知道我的帖子很长::p),即知道从类似于“desktopwindow”的打印屏幕按钮获取位图的最快方法,以便通过tcp发送到另一个应用程序。目前,我得到了另一个应用程序接收到的稳定的15帧/秒,我正在拍摄一个屏幕截图,并在大约60-70毫秒内将其转换为位图,我想这是我用.net所能做的最好的了,因为我总共进行了8个API调用,然后将其进一步转换为位图和字节。但最后,这几乎等同于使用托管函数g.CopyFromScreen…我可能至少会尝试将此代码转换为c/c++并以fps获取性能计数器,如果差异太大,我可能会尝试使用它制作一个dll,并从.net应用程序或其他什么程序调用它。好吧,它给我的是32~fps,这与我上面的例子几乎相同。。我仍然无法从Bitblt获取位图alone@SomeNickName我将尝试看看directx解决方案,然后它在C中是否有更好的性能?如果没有其他选择,我可以尝试学习所需的API,并希望学习在C/C++中实现这一点所需的小sintax。。
Private Sub PictureBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    Dim Ctr1, Ctr2, Freq As Long
    Dim dbl As Double

    QueryPerformanceCounter(Ctr1)


    Dim desktopDC As IntPtr = Nothing
    Dim picboxDC As IntPtr = Nothing

    desktopDC = GetDC(New IntPtr(0))

    picboxDC = GetDC(PictureBox1.Handle)

    BitBlt(picboxDC, 0, 0, PictureBox1.Width, PictureBox1.Height, desktopDC, 0, 0, SRCCOPY)

    QueryPerformanceCounter(Ctr2)
    QueryPerformanceFrequency(Freq)

    dbl = (Ctr2 - Ctr1) / Freq

    dbl *= 1000000

    Label1.Text = dbl.ToString 'it is in microseconds

    ReleaseDC(New IntPtr(0), desktopDC)
    ReleaseDC(PictureBox1.Handle, picboxDC)

End Sub