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