Solved

Screen Scraping with C#?

Posted on 2004-09-10
7
726 Views
Last Modified: 2011-09-20
Hi,

  I like to play Hearts on MSN Gaming Zone.  I would like to write a program that tracks the different cards that have been played for each round.  So, the question is how do I screen scrape a graphical window using C#?

The steps in my mind would consist of something like:

1) Get the device context of the foreign (Hearts) window
2) Capture the graphic bits in a well-defined, never changing location
3) Compare those graphics (the face of the card) with a library of 52 cards looking for a match

Can anyone help me with this?  Never mind if it is cheating or not, it is a way for me to learn more about graphics and programming.  I would consider giving more points if 500 is not enough for this challenge.

Thanks

Robert
0
Comment
Question by:rmyhre
  • 4
  • 2
7 Comments
 
LVL 4

Accepted Solution

by:
thedude112286 earned 500 total points
ID: 12030163
http://www.c-sharpcorner.com/Code/2003/Dec/ScreenCapture.asp was used extensively to develop this

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

class GDI32
{
      [DllImport("GDI32.dll")]
      public static extern bool BitBlt(int hdcDest,int nXDest,int nYDest,
                                       int nWidth,int nHeight,int hdcSrc,
                                       int nXSrc,int nYSrc,int dwRop);
      [DllImport("GDI32.dll")]
      public static extern int CreateCompatibleBitmap(int hdc,int nWidth,
                                                       int nHeight);
      [DllImport("GDI32.dll")]
      public static extern int CreateCompatibleDC(int hdc);
      [DllImport("GDI32.dll")]
      public static extern bool DeleteDC(int hdc);
      [DllImport("GDI32.dll")]
      public static extern bool DeleteObject(int hObject);
      [DllImport("GDI32.dll")]
      public static extern int GetDeviceCaps(int hdc,int nIndex);
      [DllImport("GDI32.dll")]
      public static extern int SelectObject(int hdc,int hgdiobj);
 

class User32
{
      [DllImport("User32.dll")]
      public static extern int FindWindow(string lpClassName, string lpWindowName);
      [DllImport("User32.dll")]
      public static extern int GetWindowDC(int hWnd);
      [DllImport("User32.dll")]
      public static extern int ReleaseDC(int hWnd,int hDC);
}
 

class Example
{
        string className, windowText;
      
        //the className parameter must be the name of the target window's class
        //and windowText must be the text of the target window - if you've never done
        //straight Win32 API programming and don't understand this concept, ask me
      public void CaptureScreen(string fileName,ImageFormat imageFormat, string className, string windowText)
      {
                  this.className = className;
                this.windowText = windowText;
                  int hdcSrc = User32.GetWindowDC(User32.FindWindow(className, windowText));
            int hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
            int hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc),
                                                                             GDI32.GetDeviceCaps(hdcSrc,8),
                                                                             GDI32.GetDeviceCaps(hdcSrc,10));
            GDI32.SelectObject(hdcDest,hBitmap);
            // set the nWidth, nHeight, nXSrc, and nYSrc parameters of BitBlt to whatever portion of the window you want
            GDI32.BitBlt(hdcDest,0,0,GDI32.GetDeviceCaps(hdcSrc,8),
                            GDI32.GetDeviceCaps(hdcSrc,10),
                            hdcSrc,0,0,0x00CC0020);
            Bitmap bitmap = GetManagedBitmap(hBitmap,fileName,imageFormat);
            Cleanup(hBitmap,hdcSrc,hdcDest);
            
                  //do whatever operations you want to do on bitmap
      }
      private void Cleanup(int hBitmap,int hdcSrc,int hdcDest)
      {
            User32.ReleaseDC(User32.FindWindow(className, windowText),hdcSrc);
            GDI32.DeleteDC(hdcDest);
            GDI32.DeleteObject(hBitmap);
      }      

      private Bitmap GetManagedBitmap(int hBitmap,string fileName,ImageFormat imageFormat)
      {
            Bitmap image =
            new Bitmap(Image.FromHbitmap(new IntPtr(hBitmap)),
                       Image.FromHbitmap(new IntPtr(hBitmap)).Width,
                       Image.FromHbitmap(new IntPtr(hBitmap)).Height);
            return image;
      }
}
0
 

Author Comment

by:rmyhre
ID: 12030252
Wow... a lot to disect there... thanks.

What I don't see is step 3... how to compare the two images?

Any help?
0
 
LVL 4

Expert Comment

by:thedude112286
ID: 12034486
I'm going away for the weekend but I'll look into comparing the images when I get back.
0
Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

 
LVL 23

Expert Comment

by:rama_krishna580
ID: 12036829
0
 
LVL 4

Expert Comment

by:thedude112286
ID: 12039977
All I can think of is to try:

if ( screenBitmap == storedBitmap )
    //match

That should work fine as long as you get the EXACT same area of the window when you store the bitmap and when you get a bitmap to compare.
0
 
LVL 4

Expert Comment

by:thedude112286
ID: 12039980
Actually, I'm not sure about how == works on Bitmaps.  You may need to examine each bit to see if it is equal.
0
 

Author Comment

by:rmyhre
ID: 12044678
I figured it out over the weekend.  Basically I dump the bitmap into a memory stream and then convert the memory stream into a byte array.  Finally, I just iterate through the array checking each value to ensure that they are the same in both the stored image and the scanned image.

Works pretty slick  :)
0

Featured Post

Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question