
Introduction
I was continuing to play around with IJW. And when I realized that there was
no direct Screen Capture method in .NET, I thought I might as well try to make a
simple Screen Capturing program. Of course since I knew as much about GDI
programming as some of these Canadians seem to know about Cricket, you might as
well have guessed that I found things more than a little difficult. Luckily Tom
Archer, James Johnson and Neil Van Note promptly answered my questions.
The sample program allows you to capture the entire screen or only the
current form and also allows you to save the image, though here I have hard
coded the filename and path, as I was too lazy to show a save dialog. If you
repeatedly click on the capture buttons, you get a weird effect of cascading
screen captures, one on top of the other as shown in the screenshot of the
sample program.
Quick Rundown
Using GetDC or GetWindowDC depending on whether we
are capturing the screen or the current window, we get our HDC
using which we call CreateCompatibleDC to create our memory DC.
Using a call to GetSystemMetrics we get the size of the screen and
then call CreateCompatibleBitmap to create a bitmap. Then we select
this bitmap into the memory DC using a call to SelectObject and
save the old bitmap. Using BitBlt we copy the screen or window
contents into this bitmap which is now selected into the memory DC. Then we
select the original bitmap back into the DC, delete the memory DC, release the
DC, and delete the bitmap. To be frank, there is not much .NET stuff involved in
the code, but imagine if you had to write all this using C#. Think of all the
P/Invoke stuff you'd have to do and the ugly declarations you'd have had to
write for the API calls. With MC++ you are saved all that bother.
Full Source Listing
The source code is self-explanatory. Notice how I have written my WinMain.
This is because I am including windows.h where WinMain is already prototyped in
that fashion.
#include "stdafx.h"
#using <mscorlib.dll>
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#include <tchar.h>
#include <windows.h>
using namespace System;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Windows::Forms;
public __gc class NForm : public Form
{
public:
Button *btn;
Button *btn2;
Button *btn3;
PictureBox *pbox;
void btn_Click(Object *sender, System::EventArgs* e);
void CaptureScreen(bool FullScreen);
NForm()
{
this->StartPosition = FormStartPosition::CenterScreen;
this->Text = "Capture screen - Nish for CodeProject -IJW";
this->Size = Drawing::Size(750,550);
this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
btn=new Button();
btn->Text="Capture Screen";
btn->Location=Point(5,5);
btn->Size=Drawing::Size(100,30);
btn->add_Click(new EventHandler(this,&NForm::btn_Click));
this->Controls->Add(btn);
btn2=new Button();
btn2->Text="Capture Form";
btn2->Location=Point(125,5);
btn2->Size=Drawing::Size(100,30);
btn2->add_Click(new EventHandler(this,&NForm::btn_Click));
this->Controls->Add(btn2);
btn3=new Button();
btn3->Text="Save C:\\Z.Jpg";
btn3->Location=Point(250,5);
btn3->Size=Drawing::Size(100,30);
btn3->add_Click(new EventHandler(this,&NForm::btn_Click));
this->Controls->Add(btn3);
pbox = new PictureBox();
pbox->Location=Point(5,45);
pbox->Size=Drawing::Size(730,470);
pbox->BorderStyle = BorderStyle::Fixed3D;
pbox->SizeMode = PictureBoxSizeMode::StretchImage;
this->Controls->Add(pbox);
}
};
int __stdcall WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
Application::Run(new NForm());
return 0;
}
void NForm::btn_Click(Object *sender, System::EventArgs *e)
{
if(sender->Equals(btn))
CaptureScreen(true);
else
{
if(sender->Equals(btn2))
CaptureScreen(false);
else
pbox->Image->Save("C:\\Z.Jpg",
Drawing::Imaging::ImageFormat::Jpeg);
}
}
void NForm::CaptureScreen(bool FullScreen)
{
HDC hDC;
if(FullScreen)
hDC = GetDC(NULL); else
{
HWND hWnd=(HWND)this->Handle.ToInt32(); hDC = GetWindowDC(hWnd); }
HDC hMemDC = CreateCompatibleDC(hDC);
RECT r;
GetWindowRect((HWND)this->Handle.ToInt32(),&r); SIZE size;
if(FullScreen)
{
size.cx = GetSystemMetrics(SM_CXSCREEN);
size.cy = GetSystemMetrics(SM_CYSCREEN);
}
else
{
size.cx = r.right-r.left;
size.cy = r.bottom-r.top;
}
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, size.cx, size.cy);
if (hBitmap)
{
HBITMAP hOld = (HBITMAP) SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
pbox->Image = Image::FromHbitmap(hBitmap);
DeleteObject(hBitmap);
}
}
History
- May 7 02 - Posted the article
- Jul 4 02 - Added sample VC++ project
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site -
www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff -
blog.voidnish.com.
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy
Summer Love and Some more Cricket as well as a programming book –
Extending MFC applications with the .NET Framework.
Nish's latest book
C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.