Click here to Skip to main content
15,884,898 members
Articles / Desktop Programming / WTL
Article

C++ Header Guard

Rate me:
Please Sign up or sign in to vote.
3.83/5 (9 votes)
17 Mar 2009CPOL2 min read 51.3K   238   12   16
Create unique preprocessor macros to prevent multiple header inclusion.
screenshot.png

Introduction

This article is a rework of the idea from an existing article but with the focus on usability and ease of use.

This utility creates unique preprocessor macros to prevent multiple header inclusion. If a filename is specified as a command line argument or a file is dropped onto the dialog, it's name is also included in the macro.

The dialog stays "always on top," accepts dropped shortcuts, snaps to screen edges and can be dragged by its surface. Upon entering a key/OK button, the displayed macro is copied to the clipboard, and the program exits.

Usage

The program is designed to be used from inside VC 2005/2008 IDE to generate a unique macro for the currently opened file:

menu2.png

menu.png

The Code

A unique macro is generated from GUID:

C++
CString CIncludeGen::CreateGuid()
{
	TCHAR fmtGuid[] = _T("%08lx_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x");
	GUID guid;
	CoCreateGuid(&guid);

	CString str;
	str.Format(fmtGuid, guid.Data1,guid.Data2,guid.Data3,
			guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
			guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
	str.MakeUpper();
	return str;
}

When sending the text to a clipboard, it is necessary to use the HWND of the dialog in OpenClipboard, as stated in MSDN:

"If an application calls OpenClipboard with hwnd set to NULL, EmptyClipboard sets the clipboard owner to NULL; this causes SetClipboardData to fail."

C++
bool CIncludeGen::copy2clipboard(HWND clipbrdowner)
{
	if (m_text.IsEmpty()) return false;
	
	bool retVal=true;
	if(::OpenClipboard(clipbrdowner))
	{
		
		LPTSTR lptstrCopy;
		LPCTSTR txt=m_text;
		HGLOBAL hglbCopy;
		
		::EmptyClipboard();
		
		hglbCopy = GlobalAlloc(GMEM_MOVEABLE,
                      (m_text.GetLength() + 1) * sizeof(TCHAR));
		if (hglbCopy != NULL)
		{
			lptstrCopy = (LPTSTR)GlobalLock(hglbCopy);
		
			memcpy(lptstrCopy, txt, 
                               (m_text.GetLength() * sizeof(TCHAR))); 
			lptstrCopy[m_text.GetLength()] = (TCHAR) 0; // null character 
			GlobalUnlock(hglbCopy); 
	
		if (NULL==::SetClipboardData(CF_UNICODETEXT,
                     hglbCopy)) MessageBeep(-1);
		}
		else retVal=false;
	
		::CloseClipboard();
		}
	else retVal=false;
return retVal;
}

The font for the edit control is created by retrieving the info about current default font and modifying its properties. The edit control is read-only, so the default background color (white) is restored by handling the WM_CTLCOLORSTATIC message:

C++
bool CMainDlg::createEditCtlFont()
{
	m_editCtlFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
	if (m_editCtlFont.IsNull()) return false;
	LOGFONT lfont={0};
	if (0==GetObject(m_editCtlFont,sizeof(LOGFONT), &lfont)) return false;
	if (IsClearTypeEnabled()) lfont.lfQuality=CLEARTYPE_QUALITY;

	lfont.lfPitchAndFamily=FIXED_PITCH | FF_MODERN;
	WCHAR fn[32]=L"Courier New";
	lfont.lfHeight=(LONG)(lfont.lfHeight*1.15);//increase size a bit

	memcpy(lfont.lfFaceName, fn, _countof(fn));
	m_editCtlFont.DeleteObject();
	if (NULL==m_editCtlFont.CreateFontIndirect(&lfont)) return false;
return true;
}

...

LRESULT CMainDlg::OnCtlColor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	if (((HWND)lParam)==GetDlgItem( IDC_EDIT1 )) return (LRESULT)GetStockObject(
             WHITE_BRUSH );
return ::DefWindowProc(m_hWnd, wParam, lParam, bHandled);
}

The dialog background color is changed by handling WM_CTLCOLORDLG and returning previously created brush of desired color:

C++
#define INCLHG_DLG_BKGCOLOR RGB(198,209,223)
...
CMainDlg::CMainDlg()
{
	m_dialogbrush.CreateSolidBrush(INCLHG_DLG_BKGCOLOR);...
LRESULT CMainDlg::OnMainDialogColor(UINT uMsg, WPARAM wParam, LPARAM lParam,
    BOOL& bHandled)
{
return (LRESULT)m_dialogbrush.m_hBrush;
}

The focus in the dialog form has the OK button, set by calling GotoDlgCtrl(GetDlgItem(IDOK)) and returning FALSE in CMainDlg::OnInitDialog.

Dropped shortcuts are resolved using the function assembled by Igor Vigdorchik. I will leave other features in the code as a readers' exercise.

The project is built with VC 2008 Express, Windows SDK 6.1, WTL 8.0 and ATL 3.0 from Platform SDK R2.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Croatia Croatia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralVery nice idea Pin
John R. Shaw23-Mar-09 15:21
John R. Shaw23-Mar-09 15:21 
GeneralJust what I was looking for... Pin
Loreia18-Mar-09 5:30
Loreia18-Mar-09 5:30 
GeneralMy vote of 2 Pin
RChin17-Mar-09 14:31
RChin17-Mar-09 14:31 
GeneralMy vote of 1 Pin
wanft17-Mar-09 11:22
wanft17-Mar-09 11:22 
GeneralRe: My vote of 1 [modified] Pin
Emilio Garavaglia17-Mar-09 22:02
Emilio Garavaglia17-Mar-09 22:02 
AnswerRe: My vote of 1 Pin
T800G18-Mar-09 5:35
T800G18-Mar-09 5:35 
GeneralRe: My vote of 1 Pin
Rick York18-Mar-09 8:24
mveRick York18-Mar-09 8:24 
GeneralRe: My vote of 1 Pin
Emilio Garavaglia18-Mar-09 23:30
Emilio Garavaglia18-Mar-09 23:30 
Rick York wrote:
#ifndef _HEADERFILE_H
#define _HEADERFILE_H
#else
#error repeated include of this file
#endif


Interesting ... but there could be a drawback:
You're writing a module that does some string manipulatione, hence you

#include <string>

Then (two months later) you write a module that parse some data from strings, hence you

#include <sstream>

Then (six month later) you are mangling a project that uses both of the modules.
Now: if the STL implementation has <sstream> and <string> written with your style and - incidentally - <sstream>includes <string> you get errors about the order in inclusion of your headers, even if they are logically independent because of a dependency in the STL you're using (and that may be not in control by you).

So, I'm not so shure that generating an error in case of multi-inclusion is a good solution for the problem.

Also, when using third party code, I'm even not so sure that relying on third party guards to take actions is good (and this also is a drawback for my previous post).
Many sources, in fact, have guards, but don't document such guards as "exposed APIs", so you cannot know if they will never be changed across versions.
The risk is to introduce dependencies on things that are not controllable.

Of course, all this does not apply if all the headers we are talking about are part of a same homogeneous set, deployed as part of a same delivery plan.


2 bugs found.
> recompile ...
65534 bugs found.
D'Oh! | :doh:




GeneralRe: My vote of 1 Pin
Rick York19-Mar-09 7:33
mveRick York19-Mar-09 7:33 
GeneralRe: My vote of 1 Pin
Goran Mitrovic18-Mar-09 9:53
Goran Mitrovic18-Mar-09 9:53 
Question#pragma once? Pin
Steve Maier17-Mar-09 11:08
professionalSteve Maier17-Mar-09 11:08 
AnswerRe: #pragma once? Pin
xliqz17-Mar-09 13:22
xliqz17-Mar-09 13:22 
GeneralRe: #pragma once? Pin
snapshot_a17-Mar-09 13:40
snapshot_a17-Mar-09 13:40 
GeneralRe: #pragma once? Pin
kenneth nielsen17-Mar-09 13:57
kenneth nielsen17-Mar-09 13:57 
GeneralRe: #pragma once? Pin
jonnybgood217-Mar-09 14:32
jonnybgood217-Mar-09 14:32 
GeneralRe: #pragma once? Pin
T800G18-Mar-09 5:41
T800G18-Mar-09 5:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.