code-section

Win32 / C++ Tips and How-To's

April 02, 2014

Here I will be posting various how-to's and tips related to win32/C++ programming that I come up with or find that solve a particular problem that I face while working on various projects. I expect that I will update it whenever I come across something suitable for listing here.

If you have tips that you would like to share, or if you find mistakes/errors/bugs, leave a comment below.

Converting from a relative path to an absolute path

// sPath[out] receives the calculated absolute path.
// sFile[in] is the relative path/filename.
LPWSTR PathRelativeToAbsolute( LPTSTR sPath, LPCTSTR sFile )
{
	if( !PathIsRelative( sFile ) )
		return NULL;
	TCHAR curPath[ MAX_PATH ];
	GetCurrentDirectory( MAX_PATH, curPath );
	return PathCombine( sPath, curPath, sFile );
}


Checking if a Window is Fullscreen or Not

/// Tests whether a window is a fullscreen window or not.
inline BOOL IsWindowFullscreen( HWND hWnd )
{
	int screenWidth = GetSystemMetrics( SM_CXSCREEN );
	int screenHeight = GetSystemMetrics( SM_CYSCREEN );

	RECT rWindow;
	GetWindowRect( hWnd, &rWindow );

	return rWindow.left == 0 && rWindow.top == 0 &&
		rWindow.right == screenWidth && rWindow.bottom == screenHeight;
}


Shortcut: Modifying the Style of a Window

/// Sets and clears style flags for a particular window.
inline VOID ModifyWindowStyle( HWND hWnd, DWORD flagsToDisable, DWORD flagsToEnable )
{
	DWORD style = GetWindowLong( hWnd, GWL_STYLE );
	SetWindowLong( hWnd, GWL_STYLE, (style & ~flagsToDisable) | flagsToEnable );
}

/// Sets and clears extended style flags for a particular window.
inline VOID ModifyWindowExStyle( HWND hWnd, DWORD flagsToDisable, DWORD flagsToEnable )
{
	DWORD exStyle = GetWindowLong( hWnd, GWL_EXSTYLE );
	SetWindowLong( hWnd, GWL_EXSTYLE, (exStyle & ~flagsToDisable) | flagsToEnable );
}


Interpolating COLORREF Values

/// Linear interpolation between two COLORREF values.
inline COLORREF InterpolateCOLORREF( COLORREF c1, COLORREF c2, float t )
{
	INT r = (INT)LINEAR_INTERPOLATE( GetRValue(c1), GetRValue(c2), t );
	INT g = (INT)LINEAR_INTERPOLATE( GetGValue(c1), GetGValue(c2), t );
	INT b = (INT)LINEAR_INTERPOLATE( GetBValue(c1), GetBValue(c2), t );
	return RGB( CLAMP(r, 0, 255), CLAMP(g, 0, 255), CLAMP(b, 0, 255 ) );
}


Memory Alignment

/// Used for memory alignment. Returns the result of rounding 'n'
/// to the smallest multiple of 'boundary'.
inline INT Align( UINT n, UINT boundary )
{ if( !boundary ) return n; return ((n + boundary - 1) / boundary) * boundary; }

/// Align to DWORD boundaries. See Align().
inline INT DwordAlign(INT n) { return Align( n, sizeof(DWORD) ); }


Checking if a File Exists

/// Check whether a file exists or not.
inline BOOL FileExists(LPCTSTR szPath)
{
	//return PathFileExists( szPath ); //Requires shlwapi.h and shlwapi.lib
  DWORD dwAttrib = GetFileAttributes(szPath);

  return (dwAttrib != INVALID_FILE_ATTRIBUTES && 
         !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}


Temporarily Switching Cursors Using Objects

/// Temporary cursor class. Create an instance of this class to change the mouse cursor,
/// and when the instance goes out of scope, the original cursor is restored.
class CTempCursor
{
public:
	HCURSOR oldCursor;
	CTempCursor( LPCTSTR cursor ) { oldCursor = SetCursor( LoadCursor( NULL, cursor ) ); }
	~CTempCursor() { SetCursor( oldCursor ); }
};

/// Temporary busy cursor. Create an instace of this class at the beginning of
/// a lengthy operation (function) to display the busy cursor. When the instance
/// is destroyed, the original cursor is restored. See CTempCursor.
class CBusyCursor : public CTempCursor {
    public: CBusyCursor():CTempCursor(MAKEINTRESOURCE(IDC_WAIT)){} };


Temporarily Changing Current Directory Using Objects

/// A simple class to make it very easy to temporarily modify the current working directory.
/// Just instantiate an object of this class and give it the desired new path, and when
/// the object goes out of scope, it will restore the previous current directory.
class CTempCurrentDirectory
{
public:
	CTempCurrentDirectory( LPCSTR sNewDir )
	{
		m_sOldDir[0] = 0;
		GetCurrentDirectory( ARRAY_SIZE( m_sOldDir ), m_sOldDir );
		SetCurrentDirectoryA( sNewDir );
	}
	CTempCurrentDirectory( LPCWSTR sNewDir )
	{
		m_sOldDir[0] = 0;
		GetCurrentDirectory( ARRAY_SIZE( m_sOldDir ), m_sOldDir );
		SetCurrentDirectoryW( sNewDir );
	}
	~CTempCurrentDirectory() { SetCurrentDirectory( m_sOldDir ); }
	TCHAR m_sOldDir[ MAX_PATH ];
};


Using the Default GUI Font

If you need to draw text in your windows, you'll want it to look pretty. Well, you can use GetStockObject( DEFAULT_GUI_FONT ), but that returns an old ugly font, not the font actually used by Windows to draw GUI stuff. Here is how to get the font used by Windows (usually 'segoe' or 'segoe ui'):

/// Creates a font that is the same as that used by Windows for GUI elements.
inline HFONT CreateGuiFont()
{
	NONCLIENTMETRICS ncm;
	ncm.cbSize = sizeof(NONCLIENTMETRICS);
	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
	return CreateFontIndirect(&ncm.lfMessageFont);
}


Loading A Web Page Into A Buffer

Here is a simplified function that will load a url into a buffer.

#include <wininet.h>
/// Loads a web page into the specified buffer.
/// Returns TRUE on success, FALSE on failure (use GetLastError()).
inline BOOL LoadWebPage( LPCSTR sURL, CHAR* sBuffer, INT maxBuffer,
                        DWORD* pBytesRead = NULL )
{
	DWORD bytesRead;
	pBytesRead = pBytesRead ? pBytesRead : &bytesRead;
	*pBytesRead = 0;
	BOOL bSuccess = FALSE;

    HINTERNET hInternet = InternetOpen( TEXT("win32"),
        INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0 );
        
	if( hInternet )
	{
		HINTERNET hAddress = InternetOpenUrlA( hInternet, sURL, NULL, 0,
            INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0 );
            
		if( hAddress )
		{
			if( InternetReadFile( hAddress, sBuffer, maxBuffer, pBytesRead ) )
				bSuccess = TRUE;

			InternetCloseHandle( hAddress );
		}
		InternetCloseHandle( hInternet );
	}

	return bSuccess;
}


Win32 Simple Application Boilerplate

#include <windows.h>

HWND				g_hWnd = NULL;
HINSTANCE			g_hInstance = NULL;

LRESULT CALLBACK	WindowProc( HWND, UINT, WPARAM, LPARAM );


INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nShowCmd )
{
	g_hInstance = hInstance;

	WNDCLASSEX winClass;
	MSG        uMsg;

    memset(&uMsg,0,sizeof(uMsg));
    
	winClass.lpszClassName = TEXT("WC_SKEL_MAINWINDOW");
	winClass.cbSize        = sizeof(WNDCLASSEX);
	winClass.style         = CS_HREDRAW | CS_VREDRAW;
	winClass.lpfnWndProc   = WindowProc;
	winClass.hInstance     = hInstance;
	winClass.hIcon	       = NULL;
    winClass.hIconSm	   = NULL;
	winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	winClass.lpszMenuName  = NULL;
	winClass.cbClsExtra    = 0;
	winClass.cbWndExtra    = 0;

	if( !RegisterClassEx(&winClass) )
		return FALSE;


	RECT rWindow = { 0, 0, 1024, 768 };
	AdjustWindowRect( &rWindow, WS_OVERLAPPEDWINDOW, FALSE );

	g_hWnd = CreateWindowEx( NULL, winClass.lpszClassName,
                             TEXT("Win32 Boilerplate - code-section.com"),
						     WS_OVERLAPPEDWINDOW,
							 0, 0,
							 CW_USEDEFAULT, //rWindow.right - rWindow.left,
							 CW_USEDEFAULT, //rWindow.bottom - rWindow.top,
							 NULL, NULL, hInstance, NULL );

	if( g_hWnd == NULL )
		return FALSE;


    ShowWindow( g_hWnd, SW_SHOW );
    UpdateWindow( g_hWnd );

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

	UnregisterClass( winClass.lpszClassName, winClass.hInstance );

	return (INT)uMsg.wParam;
}


// The message procedure for the main window.
LRESULT CALLBACK WindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
	switch( Msg )
	{
	case WM_CLOSE:
		PostQuitMessage( 0 );
		break;
	}
	return DefWindowProc( hWnd, Msg, wParam, lParam );
}