Pages

Sunday, November 8, 2009

ATL, GDI+. PNG,...

After a half of a day of a dramatic struggle with CImage, I failed to make it working with the png images - the images that contain the alpha chanel. I found the solution, but with GDI+ and I will show it later.

Firstly, I have to say, that the CImage converts any image into 32 bit per pixel format, but it is just RGB (pre-muliplay alpha?). When CImage loads an image it copies the image data into an internal buffer. You can see everything yourself, if you will debug CImage methods such as Load from the stream, for example.

Secondly, I just included atlimage.h file header into my source code and got a bunch of dlls from which my application depends now. Including the dynamic run-time libraries, and GDI+, and something from the Windows Installer, and...

I very like ATL, I just love the style, but, probably, I will try to avoid using CImage in my projects.
For a fast and dirty job that does not require to load any data with alpha..., maybe, it is possible. CImage even has AlphaBlend function - it's just a wrapper for the Win API function. From my point view, it is just one more evidence of a bad design made for this class - from one side the class uses GDI+, from other side it uses GDI function to draw the image.

The original task was to load the PNG-file from the resources in an ATL-based application. I thought I solved it. It looked great - I made a template - CImageResource, that contain only one function -  LoadFromResource. The objects I created in my application were like

CImageResource<CImage> m_Image;

I added a window background image to the resources and saw it's drawn in the application window. AlphaBlend method was used and everything was just fine.

The problems begun when I added a button image with the real visible alpha.

So finally the class CImageResource is not a template :). It looks so:
#pragma once

class CImageResource
{
Bitmap* m_pBitmap;
HGLOBAL m_hBlock;

public:
CImageResource() : m_pBitmap(NULL), m_hBlock(NULL) {}
~CImageResource() { Clear(); }

inline BOOL IsNull() const { return m_pBitmap == NULL; }

UINT GetWidth()
{
if (IsNull())
return 0;
return m_pBitmap->GetWidth();
}

UINT GetHeight()
{
if (IsNull())
return 0;
return m_pBitmap->GetHeight();
}

BOOL Draw(HDC hDC, int x, int y)
{
if (IsNull())
return FALSE;
Graphics graphics(hDC);
return graphics.DrawImage(m_pBitmap, x, y,
m_pBitmap->GetWidth(), m_pBitmap->GetHeight()) == Ok;
}

BOOL Draw(HDC hDC, RECT& rect)
{
if (IsNull())
return FALSE;
Graphics graphics(hDC);
return graphics.DrawImage(m_pBitmap, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top) == Ok;
}

BOOL Load(LPCWSTR lpszFile)
{
Clear();
m_pBitmap = Bitmap::FromFile(lpszFile);
return m_pBitmap->GetLastStatus() == Ok;
}

BOOL LoadFromResource(UINT nResID)
{
Clear();
HMODULE hModule = GetModuleHandle(NULL);
HRSRC hResource = FindResource(hModule,
MAKEINTRESOURCE(nResID), L"IMAGES");
if (hResource == NULL)
return FALSE;

HGLOBAL hImage = LoadResource(hModule, hResource);
if (hImage == NULL)
return FALSE;
LPVOID pImage = LockResource(hImage);
if (pImage == NULL)
return FALSE;

HRESULT hr = E_FAIL;
int size = SizeofResource(hModule, hResource);
m_hBlock = GlobalAlloc(GMEM_MOVEABLE, size);
if (m_hBlock == NULL)
return FALSE;

LPVOID pBlock = GlobalLock(m_hBlock);
if (pBlock != NULL)
{
memmove(pBlock, pImage, size);
IStream* pStream = NULL;
if (CreateStreamOnHGlobal(m_hBlock, FALSE, &pStream) == S_OK)
{
m_pBitmap = Bitmap::FromStream(pStream);
pStream->Release();
if (m_pBitmap != NULL)
{
if (m_pBitmap->GetLastStatus() == Ok)
return TRUE;
}
delete m_pBitmap;
m_pBitmap = NULL;
}
GlobalUnlock(m_hBlock);
}
GlobalFree(m_hBlock);
m_hBlock = NULL;
return FALSE;
}

void Clear()
{
delete m_pBitmap;
m_pBitmap = NULL;
if (m_hBlock != NULL)
{
GlobalUnlock(m_hBlock);
GlobalFree(m_hBlock);
}
}
};

Now all images are loaded and drawn with the alpha. For drawing I use the GDI+ as well.
Here are few helpful links from CodeProject about this topic:
Joe Woodbury. Loading JPG & PNG resources using GDI+: http://www.codeproject.com/KB/GDI-plus/cgdiplusbitmap.aspx
Christian Graus. Starting with GDI+: http://www.codeproject.com/KB/GDI-plus/startinggdiplus.aspx
 Darren Sessions. A user draw button that supports PNG files with transparency, for Visual C++ 6.0 and VS2005: http://www.codeproject.com/KB/buttons/GdipButton.aspx

Wednesday, November 4, 2009

Очередной Android

От Sony Ericsson (4" capacitive display, 8 с чем-то фотокамера и так далее):




Ну... что Вам сказать... По-моему пока все андроиды хуже телефонов с Windows Mobile.


Наверное, безплатный Google Map Navigation это большой плюс. Зря Microsoft не довели свою навигационную историю до ума - мыкались кого купить, свои проэкты начали (NavReady), в конце все проспали.

Smartphone market in Q3 2009

Canalys Q3 2009: iPhone, RIM taking over smartphone market


По-прежнему Nokia "впереди планеты всей" (несколько ее смартфонов я видел сам на этой неделе - очень неплохо). Благодаря iPhone, Google и RIM рост ее продаж не очень уж увеличивается. HTC завоевала свое свое законное место в лидерах. Motorola, выпала из первой пятерки. Возможно, ее Droid с безплатной Google Map Navigation вернет ей позиции. Посмотрим в результатах текущего квартала.

Sunday, November 1, 2009

Simulate mouse move and click

Just for fun. These code moves the mouse and click on the left button:
#define WIN32_LEAN_AND_MEAN

#include <Windows.h>


void LeftClick( )
{
INPUT input = { 0 };
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
::SendInput(1, &input, sizeof(INPUT));

::ZeroMemory(&input, sizeof(INPUT));
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
::SendInput(1, &input, sizeof(INPUT));
}

void MouseMove (int x, int y )
{
double fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN) - 1;
double fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN) - 1;
double fx = x * (65535.0f / fScreenWidth);
double fy = y * (65535.0f / fScreenHeight);
INPUT input = { 0 };
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
input.mi.dx = fx;
input.mi.dy = fy;
::SendInput(1, &input, sizeof(INPUT));
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
MouseMove(500, 500);
LeftClick();
return 0;
}

ATL Window

From my point of view, MFC is just a wrapper for Windows API. I think, it is a heavy and slow wrapper. I cannot say that if I need to test something simple, I always create an MFC dialog-based application as it used to be few years ago. The Visual Studio wizards create a lot of code, many files, add stdafx.h that connects my code with a lot of headers and libraries, and I still need to edit something in the resources. So, whenever possible, I use just the following simple shablon:


#define WIN32_LEAN_AND_MEAN

#include <windows.h>


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
It 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.


I have shown how to add a window to this code - Самая простая Win32 программа-шаблон для тестов. - it is more C-style, than C++. I'd say the ATL can bring a very modern C++ style into this simple test application.


For the beginning let's modify the first example from this article and add the ATL support:


#define WIN32_LEAN_AND_MEAN
#include <atlbase.h>

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
It's compiled successfully and works, but does nothing.
Let's add an ATL Window:
#define STRICT
#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;
}
This time the application window is an object of CMyWindow class. WinMain function has common things: creates the window, show it, launch the message loop.
CMyWindow class is simple too. It contains:
  1. Window class definition (DECLARE_WND_CLASS).
  2. Message map. (BEGIN_MSG_MAP.. END_MSG_MAP with two message handlers for WM_CLOSE and WM_DESTROY)
  3. 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>,
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;
}
};
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).
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;
}


This image has the alpha and it is drawn with the AlphaBlend.

Aliasing

Here are two articles about the subject:
1. Krister Walfridsson. Aliasing, pointer casts and gcc 3.3.
2. Mike Acton. Understanding Strict Aliasing.

The main idea is simple:
Pointer casts are evil (both explicit and implicit casts), and you should think twice before adding a pointer cast to the code...
Scott Meyers says about it softer:
If you’re coming to C++ from C, Java, or C#, take note, because casting in those languages is more necessary and less dangerous than in C++. But C++ is not C. It’s not Java. It’s not C#. In this language, casting is a feature you want to approach with great respect.
Key points:
1. One pointer is said to alias another pointer when both refer to the same location or object.
2. Pointers of different types cannot point to the same address.
3. Code below:
int
foo(float *f) {
int i = 23;
*f = 5.0;
/* A float* cannot point on the same address as int*. */
return i * 2;
}
Compiler may optimize as:
int
foo(float *f) {
*f = 5.0;
return 46;
}
4. Many architectures requires that pointers are correctly aligned when
accessing objects bigger than a byte. So the following code may not work:
char* data;
struct foo_header *tmp, header;

tmp = data + offset;
memcpy(&header, tmp, sizeof(header));
The reason is that the behavior is undefined when you assign an unaligned value to a pointer that points to a type that need to be aligned. What happens in the example above is that compiler notices that tmp and header must be aligned, so it may use an inlined memcpy that uses instructions that assumes aligned data.
Here is fix:
char* data;
struct foo_header header;

memcpy(&header, data + offset, sizeof(header));

Double to Int

We all know how to convert a double value to integer. Google "double to int C++". You will find exactly what you usually use:
double pi = 3.14159;
int x = int (pi);
C++ does not perform this converting from double to it automatically, because it requires the rounding off and you should be aware that you lost the fractial part of the number.

So? In a library that works with OpenGL I see this strange code:
__inline GLfixed
Fixedf(GLfloat a)
{
GLfloat b = a;
GLuint d = *((GLuint*)&b) + 0x08000000;
return (GLfixed)(*((GLfloat*)&d));
}
Why this line with *((GLuint*)&b) should be so complicated?

In order to see what's going on I wrote few lines:

int main()
{
double x1 = 123.456;
double x2 = 321.654;

int y1 = (int)x1;
int y2 = static_cast<int>(x1);
int y3 = *(int*)&x2;
int y4 = *reinterpret_cast<int*>(&x2);
return 0;
}

In the debug mode I switched to the disassember:

I'm not a guru in such things, but looks like this line:

int y3 = *(int*)&x2;
seems "complicated" only in C++. In Assembler it looks trivial:
mov         eax,dword ptr [x2] 
mov dword ptr [y3],eax
You can compare it with:
fld         qword ptr [x1] 
call @ILT+215(__ftol2_sse) (4110DCh)
mov dword ptr [y1],eax
generated from usual:
int y1 = (int)x1;

But the result is absolutely different:

That's not what I need.
In Anti-Grain Geometry Library I found:
#pragma warning(push)
#pragma warning(disable : 4035) //Disable warning "no return value"
inline int iround(double v) //-------iround
{
int t;
__asm fld qword ptr [v]
__asm fistp dword ptr [t]
__asm mov eax, dword ptr [t]
}

inline unsigned uround(double v) //-------uround
{
unsigned t;
__asm fld qword ptr [v]
__asm fistp dword ptr [t]
__asm mov eax, dword ptr [t]
}
#pragma warning(pop)

So it is possible to use:

int y5 = iround(x1);

The result will be correct: