PROWAREtech

articles » current » windows » application-programming-interface » hello-c-plus-plus

Windows API: Hello C++

A basic Windows API program example; written in C++.

See related: Windows API Example in C

The following is a good example of how to integrate C++ into a Windows API application. The key to making the addition of C++ to a Windows API program work is in using SetWindowLongPtrW() and GetWindowLongPtrW() to set and get the pointer to the app's class object.

// *******************************************************************
// *                                                                 *
// *  Example C++ Windows App                                        *
// *                                                                 *
// *******************************************************************


#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>


class ExampleCppWinApp
{
	HWND m_hwnd;
	HINSTANCE m_hInstance;

	HRESULT OnPaint(HDC hdc);
	BOOL OnClose();
	void OnResize(USHORT width, USHORT height);
	void ShowLastSystemError(LPCWSTR lpszFunction);

	static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

public:
	ExampleCppWinApp() : m_hwnd(NULL), m_hInstance(NULL) {}
	~ExampleCppWinApp() {}

	HRESULT Initialize(HINSTANCE hInstance);

	void RunMessageLoop();
};

//
// This is the application entry point.
//
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	if (SUCCEEDED(CoInitialize(NULL))) // Support for the "Component Object Model" is not needed here, but useful to have in many cases
	{

		// Application
		ExampleCppWinApp app;


		if (SUCCEEDED(app.Initialize(hInstance)))
			app.RunMessageLoop();

		CoUninitialize();
	}
	return 0;
}

//
// Creates the application window.
//
HRESULT ExampleCppWinApp::Initialize(HINSTANCE hInstance)
{
	HRESULT hr;

	// Register the window class.
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = ExampleCppWinApp::WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // must add 1 to make system colors into brushes
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = L"HelloWin";
	wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);


	if (!RegisterClassEx(&wcex))
	{
		ShowLastSystemError(L"RegisterClassEx");
		return E_FAIL;
	}

	// This is key to using C++ to create Windows Apps; lpParam == this
	m_hwnd = ::CreateWindowExW(0, wcex.lpszClassName, L"Hello Windows API World", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, this);
	hr = m_hwnd ? S_OK : E_FAIL;
	if (FAILED(hr))
		ShowLastSystemError(L"CreateWindow");
	else
	{
		m_hInstance = hInstance;
		ShowWindow(m_hwnd, SW_SHOWNORMAL);
		UpdateWindow(m_hwnd);
	}
	return hr;
}

//
// The main window message loop.
//
void ExampleCppWinApp::RunMessageLoop()
{
	MSG msg;

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

//
// Retrieve the system error message for the last-error code
//
void ExampleCppWinApp::ShowLastSystemError(LPCWSTR lpszFunction)
{

	LPVOID lpMsgBuf;

	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);

	MessageBox(GetActiveWindow(), (LPCTSTR)lpMsgBuf, lpszFunction, MB_OK);

	LocalFree(lpMsgBuf);
}


//
// Called whenever the application needs to display the client window.
//
HRESULT ExampleCppWinApp::OnPaint(HDC hdc)
{
	HRESULT hr = S_OK;
	RECT rect;

	GetClientRect(m_hwnd, &rect);
	SetBkMode(hdc, TRANSPARENT);

	DrawText(hdc, L"Hello C++ World!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

	return hr;
}

//
// If the application main window receives a WM_SIZE message...
//
void ExampleCppWinApp::OnResize(USHORT width, USHORT height)
{
}

BOOL ExampleCppWinApp::OnClose()
{
	return MessageBox(m_hwnd, L"Sure?", L"Confirm Close", MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES;
}

//
// The window message handler.
//
LRESULT CALLBACK ExampleCppWinApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	ExampleCppWinApp* pExampleCppWinApp;

	if (WM_CREATE == message)
	{
		LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
		pExampleCppWinApp = (ExampleCppWinApp*)pcs->lpCreateParams;

		// Set the window's user data to a pointer to the application.
		::SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)pExampleCppWinApp);

		return 0; // return -1 to cancel the creation of this window
	}
	else
	{
		// This is key to making this work with C++.
		pExampleCppWinApp = (ExampleCppWinApp*)(::GetWindowLongPtrW(hwnd, GWLP_USERDATA));

		if (pExampleCppWinApp)
		{
			switch (message)
			{
			case WM_CLOSE:
				if (pExampleCppWinApp->OnClose())
					DestroyWindow(hwnd);
				return 0;

			case WM_SIZE:
				pExampleCppWinApp->OnResize(LOWORD(lParam), HIWORD(lParam));
				return 0;

			case WM_DISPLAYCHANGE:
			case WM_PAINT:
			{
				PAINTSTRUCT ps;
				pExampleCppWinApp->OnPaint(BeginPaint(hwnd, &ps));
				EndPaint(hwnd, &ps);
			}
			return 0;

			case WM_DESTROY:
				PostQuitMessage(0);
				return 0;
			}
		}
		return DefWindowProc(hwnd, message, wParam, lParam);
	}
}

Here is an example of creating one C++ object per Window allowing the user to create multiple windows.

// *******************************************************************
// *                                                                 *
// *  Example C++ Multi-window Windows App                           *
// *                                                                 *
// *******************************************************************


#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

#define IDM_NEW 123
#define IDM_EXIT 124
LPCWSTR szAppName = L"HelloWin";

class ExampleCppWinApp
{
	HWND m_hwnd;
	HINSTANCE m_hInstance;

public:
	HRESULT OnPaint(HDC hdc);
	BOOL OnClose();
	void OnResize(USHORT width, USHORT height);
	void OnMenu(int command);

	ExampleCppWinApp(HWND hwnd, HINSTANCE hInst);
	~ExampleCppWinApp();
};

int window_count = 0;

ExampleCppWinApp::ExampleCppWinApp(HWND hwnd, HINSTANCE hInst) : m_hwnd(hwnd), m_hInstance(hInst)
{
	window_count++;

	if (HMENU hMenu = CreateMenu())
	{
		if (HMENU hSubMenu = CreatePopupMenu())
		{
			AppendMenu(hSubMenu, MF_STRING, (UINT_PTR)IDM_NEW, L"New");
			AppendMenu(hSubMenu, MF_MENUBARBREAK, NULL, NULL);
			AppendMenu(hSubMenu, MF_STRING, (UINT_PTR)IDM_EXIT, L"Exit");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hSubMenu, L"File");
		}
		SetMenu(hwnd, hMenu);
	}
}

ExampleCppWinApp::~ExampleCppWinApp()
{
	DestroyMenu(GetMenu(m_hwnd));

	window_count--;
}

//
// Retrieve the system error message for the last-error code
//
void ShowLastSystemError(LPCWSTR lpszFunction)
{

	LPVOID lpMsgBuf;

	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);

	MessageBox(NULL, (LPCTSTR)lpMsgBuf, lpszFunction, MB_OK);

	LocalFree(lpMsgBuf);
}

//
// This is the application entry point.
//
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	if (SUCCEEDED(CoInitialize(NULL))) // not needed, but useful to have in many cases
	{
		HRESULT hr;

		// Register the window class.
		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(NULL, IDI_APPLICATION);
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // must add 1 to make system colors brushes
		wcex.lpszMenuName = NULL;
		wcex.lpszClassName = szAppName;
		wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);


		if (!RegisterClassEx(&wcex))
		{
			ShowLastSystemError(L"RegisterClassEx");
			return E_FAIL;
		}

		HWND hwnd = ::CreateWindow(szAppName, L"Hello Windows API C++ World", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, 0);
		if (!hwnd)
			ShowLastSystemError(L"CreateWindow");
		else
		{
			ShowWindow(hwnd, SW_SHOWNORMAL);
			UpdateWindow(hwnd);

			MSG msg;

			// The main window message loop.
			while (GetMessage(&msg, NULL, 0, 0))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		CoUninitialize();
	}
	return 0;
}

//
// Called whenever the application needs to display the client window.
//
HRESULT ExampleCppWinApp::OnPaint(HDC hdc)
{
	HRESULT hr = S_OK;
	RECT rect;

	GetClientRect(m_hwnd, &rect);
	SetBkMode(hdc, TRANSPARENT);

	DrawText(hdc, L"Hello C++ World!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

	return hr;
}

//
// If the application main window receives a WM_SIZE message...
//
void ExampleCppWinApp::OnResize(USHORT width, USHORT height)
{
}

//
// If the application main window receives a WM_COMMAND message with HIWORD(wParam) == 0...
//
void ExampleCppWinApp::OnMenu(int command)
{
	if (IDM_NEW == command)
	{
		HWND hwnd = ::CreateWindow(szAppName, L"Hello Windows API C++ World", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, m_hInstance, 0);
		if (!hwnd)
			ShowLastSystemError(L"CreateWindow");
		else
		{
			ShowWindow(hwnd, SW_SHOWNORMAL);
			UpdateWindow(hwnd);
		}
	}
	else if (IDM_EXIT == command)
	{
		SendMessage(m_hwnd, WM_CLOSE, 0, 0);
	}
}

BOOL ExampleCppWinApp::OnClose()
{
	return MessageBox(m_hwnd, L"Sure?", L"Confirm Close", MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES;
}

//
// The window message handler.
//
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	ExampleCppWinApp* pExampleCppWinApp;

	if (WM_CREATE == message)
	{
		if (pExampleCppWinApp = new ExampleCppWinApp(hwnd, ((LPCREATESTRUCT)lParam)->hInstance))
		{
			// Set the window's user data to a pointer to the application object.
			::SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)pExampleCppWinApp);

			return 0;
		}
		return -1; // Out of Memory: return -1 to cancel the creation of this window
	}
	else
	{
		// This is key to making this work with C++ with the Windows API.
		if (pExampleCppWinApp = (ExampleCppWinApp*)(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)))
		{
			switch (message)
			{
			case WM_CLOSE:
				if (pExampleCppWinApp->OnClose())
				{
					// must delete object before calling DestroyWindow() because deconstructor decrements window_count.
					delete pExampleCppWinApp;

					DestroyWindow(hwnd);
				}
				return 0;

			case WM_SIZE:
				pExampleCppWinApp->OnResize(LOWORD(lParam), HIWORD(lParam));
				return 0;

			case WM_DISPLAYCHANGE:
			case WM_PAINT:
			{
				PAINTSTRUCT ps;
				pExampleCppWinApp->OnPaint(BeginPaint(hwnd, &ps));
				EndPaint(hwnd, &ps);
			}
			return 0;

			case WM_COMMAND:
				if (!HIWORD(wParam)) // then menu
					pExampleCppWinApp->OnMenu(LOWORD(wParam));
				return 0;

			case WM_DESTROY:
				if (!window_count)
					PostQuitMessage(0);
				return 0;
			}
		}
		return DefWindowProc(hwnd, message, wParam, lParam);
	}
}

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE