Click here to Skip to main content
Click here to Skip to main content

C++ Header Guard

By , 17 Mar 2009
 
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:

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."

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:

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:

#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)

About the Author

T800G
Software Developer
Croatia Croatia
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralVery nice ideamemberJohn R. Shaw23 Mar '09 - 15:21 
D'Oh! | :doh: I do not know why this generated any negative comments, since adding header guards to header files should be a natural as breathing to any C/C++ programmer. Generating unique guards is a logical approach, at least for very large projects; although I think I will still keep doing it the old way.
 
Still, good job! Smile | :)
 
INTP
"Program testing can be used to show the presence of bugs, but never to show their absence."Edsger Dijkstra

GeneralJust what I was looking for...memberloreia18 Mar '09 - 5:30 
...thanks man, I owe you one Thumbs Up | :thumbsup:
GeneralMy vote of 2memberRChin17 Mar '09 - 14:31 
I guess the code published gives us some insight into the GUID generation and clipboard usage; but the actual utility really is pointless.
GeneralMy vote of 1memberwanft17 Mar '09 - 11:22 
#pragma once solves the problem just fine
GeneralRe: My vote of 1 [modified]memberemilio_grv17 Mar '09 - 22:02 
#pragma once is today still "microsoft specific" and does not solve ALL the problem a guard can solve.
 
#pragma once grants a header is not included more than once but doesn't make any "signature" about the presence of a header.
 
If you need, in another header, to declare different things depending on the fact that a given header is wanted or not, you can only rely on gurds.
 
think to code like:
 

/// \file mywindow.h

///define an abstracrtioin for a "window"
/*! implementation is in mywindow.cpp */
class window
{
   struct blind_data; ///< declared and defined in mywindow.cpp
   blind_data* pdata; ///< create on contruct / delete on destruct
   window(const window&); ///< not implemented - not copyable
   window& operator=(const window&); ///< not impemented - not assignable
public:
   window(); ///<create the inner data - see mywindow.cpp
   ~window(); ///<create the inner data -see mywindow.cpp
 
   //whatever function you want to manipulate 
   //your window abstraction
 
#ifdef WIN32_INCLUDED
   operator HWND() const;
#endif
};
 
where WIN32_INCLUDED is in a file like
/// \file win32.h
#ifndef WIN32_INCLUDED
 
#include <windows.h>
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
 
#define WIN32_INCLUDED
#endif //WIN32_INCLUDED
 
And you main have
/// \file yourfile1.cpp
#include "mywindow.h"

/*
  your code here:
  it use window abstraction,
  but cannot use Windows native API
*/
and
/// \file yourfile2.cpp
#include "win32.h"
#include "mywindow.h"

/*
  your code here:
  it uses either window abstracction and
  Windws nativce APIs and can get a HWND for a window
  to pass to the native APIs.
*/

 

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

modified on Thursday, March 19, 2009 5:31 AM

AnswerRe: My vote of 1memberT800G18 Mar '09 - 5:35 
Thank you Emilio, I couldn't explain it better myself. Smile | :)
GeneralRe: My vote of 1memberRick York18 Mar '09 - 8:24 
emilio_grv wrote:
#ifndef WIN32_INCLUDED
#include "windows.h"
#define WIN32_INCLUDED
#endif //WIN32_INCLUDED

 
I work on fairly large scale projects with lots of libraries and I take an approach similar to this with all headers except I am probably a little more anal retentive about it. In all of the headers I write I do this :
 
// file HeaderFile.h
 
#ifndef _HEADERFILE_H
#define _HEADERFILE_H
#else
#error repeated include of this file
#endif
 
/***
#ifndef _HEADERFILE_H
#include "HeaderFile.h"
#endif
***/

 
With the little commented section there it becomes a simple matter to copy and past that to safely include the file in another header or in a code module.
 
As I said, this is rather anal retentive but the improvement in compile times are usually significant. I have seen huge speed ups on large projects when I went through all of the headers and changed them to this format. In my experience this really pays off with little to no added difficulty since I consider a copy and paste operation to be very simple.
GeneralRe: My vote of 1memberemilio_grv18 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 1memberRick York19 Mar '09 - 7:33 
Yes, there are potential issues but I have been doing this for many years and have not found a problem yet that could not be worked around easily.
 
In the case of headers at that level I nearly always include them in the stdafx.h file and then use the guard method that you mentioned previously about WIN32_INCLUDED to also include it if necessary in the modules that require it. The bottom line is I always put an external guard around including a header from within a header which is something I first noticed in some of the win32 SDK headers even though microsoft is very inconsistent about this practice. That is where the biggest compile time improvement comes from.
GeneralRe: My vote of 1memberGoran Mitrovic18 Mar '09 - 9:53 
Don't forget that #pragma once is an important compiling speed optimization because the file doesn't have to be preprocessed on second usage. This becomes important feature on large projects...
 
- Goran.

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 17 Mar 2009
Article Copyright 2009 by T800G
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid