7/25/2019 C Windows Programming Tutorial
1/22
1 - 22
C Windows Programming Tutorial
{From:http://www.geocities.com/Heartland/Meadows/9818/win32tut/index.html}
Lesson 1 - Your First windows program
Clickhereto download the source files to this tutorial.
Welcome to a journey in Windows programming. In this lesson, you will create your first
windows application which will display a "Hello World" message box.
1. If you haven't started Dev-C++ already, do so now.
2. Select File->New Project. In the dialog box that appears, choose the project type
as an Empty Project and name the project Lesson1. Also choose the C language.
3.
You land up with an empty project. Now we will set the project type to Win32GUI. This tells the compiler that the project is to be compiled as a windows GUI
application. Press Alt+P to get the project options. Select Win32 GUI under Type.
4. Right click Lesson1 on the Project Panel and click New Unit. A new file is
created. Save it as lesson1.c5. Now enter the code as given below:
http://www.geocities.com/Heartland/Meadows/9818/win32tut/index.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/index.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson1.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson1.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson1.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson1.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/index.html7/25/2019 C Windows Programming Tutorial
2/22
2 - 22
/* Windows Programming Tutorial Series* Lesson 1 - Your first windows program* Pravin Paratey (October 08, 2002)**/#include
int WINAPIWinMain(HINSTANCE hInst,
HINSTANCE hPrevInstance,LPSTR lpCmdLine,
int nCmdShow){
MessageBox (NULL, "Hello World! This is my first WIN32 program","Lesson 1", MB_OK);
return 0;}
6. Press F9 to compile and run the project. You should see the following,
Congratulations! You have just written your first windows application.
Whoa! What just happened there?
Letsbreak down the code.
1. #include All Windows programs must include the header file windows.h. This file has the
definitions of Windows system calls or the WinAPI. The WinAPI has everything
necessary for programming under windows.
2. WinMain (..)This is the entry point of a windows application. This is like the main() of a
console based application. WinMain is declared as,
int WINAPI WinMain(
HINSTANCE hInst, /* Handle to the current instance */HINSTANCE hPrevInstance,/* Handle to the previous instance */LPSTR lpCmdLine, /* pointer to command line arguments */int nCmdShow); /* show state of the window */
The parameters of WinMain are self-explanatory, except perhaps nCmdShow.
nCmdShow tells you in what manner you are expected to display this window(Maximized, Minimized, etc).
7/25/2019 C Windows Programming Tutorial
3/22
3 - 22
We haven't used any of these parameters in this lesson, but we'll see their uses in
the coming lessons.
3. MessageBox(..)This is a windows function which displays a messagebox. The MessageBox
function is declared as,
int MessageBox(HWND hWnd, /* Handle of owner window */LPCTSTR lpText, /* Address of text in message box */LPCTSTR lpCaption,/* Address of title of message box */UINT uType); /* Style of message box */
4. return 0This is the return value to the system.
This brings us to the end of the first lesson. Clickhereto go to the next lesson.
http://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson2.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson2.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson2.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson2.html7/25/2019 C Windows Programming Tutorial
4/22
4 - 22
Lesson 2 - Understanding messages and
events
Clickhereto download the source files to this tutorial.
In this tutorial you will be introduced to the event-driven programming model. You will
learn how Windows uses messages to communicate with applications, how event based
programming works, what callback functions are, and while doing this create a basicwindows application
Before we begin
If you do not have the platform SDK help files (WinAPI docs) - no, they do not comewith Dev-C++ - then I suggest you do one of the following:
1. Downloadthisfile OR2. Download the Windows platform SDK frommsdn
.
And so i t begins
Create a blank windows project in Dev-C++ (In case you've forgotten how this is done,take a look at theprevioustutorial). Name it lesson2. Open a new file(Press Ctrl+N) andsave it(Ctrl+S) as main.c. Enter the following code,
1 #include 23 HWND hwndMain; //Main window handle45 // Callback function
http://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson2.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson2.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson2.zipftp://ftp.cs.virginia.edu/pub/lcc-win32/win32hlp.exeftp://ftp.cs.virginia.edu/pub/lcc-win32/win32hlp.exeftp://ftp.cs.virginia.edu/pub/lcc-win32/win32hlp.exehttp://msdn.microsoft.com/http://msdn.microsoft.com/http://msdn.microsoft.com/http://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson1.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson1.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson1.htmlhttp://www.geocities.com/Heartland/Meadows/9818/win32tut/lesson1.htmlhttp://msdn.microsoft.com/ftp://ftp.cs.virginia.edu/pub/lcc-win32/win32hlp.exehttp://www.geocities.com/Heartland/Meadows/9818/win32tut/src/lesson2.zip7/25/2019 C Windows Programming Tutorial
5/22
5 - 22
6 LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);7 // Windows entry point8 int WINAPI9 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)10 {11 MSG msg; // MSG structure to store messages12 WNDCLASSEX wcx; // WINDOW class information13
14 // Initialize the struct to zero15 ZeroMemory(&wcx,sizeof(WNDCLASSEX));16 wcx.cbSize = sizeof(WNDCLASSEX); // Window size. Must always be sizeof(WNDCLASSEX)17 wcx.style = CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ; // Class styles18 wcx.lpfnWndProc = (WNDPROC)MainWndProc; // Pointer to the callback procedure19 wcx.cbClsExtra = 0; // Extra byte to allocate following the wndclassex structure20 wcx.cbWndExtra = 0; // Extra byte to allocate following an instance of the structure21 wcx.hInstance = hInstance; // Instance of the application22 wcx.hIcon = NULL; // Class Icon23 wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // Class Cursor24 wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW); // Background brush25 wcx.lpszMenuName = NULL; // Menu resource26 wcx.lpszClassName = "Lesson2"; // Name of this class27 wcx.hIconSm = NULL; // Small icon for this class2829 // Register this window class with MS-Windows30 if (!RegisterClassEx(&wcx))
31 return 0;3233 // Create the window34 hwndMain = CreateWindowEx(0, //Extended window style35 "Lesson2", // Window class name36 "Lesson 2 - A simple win32 application", // Window title37 WS_OVERLAPPEDWINDOW, // Window style38 CW_USEDEFAULT,CW_USEDEFAULT, // (x,y) pos of the window39 CW_USEDEFAULT,CW_USEDEFAULT, // Width and height of the window40 HWND_DESKTOP, // HWND of the parent window (can be null also)41 NULL, // Handle to menu42 hInstance, // Handle to application instance43 NULL); // Pointer to window creation data4445 // Check if window creation was successful46 if (!hwndMain)47 return 0;
4849 // Make the window visible50 ShowWindow(hwndMain,SW_SHOW);5152 // Process messages coming to this window53 while (GetMessage(&msg,NULL,0,0))54 {55 TranslateMessage(&msg);56 DispatchMessage(&msg);57 }5859 // return value to the system60 return msg.wParam;61 }6263 LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)64 {
65 switch (msg)66 {67 case WM_DESTROY:68 // User closed the window69 PostQuitMessage(0);70 break;71 default:72 // Call the default window handler73 return DefWindowProc(hwnd,msg,wParam,lParam);74 }75 return 0;76 }
7/25/2019 C Windows Programming Tutorial
6/22
6 - 22
Whew. That was long! Press F9 to compile and run. You have a basic window on your
screen!
Breaking i t up
Messages and the MSG Structure
The MSG structure is what stores the messages received by your application. Beforegoing any further, letstake a look at the event-driven programming model.
Event driven programming model
To understand event driven programming, we draw analogies from the real world.
1. Apersonplaces an order at a restaurant.
2. The waiterconveys this order to the chef.
3.
The chefgets busy and soon the order is served.
1. The userclicks the maximize button.2. Windowstells your applicationthat the maximize button has been pressed.
3. Your applicationthen redraws its window so that it covers the screen.
Every time windows has to communicate with your application, it sends messages to your
application. Once all initializations have been done and the window shown on screen, all
your application has to do is poll for windows messages.
The lines up to 51 create and show the window and the lines 52-57 poll for messages.
The GetMessage()function gets the next message to be processed from the message
queue. GetMessage()returns a non-zero value for every message other than WM_QUIT.This means that the while loop continues until it is time to quit.
TranslateMessage()translates virtual key messages to character messages.
DispatchMessage()dispatches the message to a window procedure. This means that for
messages coming to our window, the MainWndProc()is called by Windows(tm) through
DispatchMessage().
How does Windows(tm) know which function to call? Well, we tell Windows(tm) duringWNDCLASSEX initialization [line 18].
WNDCLASSEX structure
Every window that you create has an associated WNDCLASSEX structure. The
WNDCLASSEX structure provides all the information necessary for Windows(tm) to do
7/25/2019 C Windows Programming Tutorial
7/22
7 - 22
perform window related functions like drawing its icon, cursor, menu, calling the
callback function which will receive messages and so on.
The WNDCLASSEX structure is defined as,
typedef struct _WNDCLASSEX {UINT cbSize;UINT style;WNDPROC lpfnWndProc;int cbClsExtra;int cbWndExtra;HANDLE hInstance;HICON hIcon;HCURSOR hCursor;HBRUSH hbrBackground;LPCTSTR lpszMenuName;LPCTSTR lpszClassName;HICON hIconSm;
} WNDCLASSEX;
cbSize
This must always be set to sizeof(WNDCLASSEX).style
This specifies the class styles. Take a look at your SDK documentation for the
values this member can take.lpfnWndProc
Pointer to the WndProc which will handle this windows' messages.
cbClsExtraNumber of extra bytes to allocate at the end of the WNDCLASSEX structure.
cbWndExtra
Number of extra bytes to allocate at the end of the window instance.hInstance
Identifies the instance that the window procedure of this class is within.
hIcon
Handle to the icon associated with windows of this class.
hCursorHandle to the cursor for windows of this class.
hbrBackground
Identifies the class background brush.lpszMenuName
Identifies the menu for windows of this class.
lpszClassNamePointer to a NULL terminated string or an atom specifying the class of thisstructure.
hIconSm
Handle to the small icon associated with this class.
7/25/2019 C Windows Programming Tutorial
8/22
8 - 22
Registering your window class
After you've created your window class, you need to tell Windows(tm) about it. This is
done by registering the class with windows. The function call is RegisterClassEx(..).Once this is done, you can create instances of this window by calling
CreateWindowEx(..)with the proper arguments.
Creating the window
A window is created by calling the CreateWindowEx(..)defined as,
HWND CreateWindowEx(DWORD dwExStyle, // extended window styleLPCTSTR lpClassName, // pointer to registered class nameLPCTSTR lpWindowName, // pointer to window nameDWORD dwStyle, // window styleint x, // horizontal position of windowint y, // vertical position of window
int nWidth, // window widthint nHeight, // window heightHWND hWndParent, // handle to parent or owner windowHMENU hMenu, // handle to menu, or child-window identifierHINSTANCE hInstance, // handle to application instanceLPVOID lpParam // pointer to window-creation data);
Lines 34-43 create the window. If the creation was successful a non-zero handle is
returned by CreateWindowExafter which ShowWindow()shows the window on thescreen.
TIP:It is a good idea to keep referring to these functions in your sdk docs while reading
this tutorial.
7/25/2019 C Windows Programming Tutorial
9/22
9 - 22
Callback functions
A callback function is the one that receives the messages sent to your application. This is
where you do something about the message. We provide a pointer to this function while
defining the window class [line 18].
Callback functions have to be defined as,
LRESULT CALLBACKfunction-name(
HWND hwnd, // Handle of window which received thismessage
UINT msg, // The messageWPARAM wParam, // Extra informationLPARAM lParam // Extra information);
HWND hwndThe handle of the window is specified so that you know which window to act
upon. This is necessary because you may have created more than one instance of
the window.UINT msg
This contains the message sent.
WPARAM wParam and WPARAM lParam
7/25/2019 C Windows Programming Tutorial
10/22
10 - 22
wParam and lParam are used to pass extra info about the message. For example a
WM_LBUTTONDOWN (left mouse button down) message will have the x and y
co-ordinates as the upper and lower word of lParam and wParam will tell if anymodifier keys (ctrl, alt, shift) have been pressed.
MainWndProc
63 LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAMlParam)64 {65 switch (msg)66 {
...
The switch statement lets us select which message was sent. There are over 200 messages
that windows can send your application. To read about them, just search for WM_ in
your sdk docs.
WM_DESTROY
...67 case WM_DESTROY:68 // User closed the window69 PostQuitMessage(0);70 break;
7/25/2019 C Windows Programming Tutorial
11/22
11 - 22
...
The WM_DESTROY message is sent to your application when the user teminates the
application either by clicking the X at the upper right corner, pressing Alt+F4, or quitsthe application by other means.
PostQuitMessage()causes GetMessage(..)[line 53] to return false and thus breaking
out of the while loop and exiting the application. The argument to PostQuitMessageisthe return value to the system.
DefWindowProc(..)
What about the other 200 or so messages? Surely you, the programmer, aren't going towrite code for all the 200 messages. Fortunately, Windows(tm) provides the
DefWindowProc(..)function which handles all the messages. For the purposes ofdisplaying a simple window, your MainWndProc could very well have consisted of
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAMlParam){
return DefWindowProc(hwnd,msg,wParam,lParam);}
What this means is that every time you want to do something about a message, add the
case switch for the message and write the code which does something about it. All
messages that you don't want to handle should be passed to the DefWindowProc(). Thisis what we have done in our code.
...71 default:72 // Call the default window handler73 return DefWindowProc(hwnd,msg,wParam,lParam);
...
Add ing Funct ional ity
Lets pop up a MessageBox which will display the co-ordinates of the point where the left
mouse button was pressed. To do this you will have to handle the
WM_LBUTTONDOWN message.
Add this code at line 70
...68 PostQuitMessage(0);69 break;70 case WM_LBUTTONDOWN:71 pt.x = LOWORD(lParam);72 pt.y = HIWORD(lParam);73 wsprintf(str,
7/25/2019 C Windows Programming Tutorial
12/22
12 - 22
"Co-ordinates are\nX=%i and Y=%i",pt.x,pt.y);74 MessageBox(hwnd, str, "Left Button Clicked", MB_OK);75 break;76 default:
...
Press F9. This is what you should see when you click anywhere inside the window.
Exercise
Try this exercise. Pop up a message every time a key is pressed on the keyboard.
Hint: Handle the WM_CHAR message. Remember to refer to your sdk docs.
If you can manage that, give yourself a pat on the back. You now understand the basicsof event-driven programming - the mechanism which Windows(tm) uses to communicatewith your application. You have crossed one of the more difficult hurdles in learning
windows programming.
Don't worry if you could not do the exercise or if things are still a bit hazy. These
concepts will be used in every single lesson after this and it will soon become second
nature to you.
7/25/2019 C Windows Programming Tutorial
13/22
13 - 22
Understanding GDI Elements - A Part of
the series on Win32 Programming
Clickhereto download the source code for this tutorial.
GDI (which stands for graphics device interface) is what enables you to draw on the
screen without worrying about the underlying hardware. GDI functions also allow you todraw on other output devices like the printer, memory devices and metafiles. Windows
provides functions that let you draw - among other stuff - lines, circles, text and images in
various colors and styles.
You can think of GDI as a drawing kit complete with paintbrushes, watercolors, canvas,
rulers and other instruments.
Device Contexts
The first thing you must understand is device contexts. A device context is a structurethat defines a set of graphic objects and their associated attributes, as well as the graphicmodes that affect output. The graphic objects include a pen for line drawing, a brush for
painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for
defining the set of available colors, a region for clipping and other operations, and a pathfor painting and drawing operations.
Following our analogy, a device context can be considered as a canvas with certainspecial properties. You can draw and paint on this canvas and it will always appear to
others the way it was intended, even if the canvas were transformed into a sketch paper ora post-it note.
Before your application draws anything on screen, it must get its device context. This is
done through the GetDC()call which is defined as HDC GetDC(HWND hwnd). After you
are done with drawing, you must release it. This is done by the ReleaseDC()call defined
as int ReleaseDC(HWND hwnd, HDC hdc).
Graphics Objects
Pens and Brushes
Pens and Brushes are used to draw lines and paint interiors of closed objects.
Fonts
TODO
http://www.geocities.com/Heartland/Meadows/9818/win32tut/gdi.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/gdi.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/gdi.ziphttp://www.geocities.com/Heartland/Meadows/9818/win32tut/gdi.zip7/25/2019 C Windows Programming Tutorial
14/22
14 - 22
Palettes
TODO
Bitmaps
TODO
Working Examp le
Now that all the theory is out of our way, let us put our new knowledge to practice. Inthis chapter we will build an application that lets us draw lines, rectangles, circles and
bitmaps.
We will begin with our skeleton code that draws a simple window.
// draw.c// Pravin Paratey
#include
// VariablesHWND hwndMain; // Main window HWND
// FunctionsLRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAMlParam);
int WINAPIWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow){
MSG msg;WNDCLASSEX wcx;
// Fill in the WNDCLASS Structwcx.cbSize = sizeof(WNDCLASSEX);wcx.style = CS_DBLCLKS;wcx.lpfnWndProc = MainWndProc;wcx.cbClsExtra = 0;wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;wcx.hIcon = LoadIcon (NULL, IDI_APPLICATION);wcx.hCursor = LoadCursor (NULL, IDC_ARROW);wcx.hbrBackground = (HBRUSH) COLOR_BACKGROUND;wcx.lpszMenuName = NULL;wcx.lpszClassName = "Draw";wcx.hIconSm = NULL;
// Register classif(!RegisterClassEx(&wcx))
7/25/2019 C Windows Programming Tutorial
15/22
15 - 22
return 0;
hwndMain = CreateWindowEx(0,"Draw","Draw Example Application",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,400,300,NULL,NULL,hInstance,NULL);
ShowWindow(hwndMain,nCmdShow);
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);}return msg.wParam;
}
// Callback function for the Main Window classLRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAMlParam){
switch(msg){case WM_DESTROY:
PostQuitMessage(0);break;
default:return DefWindowProc(hwnd,msg,wParam,lParam);
}return 0;
}
Selecting the Drawing Shape
A real application would use a toolbar to let the user select the shape to draw. Since
creating a toolbar is too much trouble, well address this by using character input from
the keyboard to switch between the drawing shapes.
Lets keep a global variable drawShape to indicate the current tool. Add the following
lines at the beginning of the file. The lines to be added are shown in bold.
#include
// Defines#define SHAPE_NULL 0
7/25/2019 C Windows Programming Tutorial
16/22
16 - 22
#define SHAPE_LINE 1#define SHAPE_RECT 2#define SHAPE_CIRCLE 3#define SHAPE_TEXT 4
// VariablesHWND hwndMain; // Main window HWNDint drawShape; // The shape to draw
// FunctionsLRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAMlParam);
Now add the following code to the MainWndProc message handler. This will select the
current tool.
LRESULT CALLBACK
MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){CHAR ch;
switch(msg){case WM_CHAR:
if(!drawing){
ch = (TCHAR) wParam;switch(ch){case 'n': // NULL
drawShape = SHAPE_NULL;
break;case 'l': // LINE
drawShape = SHAPE_LINE;break;
case 'r': // RECTANGLEdrawShape = SHAPE_RECT;break;
case 'c': // CIRCLEdrawShape = SHAPE_CIRCLE;break;
case 'f': // FREEHANDdrawShape = SHAPE_FREEHAND;break;
}}break;
case WM_DESTROY:PostQuitMessage(0);
Drawing Shapes
7/25/2019 C Windows Programming Tutorial
17/22
17 - 22
To draw a shape we will have to
1. Get the point where the user clicked the left mouse button.2. Draw a ghost shape while the user moves the mouse with the left button down.
3. Draw the final shape when the user releases the left mouse button.
This means handling the WM_LBUTTONDOWN, WM_MOUSEMOVE and
WM_LBUTTONUP messages.
WM_LBUTTONDOWN
1. Set drawing flag to indicate drawing has begun.
2. Store the start point in beginPoint variable.
3. Text is to be drawn at the current mouse location. If the selected shape is text,draw it.
WM_MOUSEMOVE
1. Check if the left mouse button is down and that we are actually drawing (This isnecessary because clicking the mouse outside the window and moving the mouse
in will also generate this message).
2. Erase old shape.3. Draw new shape.
Erasing and drawing this ghost or rubber shape is achieved by setting the draw modeofthe pen to NOTXOR. NOTXOR has the property that drawing twice undoes the effect of
the first draw.
WM_LBUTTONUP
If the drawing flag was set,
1. Set drawing flag to false
2. Erase the ghost shape
3. Draw a permanent one
LRESULT CALLBACKMainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
CHAR ch; // This will contain keyboard inputHDC hdc; // Handle to the device contextHBRUSH hbrush; // Handle to BRUSH objectHBRUSH hOldBrush; // Stores the old BRUSH objectHPEN hPen;static POINT oldPoint; // Stores the old pointstatic POINT beginPoint; // Stores the begin pointPOINT thisPoint; // Stores the current pointstatic bool drawing = false;int ropOld; // Stores the old Raster OperatorRECT rc;
7/25/2019 C Windows Programming Tutorial
18/22
18 - 22
case WM_DESTROY:PostQuitMessage(0);break;
case WM_LBUTTONDOWN:// Says, We've begun drawingdrawing = true;
// Store the begin pointbeginPoint.x = LOWORD(lParam); // Returns x co-ordinatebeginPoint.y = HIWORD(lParam); // Returns y co-ordinate// Store the old pointoldPoint = beginPoint;break;
case WM_LBUTTONUP:if (drawing){
drawing = false;// Get Device contexthdc = GetDC(hwnd);// Set ROPropOld = SetROP2(hdc, R2_NOTXORPEN);// Get this pointthisPoint.x = LOWORD(lParam);thisPoint.y = HIWORD(lParam);
switch(drawShape){// This statement isn't neededcase SHAPE_NULL: // Do Nothing
break;case SHAPE_LINE:
// Erase old lineMoveToEx(hdc, beginPoint.x, beginPoint.y, NULL);LineTo(hdc, oldPoint.x, oldPoint.y);// Reset ROPSetROP2(hdc, ropOld);// Draw permanent oneMoveToEx(hdc, beginPoint.x, beginPoint.y, NULL);LineTo(hdc, thisPoint.x, thisPoint.y);break;
case SHAPE_RECT:// Erase old rect
Rectangle(hdc, beginPoint.x, beginPoint.y,oldPoint.x, oldPoint.y);
// Reset ROPSetROP2(hdc, ropOld);// Draw permanent oneRectangle(hdc, beginPoint.x, beginPoint.y,
thisPoint.x, thisPoint.y);break;
case SHAPE_CIRCLE:// Erase old circleEllipse(hdc, beginPoint.x, beginPoint.y, oldPoint.x,
oldPoint.y);// Reset ROPSetROP2(hdc, ropOld);// Draw permanent oneEllipse(hdc, beginPoint.x, beginPoint.y, thisPoint.x,
thisPoint.y);
break;}ReleaseDC(hwnd, hdc);
}break;
case WM_MOUSEMOVE:// Have we begun drawing?// Is the left button down?if (drawing && ((MK_LBUTTON & wParam) == MK_LBUTTON)){
// Get Device contexthdc = GetDC(hwnd);
7/25/2019 C Windows Programming Tutorial
19/22
19 - 22
// Set rop to NOTXOR so that we can draw and eraseropOld = SetROP2(hdc, R2_NOTXORPEN);// Store this pointthisPoint.x = LOWORD(lParam);thisPoint.y = HIWORD(lParam);
switch(drawShape){
// This statement isn't neededcase SHAPE_NULL: // Do Nothingbreak;
case SHAPE_LINE:// Erase old lineMoveToEx(hdc, beginPoint.x, beginPoint.y, NULL);LineTo(hdc, oldPoint.x, oldPoint.y);// Draw new oneMoveToEx(hdc, beginPoint.x, beginPoint.y, NULL);LineTo(hdc, thisPoint.x, thisPoint.y);break;
case SHAPE_RECT:// Erase old rectRectangle(hdc, beginPoint.x, beginPoint.y,
oldPoint.x, oldPoint.y);// Draw new oneRectangle(hdc, beginPoint.x, beginPoint.y,
thisPoint.x, thisPoint.y);break;case SHAPE_CIRCLE:
// Erase old circleEllipse(hdc, beginPoint.x, beginPoint.y, oldPoint.x,
oldPoint.y);// Draw new oneEllipse(hdc, beginPoint.x, beginPoint.y, thisPoint.x,
thisPoint.y);break;
}oldPoint = thisPoint;SetROP2(hdc, ropOld);ReleaseDC(hwnd, hdc);
}break;
default:return DefWindowProc(hwnd,msg,wParam,lParam);
Drawing Lines
The LineTo function draws a line from the current position to the point specified in itsarguments. Before drawing a line, we must move our pen to the starting co-ordinates.
This is done through the MoveToEx function.
Raster Operations
Raster Operations specify how the current PEN and BRUSH colors will be combined
with the colors on the screen.
R2_NOTXORPEN
R2_NOTXOR is really NOT (XOR (current_color, screen_color)). For two one bitnumbers, the truth table is,
7/25/2019 C Windows Programming Tutorial
20/22
20 - 22
X Y XOR(X,Y) NOT(XOR(X,Y))0 0 0 10 1 1 01 0 1 01 1 0 1
This is a good time to compile and run your app. Try switching tools and drawing a fewlines, rectangles and ellipses. Your screen should look something like this,
Whats with the white interior?
The inside of the rectangle and circle is filled in white because it is the default brush. Ifyou dont want the insides to be filled, add the following code.
...ReleaseCapture();
// Get Device contexthdc = GetDC(hwnd);
// Set brush to hollowlogbrush.lbStyle = BS_HOLLOW;hbrush = CreateBrushIndirect(&logbrush);holdbrush = (HBRUSH)SelectObject(hdc, hbrush);
// Set ROPropOld = SetROP2(hdc, R2_NOTXORPEN);// Get this pointthisPoint.x = LOWORD(lParam);...
SelectObject(hdc, holdbrush); // Restore the brushDeleteObject(hbrush); // Free memoryReleaseDC(hwnd, hdc);
...
7/25/2019 C Windows Programming Tutorial
21/22
21 - 22
To change the fill color, add the code:
...ReleaseCapture();// Get Device contexthdc = GetDC(hwnd)
hbrush = CreateSolidBrush(RGB(255,0,0)); //RED brushholdbrush = (HBRUSH)SelectObject(hdc, hbrush);
// Set ROPropOld = SetROP2(hdc, R2_NOTXORPEN);// Get this pointthisPoint.x = LOWORD(lParam);...SelectObject(hdc, holdbrush); // Restore the brushDeleteObject(hbrush); // Free memoryReleaseDC(hwnd, hdc);
...
Drawing Text
Windows provides a variety of functions to draw text. We will use the DrawTextEx()function defined as
int DrawTextEx(HDC hdc, // handle to device contextLPTSTR lpchText, // pointer to string to drawint cchText, // length of string to drawLPRECT lprc, // pointer to rectangle coordinatesUINT dwDTFormat, // formatting optionsLPDRAWTEXTPARAMS lpDTParams // pointer to structure for options);
Add this code to draw text:
WM_CHAR
...case 'c': // CIRCLE
drawShape = SHAPE_CIRCLE;break;
case 't': // TEXTdrawShape = SHAPE_TEXT;
break;...
WM_MOUSEMOVE
...case SHAPE_CIRCLE:
// Erase old circle
7/25/2019 C Windows Programming Tutorial
22/22
Ellipse(hdc, beginPoint.x, beginPoint.y, oldPoint.x,oldPoint.y);
// Draw new oneEllipse(hdc, beginPoint.x, beginPoint.y, thisPoint.x,
thisPoint.y);break;
case SHAPE_TEXT:// Erase old text rectRectangle(hdc, beginPoint.x, beginPoint.y, oldPoint.x,
oldPoint.y);// Draw new oneRectangle(hdc, beginPoint.x, beginPoint.y, thisPoint.x,
thisPoint.y);break;
...
WM_LBUTTONUP
case SHAPE_TEXT:Rectangle(hdc, beginPoint.x, beginPoint.y, oldPoint.x,
oldPoint.y);// Reset ROPSetROP2(hdc, ropOld);rc.left = beginPoint.x;rc.top = beginPoint.y;rc.right = thisPoint.x;rc.bottom = thisPoint.y;DrawTextEx(hdc, strOut, lstrlen(strOut), &rc,
DT_END_ELLIPSIS|DT_NOCLIP|DT_WORDBREAK, NULL);break;
Persistent Drawing
If you minimize the window and restore it, youll notice that everything youve drawn is
erased. This is because Windows sends the WM_PAINTmessage to your application tellingit to redraw its client area. To keep persistent drawings, youve got two options to keep
a list of all objects and draw them on every call to WM_PAINTor to keep a snapshot of the
image and redraw it on WM_PAINT.