Results 1 to 4 of 4
  1. #1
    abuckau907_num2's Avatar
    Join Date
    Jan 2013
    Gender
    male
    Posts
    1
    Reputation
    10
    Thanks
    1

    vb.net screenshot tutorial

    The Goal
    Basically, take screenshots of a specific app (game?) and 'scan' (ie. analyze) the image for certain things (ie. colors: health bar, ememies, etc).

    Basic Assumptions
    You already know how to program in vb.net. You know variables, functions, classes, ByRef: most of the basics. I'm not going to say "Create new project" or specifically say where to declare variables.


    Getting Started
    (I lied, make a new project )

    1) How exactly do we take the screenshot?
    2) How do we scan over (analyze) that screenshot?
    3) What is a screenshot?

    ..I'm answering in reverse order, but...

    3) Since we are using Microsoft's .Net Framework for our project, we're going to use a few .net classes/functions. Microsoft likes 'bitmaps'(reference needed?), so if we want to leverage existing .net code, there are a few things we 'have' to do. Back to the point, our screenshot will be stored as a 'Bitmap' object. (probably System.Drawing.Bitmap? I don't have msvs open atm. google tells)
    2) The bitmap class is pretty complex, and I'm not a graphics expert. The class has a function .GetPixel(x,y) which will return a 'color' object that we want. X,Y being the location in the bitmap of course. MAJOR point: It would be faster! to store the data in an array, and access it that way, instead of calling a .Function() for each and every pixel in the data! But..it works, and it's not much code. There will be a part 2 to this tutorial eventually. anyway.
    1) The .net framework of course. There is a class called 'Graphics' and a method called 'CopyFromScreen'. <--Screen = your physical monitor, ie. what you're looking at ie. screenshot area

    So, on to some code.
    I created a class called "GooeyManager" (play on words), but feel free to add it wherever you want. All of these functions can/should be made static, ie. you don't need an object of the guimgr class before you can access the functions. Change it if you want to.

    Just a demo
    Code:
    Dim _myBitmap as new Bitmap(50,50) '' 50,50 is the size: width, height, few diff. overloads
    Dim _gr As Graphics = Graphics.FromImage(_myBitmap) '' we need the gr object for copyfromscreen
    
    _gr.CopyFromScreen(***,***) '' not actual paremeters.
    _gr.Dispose() ''don't forget about this later
    _myBitmap : object of the Bitmap class. Stores the ss (screenshot) for us.
    _gr : Graphics class. It's a little complex. CopyFromScreen() is pretty straight forward.
    .CopyFromScreen() : ie. Take screenshot (of specific region on the monitor)

    [some real code]
    Code:
        Public Shared Function CopyFromScreen(ByVal tl As Point, ByVal width As Int32, ByVal height As Int32) As Bitmap
            Dim _rtnBmp As New Bitmap(width, height)
            Dim _gr As Graphics = Graphics.FromImage(_rtnBmp)
            _gr.CopyFromScreen(tl, New Point(0, 0), New Size(width, height), CopyPixelOperation.SourceCopy) '' sourcecopy or ____ ?
            _gr.Dispose()
            Return _rtnBmp
        End Function
    description of parameters/arguments
    tl : top-left, the top-left {x,y} of the region you want to copy
    br : bottom-right, the bottom-right {x,y} of the region you want to copy

    new Point(0,0) and New Size(*,*) : basically CopyFromScreen() doesn't have to use our entire bitmap.


    That's it!
    Kind of short, not a lot of code, but it can sometimes be useful.

    Just a little more, but you might not need this.
    take a ss of a specific form
    Basically it users a few more Windows API to find a specific window (app,game,whatever) and take a screenshot of only that window (assuming it's open and top-most..)
    Code:
        Public Shared Function GetWindowScreen(ByVal windowTitle As String, Optional ByVal includeBorders As Boolean = True) As Bitmap
            Dim _targetWindowHandle As IntPtr = FindWindow(Nothing, windowTitle) 'try to find window based on title.
            If _targetWindowHandle = 0 Then
                ''window not found
                MessageBox.Show("ScreenShotManager::GetScreenOfApp windowTitle not found! --> '" & windowTitle & "'" & Environment.NewLine _
                                & "Are you sure that program is running?")
                Return New Bitmap(2, 2) ''why not (1,1). choice.
            Else
                ''window found
                Dim _targetWindowInfo As WINDOWINFO
                GetWindowInfo(_targetWindowHandle, _targetWindowInfo)
                If includeBorders Then
                    Dim _tl As New Point(_targetWindowInfo.rcWindow.Left, _targetWindowInfo.rcWindow.Top)
                    Return CopyFromScreen(_tl, _targetWindowInfo.rcWindow.Width, _targetWindowInfo.rcWindow.Height)
                Else
                    Dim _tl As New Point(_targetWindowInfo.rcClient.Left, _targetWindowInfo.rcClient.Top)
                    Return CopyFromScreen(_tl, _targetWindowInfo.rcClient.Width, _targetWindowInfo.rcClient.Height)
                End If
            End If
        End Function

    A little debugging / testing...
    Just take a screenshot of an app (in my case, pinball.exe because it's stock) 15 times, as fast as possible, and see how long it take. ie. how many scans can it do per second? hopefully at least 1! preferable 4-5 ? Anyway, I'm on an old pc (Pentium 4 cpu), so hopefully your results will be a little faster.
    Code:
    Public Sub RunFPSTest()
    
            If MessageBox.Show("Open pinball.exe before you click OK") = DialogResult.OK Then
    
                Dim _ss As Bitmap
                Dim _timeLapse As TimeSpan
                Dim _startTime As DateTime = Date.Now
                Dim _aColor As Color
                Dim _ctr As Int32 = 0
    
                For jj = 1 To 15
                    _ss = GetWindowScreen("3D Pinball for Windows - Space Cadet", True)
                    For xx As Int32 = 0 To _ss.Width - 1
                        For yy As Int32 = 0 To _ss.Height - 1
                            _aColor = _ss.GetPixel(xx, yy)
                            If _aColor.R = 0 And _aColor.G = 0 And _aColor.B = 0 Then
                                'white/black
                                _ctr += 1
                            End If
                        Next
                    Next
                Next
                _timeLapse = Date.Now.Subtract(_startTime)
                MsgBox("It took " + _timeLapse.TotalSeconds.ToString & "s to scan 15 times, that's..." & Environment.NewLine _
                       & (15 / _timeLapse.TotalSeconds).ToString + " / second " & Environment.NewLine _
                       * "Image size: " & _ss.Width & "x" & _ss.Height & " pixels" & Environment.NewLine _
                       & "black_pixel_ctr: " & _ctr.ToString)
            End If
    
        End Sub


    So, I must admit, 2.** fps (I mean, scans per second) seems really slow. In terms of game fps, it seriously is, but if you consider how big the image was, and actually how many pixels it had to scan over, it's quite a lot. Pinball was roughly 600,460 which is 2,83,608 pixels! That's 2 millions pixels it has to scan, every single time. My point, keep your scan areas small, and you can actually get really good scans-per-second. Doing the entire screen this way is NOT good.

    oo..and the API/structdeclarations
    Code:
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    Private Declare Function GetWindowInfo Lib "user32" (ByVal hWnd As IntPtr, ByRef pWinInfo As WINDOWINFO) As Boolean
    
        Private Structure WINDOWINFO
            Dim cbSize As Integer
            Dim rcWindow As RECT_win32 ''entire form, including border
            Dim rcClient As RECT_win32 ''client window, no border
            Dim dwStyle As Integer 
            Dim dwExStyle As Integer
            Dim dwWindowStatus As UInt32 ''fullscreen? minimized?
            Dim cxWindowBorders As UInt32
            Dim cyWindowBorders As UInt32''not sure
            Dim atomWindowType As UInt16
            Dim wCreatorVersion As Short
        End Structure
    
    ''' <summary>
        ''' NOT bit compatible with system.drawing.rectangle
        ''' </summary>
        Private Structure RECT_win32 'not bit compatible with system.drawing.rectangle.
            Dim Left As Integer
            Dim Top As Integer
            Dim Right As Integer
            Dim Bottom As Integer
            Public Property Height() As Integer
                Get
                    Return Bottom - Top
                End Get
                Set(ByVal value As Integer)
                    Bottom = value - Top
                End Set
            End Property
            Public Property Width() As Integer
                Get
                    Return Right - Left
                End Get
                Set(ByVal value As Integer)
                    Right = value + Left
                End Set
            End Property
        End Structure
    TODO: Look into using Marshal class for quicker (array) access to the bitmap's data


    --my original account is abuckau907 , currently under 3 day ban.

    Hope this helps.
    Last edited by abuckau907_num2; 01-10-2013 at 04:10 AM.

  2. The Following User Says Thank You to abuckau907_num2 For This Useful Post:

    Pingo (01-10-2013)

  3. #2
    DawgiiStylz's Avatar
    Join Date
    Aug 2009
    Gender
    male
    Location
    Dawg House
    Posts
    7,811
    Reputation
    219
    Thanks
    2,896
    My Mood
    Tired
    Another way of doing it using gdi32.dll and user32.dll API's

    Code:
    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
    
    
            Declare Function GetDesktopWindow Lib "user32.dll" () As IntPtr
            Declare Function GetWindowDC Lib "user32.dll" (ByVal hwnd As IntPtr) As IntPtr
            Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As Int32
            Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Int32
    
    Private Class GDI32
            Public SRCCOPY As Integer = &HCC0020
            Declare Function BitBlt Lib "gdi32.dll" ( _
                ByVal hDestDC As IntPtr, _
                ByVal x As Int32, _
                ByVal y As Int32, _
                ByVal nWidth As Int32, _
                ByVal nHeight As Int32, _
                ByVal hSrcDC As IntPtr, _
                ByVal xSrc As Int32, _
                ByVal ySrc As Int32, _
                ByVal dwRop As Int32) As Int32
    
    
            Declare Function CreateCompatibleBitmap Lib "gdi32.dll" (ByVal hdc As IntPtr, ByVal nWidth As Int32, ByVal nHeight As Int32) As IntPtr
            Declare Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hdc As IntPtr) As IntPtr
            Declare Function DeleteDC Lib "gdi32.dll" (ByVal hdc As IntPtr) As Int32
            Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As IntPtr) As Int32
            Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As IntPtr, ByVal hObject As IntPtr) As IntPtr
        End Class
    
    Public Shared Function CaptureDeskTopRectangle(ByVal CapRect As Rectangle, ByVal CapRectWidth As Integer, ByVal CapRectHeight As Integer) As Bitmap
            Dim SC As New ScreenCap
            Dim bmpImage As New Bitmap(SC.CaptureScreen)
            Dim bmpCrop As New Bitmap(CapRectWidth, CapRectHeight, bmpImage.PixelFormat)
            Dim recCrop As New Rectangle(CapRect.X, CapRect.Y, CapRectWidth, CapRectHeight)
            Dim gphCrop As Graphics = Graphics.FromImage(bmpCrop)
            Dim recDest As New Rectangle(0, 0, CapRectWidth, CapRectHeight)
            gphCrop.DrawImage(bmpImage, recDest, recCrop.X, recCrop.Y, recCrop.Width, recCrop.Height, GraphicsUnit.Pixel)
            Return bmpCrop
        End Function
    
    Public Shared Function CaptureScreen() As Image
            Return CaptureWindow(User32.GetDesktopWindow())
        End Function
    
    
        Public Shared Function CaptureWindow(ByVal handle As IntPtr) As Image
            Dim SRCCOPY As Integer = &HCC0020
            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, 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
    This is from my capture image capture class

    and @
    abuckau907_num2
    You never included the API's that you've used. Such as FindWindow
    Last edited by DawgiiStylz; 01-10-2013 at 02:16 AM.

  4. #3
    abuckau907_num2's Avatar
    Join Date
    Jan 2013
    Gender
    male
    Posts
    1
    Reputation
    10
    Thanks
    1
    (oops: edited in the other api / struct)
    I don't know much about how windows internally handles the graphics. I keep seeing dc, device context? display context? I'll have to read up on it soon. Would be nice to get a little more performance out of mine, but it serves its purpose. Thnx for posting your code.

    I went to see the hobbit in 3D I should have finished editing original tut before posting, thought it was just about finished. I posted 1/2 ( 1 of 2) of the api's used

    Another little piece, with different API, to get only 1 pixel.
    Code:
        Private Declare Function GetDesktopWindow Lib "user32" () As IntPtr
        Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd As IntPtr) As IntPtr
        Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As IntPtr, ByVal XPos As Integer, YPos As Integer) As UInteger
        Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean
    
    Public Shared Function GetPixelColor(ByVal x As Int32, ByVal y As Int32) As Color
            Dim hWnd As IntPtr
            Dim hDC As IntPtr
            hWnd = GetDesktopWindow()
            hDC = GetWindowDC(hWnd)
    
            Dim lColor As Int32 = GetPixel(hDC, x, y)
            ReleaseDC(hWnd, hDC)
    
            Return ColorTranslator.FromWin32(lColor) 
        End Function
    ^^might be useful if know you the exact location of a pixel and that location won't change.
    Last edited by abuckau907_num2; 01-10-2013 at 04:28 AM.

  5. #4
    'Bruno's Avatar
    Join Date
    Dec 2009
    Gender
    male
    Location
    Portugal
    Posts
    2,883
    Reputation
    290
    Thanks
    1,036
    My Mood
    Busy
    Reference the functions from winapi to MSDN.. So people can actually learn and have a proper explanation on what it does.. ._.
    Light travels faster than sound. That's why most people seem bright until you hear them speak.

Similar Threads

  1. [Tutorial] VB.Net Hacking Tutorial (28 Min Video/Voice)
    By Jorndel in forum Call of Duty Modern Warfare 3 Tutorials
    Replies: 28
    Last Post: 12-25-2012, 12:05 PM
  2. [Tutorial] VB.NET MPGH TUTORIAL - HELLO VB !
    By Sprite in forum CrossFire Tutorials
    Replies: 0
    Last Post: 06-17-2011, 07:10 PM
  3. [VB.NET]INI Tutorials 0
    By ♪~ ᕕ(ᐛ)ᕗ in forum Programming Tutorials
    Replies: 2
    Last Post: 03-25-2011, 06:42 AM
  4. [Tutorial] How to VB.Net your trainer
    By dezer in forum WarRock - International Hacks
    Replies: 10
    Last Post: 07-16-2007, 10:28 PM
  5. [TUTORIAL]how to VB.net 2005 Trainers (Incl. secure passwords)
    By kyo in forum WarRock - International Hacks
    Replies: 20
    Last Post: 07-06-2007, 09:42 PM