Link to home
Start Free TrialLog in
Avatar of pgmerLA
pgmerLA

asked on

Drawing with GDIplus and double buffering

Drawing with GDIplus and double buffering:
Avatar of JimBeveridge
JimBeveridge
Flag of United States of America image

Please update this topic with the body of your question, otherwise delete the question.
Could you be more specific.  Are you asking how to double buffer your paints using GDI++?  If so, you can create a Bitmap of the same size as the region you want to paint:

http://msdn.microsoft.com/en-us/library/ms534420%28v=VS.85%29.aspx

Then you can a Graphics object based on that bitmap:

http://msdn.microsoft.com/en-us/library/ms534453%28v=VS.85%29.aspx

You can then paint into the bitmap using the methods of the Graphics class.

Finally, you can create a Graphics object for the DC into which you want to paint and then paint the Bitmap onto that DC using that second Graphics object.
Ok for the next step we would like to actually begin drawing something , wouldn't we?
Find the function WndProc and in there the WM_PAINT case, this is where all the drawing occurs...
Now if we where to draw directly on the window surface, and the drawing would change frequently, we would see a "flickering" effect (very un-pretty) so to overcome that we will commence all the drawing into a bitmap in memory and then copy this entire bitmap to the window surface at once.
So... After the line that says BeginPaint... put:

int width = ps.rcPaint.right - ps.rcPaint.left;
int height = ps.rcPaint.bottom - ps.rcPaint.top;
Bitmap memoryBitmap(width, height);
Graphics(&memoryBitmap);

Open in new window


Now we have the graphics object which we will use to draw everything so let's draw a simple rectangle...

gr.Clear(Color::White);		// Clear to white background
Pen pen(Color::Red);		// This is the pen we will use to draw
gr.DrawRectangle(&pen, 10,10,100,100); // Draw rectangle from 10,10 to 110,110

Open in new window


Now that we drawn something on our memory bitmap it's time to copy it to the actual window surface.
To do so we will create another Graphics object from the HDC of the window that the BeginPaint function created for us:
Graphics grScreen(hdc);

Open in new window

Now just draw the memory bitmap on this new graphics object:
grScreen.DrawImage(&memoryBitmap, 0,0);

Open in new window


That's it if you now run the application this is what you should see:

 User generated image
Now if you'll try to resize the window now you will see that there is still flickering on the rectangle this is happening because window send the WM_ERASEBACKGROUND message prior to painting and erases the window to white, so we need to tell windows that we are handling the erase ourself. To do so add another case statement to the select where the WM_PAINT is located like this:
case WM_ERASEBKGND:
return TRUE;
break;

Open in new window


Now that tells window that the message is received and handled by us...
Try resizing the window now, voila , no flickering.

I am not posting the entire code intentionally since I want you to learn from this and not just blindly copy and paste, how ever if you run into trouble with this I'll post the entire code.

If everything works , on to the next step: "Reading the file and drawing the grid"
Unfortunately I am not aware of any other means of communicating here but the comments... Also sorry it takes time to answer each question, part of it is because of our time difference... (10 hours I believe)
Hey pgmerLA,
Are you stuck? Do you need more help?
Avatar of pgmerLA
pgmerLA

ASKER

Hi SunnyDark,
I am actually stuck in step 1.
I have tried to do it by myself and I am running into trouble.

I have few questions that seems so basic, they are embarrassing to ask.
1.When I create a project, should I click on/off "Precompiled header"?

2.how do I open the stdafx.h file and how do I find "#define WIN32_LEAN_AND_MEAN"?

3.you said to comment it. what do you mean by it?

4. how do I find the InitInstance function?

Thanks for the help.

OK ,
When you create the project choose:
Application type: Windows application
Leave everything else as it is...
All the necessary files will be created for you.

If you followed the instructions and created a new project in Visual Studio 2008 you should heve the following project structure:
 User generated image
 
As you can see on the left (the location of solution explorer may be different for you) there are the project files... One of them is stdafx.h , you can see it opened in the editor.
On line 10 you can see the following:
#define WIN32_LEAN_AND_MEAN

I've put double forward slash to comment it out (this is how you comment a line in c++, just start it with double forward slashes).

Now if you open the file GDIGraph.cpp (provided you named the project GDIGraph) you should be able to find the InitInstance function inside that file:
The function definition looks like this:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
.....
}

You may also use the find function (in edit menu) to find things in your solution.
Avatar of pgmerLA

ASKER

Hi SunnyDark,

I have completed the first step, but I am still getting lost of error code: c4430,c2440, c2146 etc...(104 in total)
// GDIGraph.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "GDIGraph.h"
#pragma comment(lib,"gdiplus.lib")
#include<gdiplus.h>
using namespace Gdiplus;

#define WIN32_LEAN_AND_MEAN  //WHAT TYPE OF COMMENT WOULD BE APPROPRIATE HERE?
#define MAX_LOADSTRING 100


// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR	gdiplusToken;


// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_GDIGRAPH, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIGRAPH));

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	GdiplusShutdown(gdiplusToken);
	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDIGRAPH));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_GDIGRAPH);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   GdiplusShutdown(gdiplusToken);
   
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: Add any drawing code here...
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

Open in new window

Ok , Here is what you need to fix,
Remove the line
#define WIN32_LEAN_AND_MEAN
From this file.
This is already defined in stdafx.h on line 10.
When I say to comment something OUT it means to make this line a comment or imply put, just erase it. So open stdafx.h go to line 10, find #define WIN32_LEAN_AND_MEAN and erase it (or make it a comment , that is what I meant from the beginning).
Avatar of pgmerLA

ASKER

got it. step 1 accomplished!
Nice,
You already have step 2 right here (this question), so you may move right to it.
Avatar of pgmerLA

ASKER

Can you tell me what part of the code I am making a mistake?
I can't compile it.
// GDIGraph.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "GDIGraph.h"
#pragma comment(lib,"gdiplus.lib")
#include<gdiplus.h>
using namespace Gdiplus;


#define MAX_LOADSTRING 100


// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR	gdiplusToken;


// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_GDIGRAPH, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIGRAPH));

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	GdiplusShutdown(gdiplusToken);
	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDIGRAPH));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_GDIGRAPH);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   GdiplusShutdown(gdiplusToken);
   
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: Add any drawing code here...
		int width = ps.rcPaint.right - ps.rcPaint.left;
		int height = ps.rcPaint.bottom - ps.rcPaint.top;
		Bitmap memoryBitmap(width, height);
		Graphics(&memoryBitmap);
		gr.Clear(Color::White);		// Clear to white background
		Pen pen(Color::Red);		// This is the pen we will use to draw
		gr.DrawRectangle(&pen, 10,10,100,100); // Draw rectangle from 10,10 to 110,110
		Graphics grScreen(hdc);
		grScreen.DrawImage(&memoryBitmap, 0,0);
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_ERASEBKGND:
	return TRUE;
	break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

Open in new window

You are calling GdiplusShutdown in InitInstance (line 126) instead of GdiplusStartup
Avatar of pgmerLA

ASKER

do you know how to make line number appear in MS VS2008?
Avatar of pgmerLA

ASKER

for the GdiplusStartup(), how can I know what arguments to put in?  line 126.
Avatar of pgmerLA

ASKER

Hi SunnyDark,

Are you still interested in teaching me?
I hope you are :)
Sure , I somehow missed your comments...
So to make line numbers to appear look at the screen cast.
 SunnyDark-434444.flv

Now for the gdistartup function, it was actually my fault , in the original answer for the first step the line with gdistartup somehow "mysteriously" disappeared from the post...
The line should be:
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

Open in new window

Avatar of pgmerLA

ASKER

Hi SunnyDark,
I have attached my code.
I can't compile it. Could you tell me where I made a mistake?
Thanks.
Matt


 error C2040: 'memoryBitmap' : 'Gdiplus::Graphics &' differs in levels of indirection from 'Gdiplus::Bitmap'
error C2530: 'memoryBitmap' : references must be initialized
 error C2065: 'gr' : undeclared identifier
error C2228: left of '.Clear' must have class/struct/union
1>        type is ''unknown-type''
error C2065: 'gr' : undeclared identifier
 error C2228: left of '.DrawRectangle' must have class/struct/union
 error C2360: initialization of 'grScreen' is skipped by 'case' label
 error C2360: initialization of 'pen' is skipped by 'case' label
error C2360: initialization of 'memoryBitmap' is skipped by 'case' label
 error C2360: initialization of 'height' is skipped by 'case' label
error C2360: initialization of 'width' is skipped by 'case' label
 error C2360: initialization of 'grScreen' is skipped by 'case' label
: error C2360: initialization of 'pen' is skipped by 'case' label
 error C2360: initialization of 'memoryBitmap' is skipped by 'case' label
error C2360: initialization of 'height' is skipped by 'case' label

error C2360: initialization of 'width' is skipped by 'case' label
 error C2361: initialization of 'grScreen' is skipped by 'default' label

 error C2361: initialization of 'pen' is skipped by 'default' label

 error C2361: initialization of 'memoryBitmap' is skipped by 'default' label



// GDIGraph.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "GDIGraph.h"
#pragma comment(lib,"gdiplus.lib")
#include<gdiplus.h>
using namespace Gdiplus;


#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR			gdiplusToken;

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_GDIGRAPH, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIGRAPH));

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	GdiplusShutdown(gdiplusToken);
	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDIGRAPH));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_GDIGRAPH);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		
		// TODO: Add any drawing code here...
		int width = ps.rcPaint.right - ps.rcPaint.left;
		int height = ps.rcPaint.bottom - ps.rcPaint.top;
		Bitmap memoryBitmap(width, height);
		Graphics(&memoryBitmap);
		gr.Clear(Color::White); // Clear to white background
        Pen pen(Color::Red); // This is the pen we will use to draw
        gr.DrawRectangle(&pen, 10,10,100,100); // Draw rectangle from 10,10 to 110,110
		Graphics grScreen(hdc);
		grScreen.DrawImage(&memoryBitmap, 0,0);
		EndPaint(hWnd, &ps);
		break;
	case WM_ERASEBKGND:
		return TRUE;
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of SunnyDark
SunnyDark
Flag of Israel image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial