取得台球游戏的图像

这里为了在窗口被遮挡的时候也能够取得正确图像,我们不能采用屏幕图像传输的方法,而.NET仅提供了一个快捷方法传输屏幕图像,这个方法不适合我们。最终还是决定使用传统的WIN32 API来实现这个功能,涉及到的API和使用方法都是很久以前大家就非常熟悉的,只是把它们用在.NET中时需要更改一些内容。

其API声明如下:


Public Class GDI32
    Public Const SRCCOPY As Integer = 13369376
    <DllImport("gdi32.dll")> _
    Public Shared Function BitBlt(ByVal hObject As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hObjectSource As IntPtr, _
    ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As Integer) As Boolean
    End Function
    <DllImport("gdi32.dll")> _
    Public Shared Function CreateCompatibleBitmap(ByVal hDC As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) As IntPtr
    End Function
    <DllImport("gdi32.dll")> _
    Public Shared Function CreateCompatibleDC(ByVal hDC As IntPtr) As IntPtr
    End Function
    <DllImport("gdi32.dll")> _
    Public Shared Function DeleteDC(ByVal hDC As IntPtr) As Boolean
    End Function
    <DllImport("gdi32.dll")> _
    Public Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
    End Function
    <DllImport("gdi32.dll")> _
    Public Shared Function SelectObject(ByVal hDC As IntPtr, ByVal hObject As IntPtr) As IntPtr
    End Function
End Class

Public Class User32
    <StructLayout(LayoutKind.Sequential)> Public Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
    End Structure
    <StructLayout(LayoutKind.Sequential)> Public Structure POINT
        Public X As Integer, Y As Integer
    End Structure
    <DllImport("user32.dll")> Public Shared Function GetDesktopWindow() As IntPtr
    End Function
    <DllImport("user32.dll")> Public Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
    End Function
    <DllImport("user32.dll")> Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As IntPtr
    End Function
    <DllImport("user32.dll")> Public Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef rect As RECT) As IntPtr
    End Function
    <DllImport("user32.dll")> Public Shared Function WindowFromPoint(ByVal pt As POINT) As IntPtr
    End Function
End Class

接下来我们实现一个方法,这个方法只需要传入一个Handle,返回值为一个Image对象,这个返回值可以直接转化为BitMap对象供我们分析图像使用。

一下在同一个文件中,该文件开头需要导入名空间:

Imports System.Runtime.InteropServices
Imports System.Drawing.Imaging


Public Class ScreenCapture
    ''' <summary>
    ''' 取得窗口图像
    ''' </summary>
    ''' <param name="handle">句柄</param>
    ''' <returns>图像</returns>
    ''' <remarks></remarks>
    Public Shared Function CaptureWindow(ByVal handle As IntPtr) As Image
        Dim hdcSrc As IntPtr = User32.GetWindowDC(handle)
        Dim windowRect As New User32.RECT()
        User32.GetWindowRect(handle, windowRect)
        Dim width As Integer = windowRect.right - windowRect.left
        Dim height As Integer = windowRect.bottom - windowRect.top
        Dim hdcDest As IntPtr = GDI32.CreateCompatibleDC(hdcSrc)
        Dim hBitmap As IntPtr = GDI32.CreateCompatibleBitmap(hdcSrc, width, height)
        Dim hOld As IntPtr = GDI32.SelectObject(hdcDest, hBitmap)
        GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY)
        GDI32.SelectObject(hdcDest, hOld)
        GDI32.DeleteDC(hdcDest)
        User32.ReleaseDC(handle, hdcSrc)
        Dim img As Image = Image.FromHbitmap(hBitmap)
        GDI32.DeleteObject(hBitmap)
        Return img
    End Function

End Class

接下来只需要取得台球窗口句柄就可以了,这里还是使用传统的API来实现,使用SPY++即可得到这个窗口的类名信息,我们取最小的子窗口。这个方法同样需要一个传入参数,我们的瞄准器采取事件驱动模式,所以传入参数定位为鼠标所在坐标,那么这个函数实际上就是已知鼠标坐标,返回窗口Handle,但在SPY++中观察,发现有一个窗口和本窗口很相似,所以为了区分,我们遍历其所有父及父的父(也就是他爷爷,最后到了他爷爷的爹或者他爹的爷爷)。。。。。。。

Public Class GameFrame
    'api
    Private Declare Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" (ByVal xPoint As Integer, ByVal yPoint As Integer) As Integer
    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As IntPtr, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
    Private Declare Function GetParent Lib "user32" Alias "GetParent" (ByVal hwnd As IntPtr) As IntPtr
 Private Shared _hwndback As IntPtr '上次取得的台面句柄


    Public Shared Function GetBitMap(ByVal point As Point) As Bitmap
        Dim hwnd As IntPtr = WindowFromPoint(point.X, point.Y)  '鼠标所在窗口
        If hwnd <> _hwndback Then
            Dim Length As Integer = 100
            Dim ClassName As String = Space(100)
            GetClassName(hwnd, ClassName, Length)   '窗口类名
            ClassName = ClassName.Replace(Chr(0), "").Trim
            If ClassName = Setting.CName Then
                Dim phwnd As IntPtr
                If GetpClassname(hwnd, phwnd) = Setting.pCName Then
                    Dim pphwnd As IntPtr
                    If GetpClassname(phwnd, pphwnd) = Setting.ppCName Then
                        Dim ppphwnd As IntPtr
                        If GetpClassname(pphwnd, ppphwnd) = Setting.pppCName Then
                            _hwndback = hwnd    '保存刚取得的句柄
                            Line.Graphics = Graphics.FromHwnd(hwnd)  '【创建画布】
                            Return ScreenCapture.CaptureWindow(hwnd)  '【图像】
                        End If
                    End If
                End If
            End If
        Else
            Line.Graphics = Graphics.FromHwnd(hwnd) '【创建画布】
            Return ScreenCapture.CaptureWindow(hwnd)  '【图像】
        End If
        Return Nothing
    End Function
    '获取父窗口类名
    Private Shared Function GetpClassname(ByVal hwnd As IntPtr, ByRef phwnd As IntPtr) As String
        phwnd = GetParent(hwnd)
        Dim pClassName As String = Space(100)
        GetClassName(phwnd, pClassName, 100)
        pClassName = pClassName.Replace(Chr(0), "").Trim
        Return pClassName
    End Function

End Class

这里的类名放在了Setting类当中,其具体值分别为:

Public Class Setting
    Public Shared CName As String = "AfxWnd42"
    Public Shared pCName As String = "#32770"
    Public Shared ppCName As String = "AfxMDIFrame42"
    Public Shared pppCName As String = "Afx:400000:0"
End Class

 

好了,可以测试了,截取一个台球图像到程序吧!

在窗体上绘制一个PICTUREBOX,命名为PIC,添加一个TIMER控件,修改其为有效。

在TICK事件中添加以下代码:

GameFrame.GetBitMap(500,400)

然后打开联众台球。。。。美式或斯诺克都可以。如果取不到图像,可以调节500,400这个数值。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清晨曦月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值