Skip to content

Instantly share code, notes, and snippets.

@alf-p-steinbach
Last active May 27, 2020 07:52
Show Gist options
  • Save alf-p-steinbach/af5805d6bfd0f70ab1ed518286179c0d to your computer and use it in GitHub Desktop.
Save alf-p-steinbach/af5805d6bfd0f70ab1ed518286179c0d to your computer and use it in GitHub Desktop.
Demo of Windows API level coding
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity type="win32" name="Demo of Windows API level coding" version="1.0.0.0"/>
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings"
>UTF-8</activeCodePage>
</windowsSettings>
</application>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
// Source encoding: UTF-8 with BOM (π is a lowercase Greek "pi").
//----------------------------------- <windows.h> include. Put this in a separate header.
#ifdef UNICODE
# error "This app is UTF-8. Don't define UNICODE."
#endif
#define STRICT
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN // Reduces header size 50%, also fixes winsock2.
#include <windows.h> // Main include.
#include <windowsx.h> // Message cracker macros + utility wrapper macros.
#include <commctrl.h> // InitCommonControlsEx
//---------------------------------------------------------------------------------------
#include <stdint.h> // uintptr_t
#include <stdlib.h> // EXIT_...
#include <string> // std::string
#include <stdexcept> // std::(runtime_error, exception)
#define FAIL( s ) cppx::fail( std::string() + __func__ + " - " + s )
#define WITH( decl ) if( auto&& [[maybe_unused]] _ = decl; false ) {} else
#include <iostream> //!DEBUG
using std::clog;
namespace cppx {
using std::runtime_error, std::string;
using C_str = const char*;
auto hopefully( const bool e ) -> bool { return e; }
auto fail( const string& s ) -> bool { throw runtime_error( s ); }
} // namespace cppx
namespace winapi_util {
using cppx::C_str, cppx::hopefully, cppx::fail;
using std::string;
inline auto create_default_font()
-> HFONT
{
// See <url: https://stackoverflow.com/a/6057761/464581>
// Get the system message box font information.
NONCLIENTMETRICS ncm = { sizeof( ncm ) };
::SystemParametersInfo( SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0 );
// Create a corresponding font.
const HFONT result = ::CreateFontIndirect( &ncm.lfMessageFont );
hopefully( result != 0 )
or FAIL( "CreateFontIndirect failed" );
return result;
}
inline auto the_default_gui_font()
-> HFONT
{
static const HFONT the_font = create_default_font();
return the_font;
}
auto create_control(
const HWND parent,
const int id,
const C_str windowclass_name,
const POINT position,
const SIZE size,
const C_str text = "",
const DWORD additional_styles = 0
) -> HWND
{
const HWND handle = ::CreateWindow(
windowclass_name,
text,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | additional_styles,
position.x, position.y, size.cx, size.cy,
parent, // parent
reinterpret_cast<HMENU>( static_cast<uintptr_t>( id ) ),
::GetModuleHandle( nullptr ),
nullptr // custom params
);
hopefully( handle != 0 )
or FAIL( "CreateWindow failed" );
SetWindowFont( handle, the_default_gui_font(), false ); // <windowsx.h> macro
return handle;
}
auto text_of( const HWND window )
-> string
{
const int n_chars = GetWindowTextLength( window );
if( n_chars == 0 ) {
return "";
}
string result( n_chars + 1, '\0' );
::GetWindowText( window, &result[0], int( result.size() ) );
result.resize( n_chars ); // Remove trialing zero-byte.
return result;
}
auto text_of_item( const HWND window, const int item_id )
-> string
{
const HWND item = ::GetDlgItem( window, item_id );
hopefully( item != 0 )
or FAIL( "GetDlgItem failed" );
return text_of( item );
}
namespace common_controls {
struct Usage
{
Usage()
{
INITCOMMONCONTROLSEX params = { sizeof( params ) };
params.dwICC = ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
::InitCommonControlsEx( &params )
or FAIL( "InitCommonControlsEx failed" );
}
};
}
} // winapi_util
namespace app {
using cppx::hopefully, cppx::fail;
using winapi_util::text_of_item;
namespace main_window
{
using std::string;
using winapi_util::create_control;
const auto& windowclass_name = "Main window";
namespace cmd_id {
const int generate = 101;
} // namespace cmd_id
namespace control_id {
const int name_edit = 1001;
const int age_edit = 1002;
const int result_edit = 1003;
} // namespace control_id
void on_cmd_generate( const HWND window )
{
const string name = text_of_item( window, control_id::name_edit );
const string age = text_of_item( window, control_id::age_edit );
const string text = name + " is " + age + " years old";
clog << "Setting text \"" + text + "\"\n";
::SetDlgItemText( window, control_id::result_edit, text.c_str() );
}
void on_command( const HWND window, const int id )
{
clog << "on_command " << id << "\n";
switch( id ) {
case IDOK:
case cmd_id::generate: return on_cmd_generate( window );
}
}
void on_wm_close( const HWND window )
{
::DestroyWindow( window );
}
void on_wm_command(
const HWND window,
const int command_id,
const HWND control,
const UINT notification_code
)
{
(void) control;
if( notification_code > 1 ) {
// Handle notification messages. E.g. each edit keypress sends execution here.
} else {
on_command( window, command_id );
}
}
auto on_wm_create( const HWND window, CREATESTRUCT* )
-> bool
{
create_control( window, 0, "STATIC", {100, 50}, {98, 38}, "Name:" );
create_control( window, control_id::name_edit, "EDIT", {200, 50}, {98, 38}, "", WS_BORDER | WS_TABSTOP );
create_control( window, 0, "STATIC", {100, 90}, {98, 38}, "Age:" );
create_control( window, control_id::age_edit, "EDIT", {200, 90}, {98, 38}, "", WS_BORDER | WS_TABSTOP );
create_control( window, cmd_id::generate, "BUTTON", {150, 140}, {98, 38}, "Generate", BS_DEFPUSHBUTTON | WS_TABSTOP );
const HWND x = create_control( window, control_id::result_edit, "EDIT", {100, 200}, {300, 200} );
::EnableWindow( x, false );
return true;
}
void on_wm_destroy( const HWND window )
{
(void) window;
::PostQuitMessage( EXIT_SUCCESS );
}
auto WINAPI message_handler(
const HWND window,
const UINT message_id,
const WPARAM word_param,
const LPARAM long_param
) -> LRESULT
{
#define HANDLE_WM( name, func ) HANDLE_WM_##name( window, word_param, long_param, func )
switch( message_id ) {
case WM_CLOSE: return HANDLE_WM( CLOSE, on_wm_close );
case WM_COMMAND: return HANDLE_WM( COMMAND, on_wm_command );
case WM_CREATE: return HANDLE_WM( CREATE, on_wm_create );
case WM_DESTROY: return HANDLE_WM( DESTROY, on_wm_destroy );
}
return ::DefDlgProc( window, message_id, word_param, long_param );
#undef HANDLE_WM
}
void register_windowclass()
{
WNDCLASS params = {};
params.style = CS_DBLCLKS;
params.lpfnWndProc = &message_handler;
params.hInstance = ::GetModuleHandle( nullptr );
params.hIcon = ::LoadIcon( 0, IDI_APPLICATION );
params.hCursor = ::LoadCursor( 0, IDC_ARROW );
params.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_3DFACE + 1 );
params.lpszClassName = windowclass_name;
params.cbWndExtra = DLGWINDOWEXTRA; // To be able to use DefDlgProc.
clog << "Calling RegisterClass\n";
const ATOM result = ::RegisterClass( &params );
hopefully( result != 0 )
or FAIL( "RegisterClass failed" );
clog << "RegisterClass succeeded\n";
}
auto create()
-> HWND
{
clog << "Calling CreateWindow\n";
const HWND handle = ::CreateWindow(
windowclass_name,
"Demo of Windows API level coding",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 400,
HWND(), // parent
HMENU(),
GetModuleHandle( nullptr ),
nullptr // custom params
);
hopefully( handle != 0 )
or FAIL( "CreateWindow failed" );
clog << "CreateWindow succeeded\n";
return handle;
}
} // namespace main_window
void process_messages_for( const HWND window )
{
MSG m;
while( ::GetMessage( &m, 0, 0, 0 ) > 0 ) {
const bool processed = ::IsDialogMessage( window, &m );
if( not processed ) {
::TranslateMessage( &m );
::DispatchMessage( &m );
}
}
hopefully( m.message == WM_QUIT )
or FAIL( "GetMessage failed" );
}
void run()
{
WITH( winapi_util::common_controls::Usage() ) {
main_window::register_windowclass();
const HWND window = main_window::create();
::ShowWindow( window, SW_SHOWDEFAULT );
process_messages_for( window );
}
}
} // namespace app
auto main()
-> int
{
using std::exception;
using std::cerr;
clog << "Starting.\n";
try {
app::run();
clog << "Finished.\n";
return EXIT_SUCCESS;
} catch( const exception& x ) {
::MessageBox( 0, x.what(), "Oops", MB_ICONERROR | MB_SETFOREGROUND );
}
clog << "Finished.\n";
return EXIT_FAILURE;
}
#include <windows.h>
1 RT_MANIFEST "app-manifest.xml"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment