MFC and ATL are part of WDK (in case you didn't know...)

In case you don't already know, a slightly outdated version of the Microsoft Foundation Class library (MFC) and Active Template Library (ATL) are included as part of Windows Driver Kit (WDK).

I have to admit that I hadn't realised until recently, thinking that you could only get these as part of a paid for copy of Visual Studio (that is, not the express editions).

Of course, you don't get the various wizards to help you manage your MFC and ATL projects, or a built-in resource editor, but it does allow you to implement programs using these libraries.

Of more interest (to me, at least) is that this opens up the possibility of using the Windows Template Library (WTL) -- which is built on top of ATL -- with Visual Studio express editions. If you like the Win32 API but would prefer to use classes, it is certainly worth a look.

Edit: I've added a small (?) example over the next three posts, so you can see what a basic WTL app looks like, for those of you who are interested.

Andy

Windows Template Library (WTL):
http://sourceforge.net/projects/wtl/

Using the Windows Template Library Part 1: Getting Started
http://www.gamedev.net/page/resources/_/technical/general-programming/using-the-windows-template-library-part-1-gett-r2042

Last edited on
Simple WTL app -- Part 1 of 3 : MainFrame

WTL apps have more boiler plate than old school Win32 apps, but easier to structure when things get less trivial.

This example has been stripped right down to create as near to a "hello" app as I could get. It could have been made a bit simpler if I'd left the text as small and black. I could have also replaced the FrameWindow/View pair with a single window, but the pair is what is used in most cases (when you have a toolbar, etc.)

A real WTL app would have:
- a resource segment
- a menu and toolbar
- an idle loop to handle menu and toolbar item greying
- etc.

I've also removed the COM initilization from WinMain as it's not needed here (it's usually part of the standard WTL WinMain).

Header file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once

// MainFrm.h

class CMainFrame
: public CFrameWindowImpl<CMainFrame>
, public CMessageFilter
{
public:
	DECLARE_FRAME_WND_CLASS(NULL, 0)

	CWTL_TestView m_view;

	virtual BOOL PreTranslateMessage(MSG* /*pMsg*/) { return FALSE; }

	BEGIN_MSG_MAP_EX(CMainFrame)
		MSG_WM_CREATE(OnCreate)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

	int OnCreate(LPCREATESTRUCT lpCreateStruct);
};


cpp file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// MainFrm.cpp

#include "stdafx.h"

#include "WTL_TestView.h"
#include "MainFrm.h"

int
CMainFrame::OnCreate(LPCREATESTRUCT /*lpCreateStruct*/)
{
	// in a proper WTL project, the window title is read from the resource file
	const TCHAR achWindowTitle[] = _T("Hello WTL");
	SetWindowText(achWindowTitle);

	DWORD dwStyle   = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	DWORD dwExStyle = WS_EX_CLIENTEDGE;

	m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, dwStyle, dwExStyle);

	return 0;
}

Last edited on
Simple WTL app -- Part 2 of 3 : View

Continued...

Header file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once

// WTL_TestView.h

class CWTL_TestView
: public CWindowImpl<CWTL_TestView>
{
public:
	DECLARE_WND_CLASS(NULL)

	BOOL PreTranslateMessage(MSG* /*pMsg*/) { return FALSE; }

	BEGIN_MSG_MAP_EX(CWTL_TestView)
		MSG_WM_PAINT(OnPaint)
	END_MSG_MAP()

	void OnPaint(CDCHandle dc);
};


cpp file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// WTL_TestView.cpp

#include "stdafx.h"

#include "WTL_TestView.h"

void
CWTL_TestView::OnPaint(CDCHandle /*dc*/)
{
	CPaintDC dc(m_hWnd);

	COLORREF crefRed = RGB(255, 0, 0);

	LOGFONT logFont = {0};
	logFont.lfHeight = 72;
	logFont.lfWeight = FW_BOLD;
	_tcscpy_s(logFont.lfFaceName, _T("Arial"));

	CFont font;
	font.CreateFontIndirect(&logFont);

	CRect rect;
	GetClientRect(rect);

	CAtlString strMessage = _T("Hello WTL!");
	UINT uFormat = DT_CENTER | DT_VCENTER | DT_SINGLELINE;

	COLORREF crefTextOld = dc.SetTextColor(crefRed);
	HFONT    hfontOld    = dc.SelectFont(font);

	dc.DrawText(strMessage, strMessage.GetLength(), rect, uFormat);

	dc.SetTextColor(crefTextOld);
	dc.SelectFont(hfontOld);
}
Last edited on
Simple WTL app -- Part 3 of 3 : WinMain and precompiled header

Continued till the end.

cpp file for WinMain:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// WTL_Test.cpp

#include "stdafx.h"

#include "WTL_TestView.h"
#include "MainFrm.h"

CAppModule _Module;

int
Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
	CMessageLoop theLoop;
	_Module.AddMessageLoop(&theLoop);

	CMainFrame wndMain;

	if(wndMain.CreateEx() == NULL)
	{
		ATLTRACE(_T("Main window creation failed!\n"));
		return 0;
	}

	wndMain.ShowWindow(nCmdShow);
	int nRet = theLoop.Run();
	_Module.RemoveMessageLoop();

	return nRet;
}

int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
	// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
	::DefWindowProc(NULL, 0, 0, 0L);

	HRESULT hRes = _Module.Init(NULL, hInstance);
	ATLASSERT(SUCCEEDED(hRes));

	int nRet = Run(lpstrCmdLine, nCmdShow);

	_Module.Term();

	return nRet;
}

Precompiled header file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma once

// stdafx.h

#define WINVER        0x0502
#define _WIN32_WINNT  0x0502

#define _SECURE_ATL   1

#include <atlbase.h>
#include <atlstr.h>
#include <atltypes.h>
#include <atlapp.h>

extern CAppModule _Module;

#include <atlwin.h>
#include <atlcrack.h>
#include <atlframe.h> 


cpp file for precompiled header:

1
2
3
4
5
6
7
// stdafx.cpp

#include "stdafx.h"

#if (_ATL_VER < 0x0700)
#include <atlimpl.cpp>
#endif //(_ATL_VER < 0x0700) 

Last edited on
Using just a single window...

Actually, replacing MainFrame and View with a single window is easy enough...

Also need to make a slight tweak to the Run() function, which is used by WinMain. But not WinMain itself.

And #include <atlframe.h> can be removed from stdafx.h

Header file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once

// WTL_TestWnd.h

class CWTL_TestWindow
: public CWindowImpl<CWTL_TestWindow>
{
public:
	DECLARE_WND_CLASS(NULL)

	BOOL PreTranslateMessage(MSG* /*pMsg*/) { return FALSE; }

	BEGIN_MSG_MAP_EX(CWTL_TestWindow)
		MSG_WM_DESTROY(OnDestroy)
		MSG_WM_PAINT(OnPaint)
	END_MSG_MAP()

	void OnDestroy();
	void OnPaint(CDCHandle dc);
};


cpp file :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// WTL_TestWnd.cpp

#include "stdafx.h"

#include "WTL_TestWnd.h"

void
CWTL_TestWindow::OnDestroy()
{
	PostQuitMessage(0);
}

void
CWTL_TestWindow::OnPaint(CDCHandle /*dc*/)
{
	CPaintDC dc(m_hWnd);

	COLORREF crefRed = RGB(255, 0, 0);

	LOGFONT logFont = {0};
	logFont.lfHeight = 72;
	logFont.lfWeight = FW_BOLD;
	_tcscpy_s(logFont.lfFaceName, _T("Arial"));

	CFont font;
	font.CreateFontIndirect(&logFont);

	CRect rect;
	GetClientRect(rect);

	CAtlString strMessage = _T("Hello WTL!");
	UINT uFormat = DT_CENTER | DT_VCENTER | DT_SINGLELINE;

	COLORREF crefTextOld = dc.SetTextColor(crefRed);
	HFONT    hfontOld    = dc.SelectFont(font);

	dc.DrawText(strMessage, strMessage.GetLength(), rect, uFormat);

	dc.SetTextColor(crefTextOld);
	dc.SelectFont(hfontOld);
}


Adjusted Run() function :

The #includes in WTL_Test.cpp will need to be tweaked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int
Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
	CMessageLoop theLoop;
	_Module.AddMessageLoop(&theLoop);

	CWTL_TestWindow wndMain;

	// in a proper WTL project,the window title is read from the resource file
	const TCHAR achWindowTitle[] = _T("Hello WTL");
	if(wndMain.Create(NULL, 0, achWindowTitle, WS_OVERLAPPEDWINDOW) == NULL)
	{
		ATLTRACE(_T("Main window creation failed!\n"));
		return 0;
	}

	wndMain.ShowWindow(nCmdShow);
	int nRet = theLoop.Run();
	_Module.RemoveMessageLoop();

	return nRet;
}

Last edited on
Topic archived. No new replies allowed.