Click here to Skip to main content
15,893,668 members
Articles / Programming Languages / C++

Writing Win32 Apps with C++: V2 - part 1

Rate me:
Please Sign up or sign in to vote.
4.70/5 (34 votes)
20 Jun 2005CPOL14 min read 107.9K   1.2K   73  
An independent framework to handle Win32 objects inside C++ classes.
//winmain.h winmain services
#pragma once

namespace GE_{ namespace win{

	//some important Global stores

	inline HINSTANCE& hInst() {static  HINSTANCE h=NULL; return h; }
	inline HWND& hMainWnd() {static  HWND h=NULL; return h; }
	
	//Messageloop for WinMain,
	// instatiate on stach, an call "run('mainwindow')"
	class Messageloop
	{
	private:
		static Messageloop*& _mainloop() { static Messageloop* m= NULL; return m;}
		LRESULT lastresult;
	public:
		static Messageloop& get() { return *_mainloop(); }
	public:
		struct idle_event_type: public stdx1::event_source {} idle_event;
		struct message_event_type: 
			public stdx1::event_source  
		{
			MSG* pmsg;
		};
		message_event_type message_event;

		bool is_idlemessage(UINT msg)
		{
			// These messages should NOT cause idle processing
			switch(msg)
			{
			case WM_NCMOUSEMOVE:
			case WM_MOUSEMOVE:
			case WM_PAINT:
			case 0x0118:	// WM_SYSTIMER (caret blink) [WTL suggestion ...]
				return false;
			}
			return true;
		}

		LRESULT result() { return lastresult; }

		//declares and initialize a Messageloop
		Messageloop(HINSTANCE _hInst)
		{
			if(!_mainloop()) _mainloop() = this;
			if(!hInst()) hInst() = _hInst;
			lastresult = 0;
		}

		//the loop body
		bool body()
		{
			//the message loop body
			MSG msg;
			if(GetMessage(&msg, 0, 0,0) == -1)
				return false; //invalid call
			if(msg.message == WM_QUIT)
			{
				idle_event.fire(idle_event); //just if having pendings ...
				return false;
			}
			message_event.pmsg = &msg;
			if(message_event.fire(message_event))
				return true; //message filtered from outside
			TranslateMessage(&msg);
			lastresult = DispatchMessage(&msg);
			if(!PeekMessage(&msg, 0, 0,0, PM_NOREMOVE) && is_idlemessage(msg.message))
				idle_event.fire(idle_event);
			return true;
		}
		
		//a externally controllable loop
		bool loopwhile(bool& b)
		{
			while(b && body()) {}
			return b;
		}

		//an only internally controlled loop
		void run(HWND _hwnd)
		{
			if(!hMainWnd() && _hwnd) hMainWnd() = _hwnd;
			bool b = true;
			loopwhile(b);
		}

	};


	//a RefcountableValue with destroy policy
	template<class H, class DeletePolicy, H nullval=NULL>
	class RefcountableW32Handle: public stdx1::RefcountableValue<H,nullval>
	{
	protected:
		virtual void on_lastrelease() { DeletePolicy(*this); }
	};


	//Resource ID UINT and STRING converter
	class ResID
	{
	private:
		LPCTSTR resID;
	public:
		ResID() { resID = 0; }
		ResID(LPCTSTR _resID) { resID = _resID; }
		ResID(UINT _resID) { resID = MAKEINTRESOURCE(_resID); }
		operator LPCTSTR() const { return resID; }
	};

	
	//WNDCLASS registrations helpers
	class _WndClassEx:
		public stdx1::HandableRefcounter<stdx1::RefcountableValue<ATOM> >
	{
	private:
		HINSTANCE hRegInstance;

		virtual void on_lastrelease() 
		{	
			UnregisterClass((LPCTSTR)(ATOM)*this, hRegInstance);
			STRACE(trc, 3, ("Unregistered class with ATOM %x\n", (ATOM)*this));
		}

	public:
		void Register(
			HINSTANCE hInst,
			LPCTSTR clsName,
			ResID resID, 
			int nBkgSysColorIdx=COLOR_WINDOW, 
			WNDPROC pfnDefWndProc= DefWindowProc, 
			DWORD dwStyle = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS
			)
		{
			WNDCLASSEX wc;
			wc.cbSize = sizeof(WNDCLASSEX);
			wc.style = dwStyle;
			wc.lpfnWndProc = pfnDefWndProc;
			wc.cbClsExtra = wc.cbWndExtra = 0;
			wc.hInstance = hInst;
			wc.hIcon = (HICON)LoadImage(wc.hInstance, resID, IMAGE_ICON, 0,0, LR_DEFAULTSIZE);
			wc.hIconSm = (HICON)LoadImage(wc.hInstance, resID, IMAGE_ICON, 16,16, LR_DEFAULTCOLOR);
			wc.hCursor = LoadCursor(wc.hInstance, resID); if(!wc.hCursor) wc.hCursor = LoadCursor(NULL, IDC_ARROW);
			wc.hbrBackground = (nBkgSysColorIdx==-1)? NULL: GetSysColorBrush(nBkgSysColorIdx);
			wc.lpszMenuName = NULL;
			wc.lpszClassName = clsName;

			_set(RegisterClassEx(&wc));
			STRACE(trc,3,("Registering class %s, ATOM %x\n", clsName, (ATOM)*this));
			hRegInstance = hInst;
		}

		void Register(
			HINSTANCE hInst,
			LPCTSTR clsName,			//the name for the class (will autogenerate)
			HICON HIcon = (HICON)-1,	//IDI_APPLICATION
			HCURSOR HCursor = (HCURSOR)-1, //IDC_CURSOR
			int nBkgSysColorIdx = COLOR_WINDOW,	// the background brush index: -1 means no backround
			WNDPROC pfnDefWndProc = DefWindowProc,// the window procedure to subclass: DefWndProc , DefDialogProc etc... 
			DWORD dwStyle = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS //class style
			)
		{
			WNDCLASSEX wc;
			wc.cbSize = sizeof(WNDCLASSEX);
			wc.style = dwStyle;
			wc.lpfnWndProc = pfnDefWndProc;
			wc.cbClsExtra = wc.cbWndExtra = 0;
			wc.hInstance = hInst;
			wc.hIcon = (HIcon==(HICON)-1)? LoadIcon(NULL, IDI_APPLICATION): HIcon;
			wc.hIconSm = NULL;
			wc.hCursor = (HCursor==(HCURSOR)-1)? LoadCursor(NULL, IDC_ARROW): HCursor;
			wc.hbrBackground = (nBkgSysColorIdx==-1)? NULL: GetSysColorBrush(nBkgSysColorIdx);
			wc.lpszMenuName = NULL;
			wc.lpszClassName = clsName;

			_set(RegisterClassEx(&wc));
			STRACE(trc,3,("Registering class %s, ATOM %x\n", clsName, (ATOM)*this));
			hRegInstance = hInst;
		}

		operator LPCTSTR() const { return (LPCTSTR)(ATOM)*this; }

	};

	typedef stdx1::Handle<_WndClassEx> Wndclassex;


	//provides delayed delete to a derived object.
	//	deletion takes place on the next idle event fired by the message loop
	class delete_onidle:
		public stdx1::event_handler<Messageloop::idle_event_type>
	{
	private:
		bool bDelete;
	protected:
		delete_onidle() { bDelete = false; }
		virtual ~delete_onidle() {}

		virtual bool on_event(const Messageloop::idle_event_type& ie, stdx1::event_source::state* pState)
		{
			pState->do_next();
			if(bDelete)
			{
				delete this;
			}
			return true;
		}

	public:
		
		void post_delete()
		{
			bDelete = true;
			Hook(Messageloop::get().idle_event);
		}
	};


}}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Architect
Italy Italy
Born and living in Milan (Italy), I'm an engineer in electronics actually working in the ICT department of an important oil/gas & energy company as responsible for planning and engineering of ICT infrastructures.
Interested in programming since the '70s, today I still define architectures for the ICT, deploying dedicated specific client application for engineering purposes, working with C++, MFC, STL, and recently also C# and D.

Comments and Discussions