#define WIN32_LEAN_AND_MEANIt is not the Win32 console application, I can test many new for me things from the Platform SDK and do not see the annoying console window.
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
#define WIN32_LEAN_AND_MEANIt's compiled successfully and works, but does nothing.
#include <atlbase.h>
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
Let's add an ATL Window:
#define STRICTThis time the application window is an object of CMyWindow class. WinMain function has common things: creates the window, show it, launch the message loop.
#define WIN32_LEAN_AND_MEAN
#include <atlbase.h>
#include <atlwin.h>
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CMyWindowTraits;
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CMyWindowTraits>
{
public:
DECLARE_WND_CLASS(L"My Window")
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()
LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DestroyWindow();
return 0;
}
LRESULT OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PostQuitMessage(0);
return 0;
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
CMyWindow wnd;
MSG msg;
HWND hWnd = wnd.Create(NULL, CWindow::rcDefault, L"ATL Window");
if (hWnd == NULL)
return 0;
wnd.ShowWindow(nShowCmd);
wnd.UpdateWindow();
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
CMyWindow class is simple too. It contains:
- Window class definition (DECLARE_WND_CLASS).
- Message map. (BEGIN_MSG_MAP.. END_MSG_MAP with two message handlers for WM_CLOSE and WM_DESTROY)
- Window styles (CMyWindowTraits).
That'all:
Why I like this style?
Mainly, because I see and control each message my window receives. Nothing is hidden from me, I have to write with my hands everything I want to happen in my application. This style allows me to learn more about Win32, understand better the Windows.
Let's add one more message handler into the CMyWindow class - for example, let's handle WM_ERASEBKGND. We need to update the message map:
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
and add the method that will be called on the message arriving:LRESULT OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return 1;
}
We got a transparent window:
The window is transparent, because the background eraser is empty, but return 1 - meaning we have painted the background.
Why I like ATL?
Because I can use the templates and real Object-Oriented programming for my window classes. For example, ATL allows me to split the message map in the CMyWindow class between many classes and do not have a long and heavy window class. Let's move the backround painter to a seperate class like the following:
template <class T, COLORREF color>
class CBackground
{
HBRUSH m_hBrush;
public:
CBackground()
{
m_hBrush = CreateSolidBrush(color);
}
~CBackground()
{
DeleteObject(m_hBrush);
}
BEGIN_MSG_MAP(CBackground)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
END_MSG_MAP()
LRESULT OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
HDC hDC = (HDC)wParam;
RECT rect = { 0 };
pT->GetClientRect(&rect);
FillRect(hDC, &rect, m_hBrush);
return 1;
}
};
This time I created a brush with the predefined color in the class contstructor and delete it in the destructor. Please pay attention that we do not need to check any pointer in OnEraseBkgnd method - no one of them can be NULL.
We need to modify the CMyWindow:
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CMyWindowTraits>,CBackground class was added into the inheritance list. and CHAIN_MSG_MAP was added into the map (I used typedef to use a simple name in the message map macro).
public CBackground<CMyWindow, RGB(128, 128, 128)>
{
public:
typedef CBackground<CMyWindow, RGB(128, 128, 128)> CBackgroundEraser;
DECLARE_WND_CLASS(L"My Window")
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
CHAIN_MSG_MAP(CBackgroundEraser)
END_MSG_MAP()
LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DestroyWindow();
return 0;
}
LRESULT OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PostQuitMessage(0);
return 0;
}
};
And here is the application:
Now we have ATL included and so can use other cool stuff. Let's put an image onto the background of our window:
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <atlbase.h>
#include <atlwin.h>
#include <atlimage.h>
template <class T, WCHAR* lpszFileName>
class CImageBackground
{
CImage m_Image;
public:
CImageBackground()
{
m_Image.Load(lpszFileName);
}
BEGIN_MSG_MAP(CBackground)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
END_MSG_MAP()
LRESULT OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
HDC hDC = (HDC)wParam;
RECT rect = { 0 };
pT->GetClientRect(&rect);
m_Image.AlphaBlend(hDC, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
0, 0, m_Image.GetWidth(), m_Image.GetHeight());
return 1;
}
};
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CMyWindowTraits;
WCHAR s_szFile[] = L"image.jpg";
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CMyWindowTraits>,
public CImageBackground<CMyWindow, s_szFile>
{
public:
typedef CImageBackground<CMyWindow, s_szFile> CBackgroundEraser;
DECLARE_WND_CLASS(L"My Window")
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
CHAIN_MSG_MAP(CBackgroundEraser)
END_MSG_MAP()
LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DestroyWindow();
return 0;
}
LRESULT OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PostQuitMessage(0);
return 0;
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
CMyWindow wnd;
MSG msg;
HWND hWnd = wnd.Create(NULL, CWindow::rcDefault, L"ATL Window");
if (hWnd == NULL)
return 0;
wnd.ShowWindow(nShowCmd);
wnd.UpdateWindow();
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaRQIqRyRBX8vTW59Bjl0Gmb1N8Jiwzp8qY3DFKPUIwYH6FnMeEzanPhyphenhyphengslUYMnlsEHHwadjAirOiwf1EQhNmuoSImA_toIGfM531ACELR9jYi5txl0GQQVNb28iDZ8h-vFDPF2G1sGg/s320/ATL+Window+image.jpg)
This image has the alpha and it is drawn with the AlphaBlend.
No comments:
Post a Comment