Page 1 of 1

Intro to the Windows API Part 3: Creating and using controls Rate Topic: -----

#1 Aphex19  Icon User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 615
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Posted 27 March 2011 - 10:12 AM

*
POPULAR

Welcome to my third intro to the Windows API tutorial, my first two tutorials can be found here...

Intro to the Windows API
Intro to the Windows API part 2: Creating a menu

In this tutorial, we will create a simple application which will demonstrate some of the more common controls in the Windows API. This application will allow us to input the title of the window using an edit control, and will look like this.

Posted Image

The code that we will use is losely based on code from earlier tutorials, except for a few additions, those being exception handling and an added header file to help organise our code better. Enough talking though, let's get straight to the code. I'll post the entire code here, then explain.

WinMain.h
#ifndef WINMAIN_H
#define WINMAIN_H

#include <Windows.h>	
#include <exception>

/* Create nice looking controls */
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' \
					   version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' \
						language='*'\"")

// Add new popup menu
#define ADDPOPUPMENU(hmenu, string) \
	HMENU hSubMenu = CreatePopupMenu(); \
	AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, string);

// Add a menu item
#define ADDMENUITEM(hmenu, ID, string) \
	AppendMenu(hSubMenu, MF_STRING, ID, string);

enum 
{
	IDC_FILE_EXIT = 10000,
	IDC_BUTTON_SHOW_MSG,
	IDC_EDIT_CTRL,
	IDC_STATIC_TEXT
};

LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void CreateWin32Window(HINSTANCE hInstance, int width, int height);

#endif /* WINMAIN_H */


WinMain.cpp
#include "WinMain.h"

// Global variables
const char *clsName = "WinAPI";
char *title	= "Windows API";
bool running = TRUE;
HWND hWnd = NULL;

/* 
 * Creates a menu and assigns it to the window
 * specified by the HWND passed.
 */
void CreateMainMenu(HWND hWnd)
{
    HMENU hMenu = CreateMenu();

	ADDPOPUPMENU(hMenu, "&File");
	ADDMENUITEM(hMenu, IDC_FILE_EXIT, "&Exit");

    SetMenu(hWnd, hMenu);
}

/* 
 * Creates all the common controls and assigns 
 * them to the window specified by the HWND passed.
 */
void CreateControls(HWND hWnd, HINSTANCE hInstance)
{
	HWND hStaticText	= NULL;
	HWND hButton		= NULL;
	HWND hEdit			= NULL;
	HWND hGroupBox      = NULL;

	// Create some static text
	if ((hStaticText =  CreateWindow( "Static", 
									  "Type in the edit box to change the title", 
									  WS_CHILD | WS_VISIBLE | SS_LEFT,	
								      40,40, 640,20, 
								      hWnd, NULL, hInstance, NULL)) == NULL)
	{
		throw std::exception("Failed to create controls");
	}

	// Create an edit control
	if ((hEdit =  CreateWindow( "Edit", 
								NULL, 
							    WS_VISIBLE|WS_CHILD|WS_BORDER|ES_AUTOHSCROLL|ES_AUTOVSCROLL,	
							    40,80,243,23, 
						        hWnd, (HMENU)IDC_EDIT_CTRL, 
							    hInstance, NULL)) == NULL)
	{
		throw std::exception("Failed to create controls");
	}

	// Create a group box control
	if ((hGroupBox =  CreateWindow( "Button", 
								    "Title edit", 
								    WS_CHILD | WS_VISIBLE | BS_GROUPBOX,	
							        20, 10, 292, 185, 
						            hWnd, NULL, 
							        hInstance, NULL)) == NULL)
	{
		throw std::exception("Failed to create controls");
	}

	// Create a button control
	if ((hButton =  CreateWindow( "Button", 
								  "Reset title", 
								  BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,	
							      95,130,120,28, 
						          hWnd, (HMENU)IDC_BUTTON_SHOW_MSG, 
							      hInstance, NULL)) == NULL)
	{
		throw std::exception("Failed to create controls");
	}

	// Create underlined text for the static control.
	HFONT hFontBold = CreateFont( 16,0, 
								  0,0, 
								  560,FALSE,FALSE,FALSE, 
								  ANSI_CHARSET,OUT_DEVICE_PRECIS,CLIP_MASK, 
								  ANTIALIASED_QUALITY, DEFAULT_PITCH, 
								  "MS Outlook"); 

	// Use normal font for other controls.
	HFONT hFont = CreateFont( 17,0, 
							  0,0, 
							  550,FALSE,FALSE,FALSE, 
							  ANSI_CHARSET,OUT_DEVICE_PRECIS,CLIP_MASK, 
							  ANTIALIASED_QUALITY, DEFAULT_PITCH, 
							  "MS Outlook"); 

	// Set the new font for the controls
    SendMessage(hStaticText, WM_SETFONT, WPARAM (hFont), TRUE);
    SendMessage(hGroupBox, WM_SETFONT, WPARAM (hFontBold), TRUE);
    SendMessage(hButton, WM_SETFONT, WPARAM (hFont), TRUE);
    SendMessage(hEdit, WM_SETFONT, WPARAM (hFont), TRUE);
}

/* 
 * Entry point of the application.
 */
int WINAPI WinMain( HINSTANCE hInstance,		
					HINSTANCE hPrevInstance,	
					LPSTR lpCmdLine,			
					int nCmdShow)				
{										
	MSG			msg;

	try
	{
		// Create the main window
		CreateWin32Window(hInstance, 340, 260);

		// Create the main menu
		CreateMainMenu(hWnd);

		// Create controls
		CreateControls(hWnd, hInstance);
	}
	catch (std::exception &e)
	{
		MessageBox(NULL, e.what(), "ERROR", MB_OK | MB_IConerror);
		return EXIT_FAILURE;
	}

	// The window is initially hidden, we need to show it
	ShowWindow(hWnd, SW_SHOW);	

	// The main message loop of our program 
	while(running)								
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))	
		{
			TranslateMessage(&msg);			
			DispatchMessage(&msg);			
		}
	}

	return msg.wParam;
}

/* 
 * Creates a Win32 window 
 */
void CreateWin32Window(HINSTANCE hInstance, int width, int height)
{
	WNDCLASSEX	WndEx;

	WndEx.cbSize			= sizeof(WNDCLASSEX);
	WndEx.style				= CS_HREDRAW | CS_VREDRAW;
	WndEx.lpfnWndProc		= (WNDPROC) WndProc;
	WndEx.cbClsExtra		= 0;
	WndEx.cbWndExtra		= 0;
	WndEx.hIcon				= LoadIcon(NULL, IDI_WINLOGO);
	WndEx.hCursor			= LoadCursor(NULL, IDC_ARROW);
	WndEx.hbrBackground		= (HBRUSH)GetStockObject(WHITE_BRUSH); 
	WndEx.lpszMenuName		= NULL;
	WndEx.lpszClassName		= clsName;
	WndEx.hInstance			= hInstance;
	WndEx.hIconSm			= LoadIcon(NULL, IDI_APPLICATION);

	// Register the windows class
	if (!RegisterClassEx(&WndEx))
	{
		throw std::exception("Window creation error: RegisterClassEx failed");
	}

	// Create the window
	if (!(hWnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
								clsName,							
								title,								
								WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | 
								WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,				
								CW_USEDEFAULT, CW_USEDEFAULT,		
								width, height,							
								NULL,							
								NULL,								
								hInstance,							
								NULL)))								
	{	
		throw std::exception("Window creation error: CreateWindowEx failed");
	}
}

/* 
 * Callback procedure to handle messages sent by the main window.
 */
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)									
	{
		case WM_CLOSE:	
			DestroyWindow(hWnd);
			return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
			running = false;
			return 0;

		case WM_COMMAND:											
		{
			// The low word of wParam contains the menu ID. 
			switch(LOWORD(wParam))
			{  
				case IDC_FILE_EXIT:
					PostQuitMessage(0);
					running = false;
					break;

				case IDC_BUTTON_SHOW_MSG:
					SetWindowText(GetDlgItem(hWnd, IDC_EDIT_CTRL), NULL);
					SetWindowText(hWnd, "Windows API");			
					MessageBox(hWnd, "Title reset", "Message", MB_ICONINFORMATION); 
					break;
			}

			// Has the user changed the text in the edit control?
			if (HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == IDC_EDIT_CTRL)
			{
				static char text[256];
				GetWindowText(GetDlgItem(hWnd, IDC_EDIT_CTRL), (LPSTR)text, 256);
				SetWindowText(hWnd, (LPSTR)text);
			}

		} break;

		// Make static and button control Bkgd transparent
		case WM_CTLCOLORBTN:
		case WM_CTLCOLORSTATIC:
		{
			SetBkMode((HDC)wParam, TRANSPARENT); 
			return (INT_PTR)(HBRUSH)GetStockObject(WHITE_BRUSH);
		} break;

		default:
			return DefWindowProc(hWnd,uMsg,wParam,lParam);
	}
}



Creating the window
The window is created in a function called CreateWin32Window, which takes the HINSTANCE passed into WinMain and the width and height that we want our window to be. Inside of CreateWin32Window, things should look pretty familar, but the style of the window has been changed to make sure the user cannot resize it. Exception handling has also been added for good practice.

Creating the controls
The function CreateControls deals with the creation of all the controls which are present in the window, this function takes a Handle to the parents window (HWND) and an instance of the application (HISTANCE). The controls themselves are created using CreateWindow.

The first parameter of CreateWindow is a string containing the class name of the control we want to create, this basically describes the type of control that we want to use. For example, "Static" specifies a text control, and "Button" specifies a button control.

The second parameter is the title, but this may or may not be applicable, for example, a button may have a title, but an edit box does not.

The HMENU parameter specifies the ID of this control, we can use this for many purposes, such as getting a handle to the control, or catching messages it sends to the message loop.

CreateWindow also returns a handle to the created control, which is being assigned to a variable in this case.

In CreateControls, a font is specified for some of the controls. This is easy to do using CreateFont and is pretty self explanitory. Note that to assign the font to a control, a WM_SETFONT message is sent containing a HFONT in the WPARAM.

Intercepting the messages sent by the controls
In our message loop, you will notice a case for the IDC_BUTTON_SHOW_MSG ID. This message is sent when the user clicks out button, in which case we then reset the title of the window.

You may also notice the following code.

if (HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == IDC_EDIT_CTRL)


The purpose of this is to detect when a change has occured to the edit box, that is, the user has changed the text it contains. We react to this by simply grabbing the text from the text box and setting it to the title main window.

The WM_CTLCOLORBTN and WM_CTLCOLORSTATIC cases are for ensuring that our controls have a transparent background, so they don't stick out like a sore thumb.

Wrapping it up
This has been a pretty short tutorial, but there's not much more to say that hasen't already been said in the other tutorials.

Thanks for reading

Is This A Good Question/Topic? 6
  • +

Replies To: Intro to the Windows API Part 3: Creating and using controls

#2 souldeep  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 20-April 11

Posted 20 April 2011 - 09:26 AM

Thank you for this very well done tutorial.
Was This Post Helpful? 0
  • +
  • -

#3 Aphex19  Icon User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 615
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Posted 12 May 2011 - 08:17 AM

View Postsouldeep, on 20 April 2011 - 10:26 AM, said:

Thank you for this very well done tutorial.


You're welcome, I'm happy to hear it.
Was This Post Helpful? 0
  • +
  • -

#4 nifleheim13  Icon User is online

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 40
  • Joined: 28-February 11

Posted 10 June 2011 - 12:18 AM

i'm currently looking for a tutorial on how to use the WinAPI on c++.....and i saw your tutorial from part 1 to 3, thanks....going to use it as a reference....
Was This Post Helpful? 0
  • +
  • -

#5 Heskel  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 02-July 11

Posted 02 July 2011 - 02:23 PM

This is a great tutorial, just what i needed to get started.Thanks a lot Aphex19.
Was This Post Helpful? 0
  • +
  • -

#6 Jimbo7136  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 33
  • Joined: 01-July 12

Posted 22 July 2012 - 05:30 PM

Thanks very much for making this tutorial.

I was hoping someone would continue down the intro to win32 road, I've been following several basic win32 tutorials and last time I was looking for a tutorial on controls there wasn't one yet, so thanks and kudos to you.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1