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);
	}
}

PROWAREtech

Hello there! How can I help you today?
Ask any question

PROWAREtech

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.
ACCEPT REJECT