Monday, June 29, 2009

A better look

Here's a better look for the CrypSafe main view. As you can see I'm using a new font for the item text, added a separation line between the items and painted the background with a different brush for odd-numbered items. The changes to the code are not very dramatic, so let's take a look at them.

The first change is the new font. To use a new font I generally declare a CFont object on the view class like this:

private:
CFont m_largeFont;

This way I know that the font will exist throughout the life cycle of the containing view. Creating the font itself is always a bit of a pain, but i prefer to use the following method because it does give me full control over what is going on. The following code snippet was taken from the view constructor in CCrypSafeView.cpp:

LOGFONT lf;
int nLogPixelsY = DRA::LogPixelsY();

lf.lfHeight = DRA::HIDPIMulDiv(-12, nLogPixelsY, 72);
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_NORMAL;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = 0;
lf.lfCharSet = ANSI_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = CLEARTYPE_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
_tcscpy(lf.lfFaceName, TEXT("Tahoma"));
m_largeFont.CreateFontIndirect(&lf);

The code at the top is the most important one because it makes sure that we create the font with the right size in points, independently of the resolution of your device's screen.

Now that the new font is ready to use, let's see how to use it on the DrawItem method. First, you need to declare an HFONT variable:

HFONT hFont;

This is used to store the DC's currently selected font while we use our custom font. Setting the new font is easy:

hFont = dc.SelectFont(m_largeFont);

When we are done with the new font, we must set the old DC font back:

dc.SelectFont(hFont);

To paint the text with a left border, I copied the item CRect to a new instance:

CRect rcText(rcItem);

Before painting, the left value is adjusted:

rcText.left += DRA::SCALEX(4);

Note that this will correctly scale in higher DPI screens. As you can see from the included image, the even-numbered items have a white background while the odd-numbered ones have a very light gray background. As I explained in the previous post, the client code in DrawItem is supposed to paint the background, and doing it is extremely easy:

COLORREF rgb(m_rgbBack);
if(iItem % 2) rgb = RGB(0xf0, 0xf0, 0xf0);
brush.CreateSolidBrush(rgb);
dc.FillRect(&rcItem, brush);

The m_rgbBack variable is declared by CTouchListBase and contains the default background color (this color is used to fill in the unpainted space at the bottom of the list). If the item has an odd number, I replace the default white with a light gray and use this RGB value to create a brush. Painting the item's background is a simple issue of calling FillRect with the supplied item CRect (rcItem).

Now we can paint the item's text making sure that it is painted with a transparent background mode:

int nBkMode = dc.SetBkMode(TRANSPARENT);
dc.DrawText(pItem->GetText(), -1, &rcText, DT_LEFT | DT_VCENTER);
dc.SetBkMode(nBkMode);

Note that the text is painted using the rcText rectangle, not the item's. This way we get the left margin effect. Finally we can print the bottom separation line:

CPen pen;
HPEN hPen;
pen.CreatePen(PS_SOLID, 1, m_rgbLine);
hPen = dc.SelectPen(pen);
dc.MoveTo(0, rcItem.bottom - 1);
dc.LineTo(rcItem.right, rcItem.bottom - 1);
dc.SelectPen(hPen);

The m_rgbLine contains the default color for the separation line (gray). As you can see, this is not rocket sience. Next, I will explore how to add a navigation cursor and key handling.

Sample code: CrypSafe01.zip (96 KB)

Friday, June 26, 2009

The CrypSafe prototype

Today I present the very first iteration of the mobile password safe application. First I decided to name it "CrypSafe". Second, I also decided to post the code in very small increments so that the whole process of using the WM framework becomes clearer (and also to allow me to add changes as I see fit). Third, I'm starting off with a prototype.

The application architecture is actually very simple (as usual, I'm using WTL 8.0):
  • A main frame window that contains the content views and any decorations
  • A category view that shows the information categories in the safe
  • A detail view showing the individual items in each category
  • An item editing dialog
More items will be added if need arises, but for now I would say that this is enough. When you create a new project using the WTL Mobile Application Wizard, you get a lot of code created for you. In fact, after creating the project you can compile and run (and it will run - just make sure that the WTL include files are reachable for both the C++ and resource compilers). I usually create an SDI application with a child view because it's the most flexible arrangement. You can skip the child view and pain directly on the frame's client area, but this will make it harder for you to use multiple views. Incidentally, the code that flips views does paint on the frame's client area, but that's another story.

After creating your initial project, our first stop is to change the view window (see the source code):

class CCrypSafeView : public CTouchList<CCrypSafeView>, public CChildView<CCrypSafeView>

This means that our view will implement both a "touch list" and will also behave like a switchable child view. Next we need to remove the standard painting protocol and replace it with the touch list's:

virtual void DrawItem(HDC hDC, int iItem, CRect &rcItem);

Yes, we only need this because the list is painted item by item. Remove the OnPaint handler because it is not needed (it's implemented by the base class). I also added a default constructor where I placed the initial list of categories for the prototype:


CCrypSafeView::CCrypSafeView()
{
AddItem(new CTouchListItem(L"Credit Cards"));
AddItem(new CTouchListItem(L"Debit Cards"));
AddItem(new CTouchListItem(L"Mail Accounts"));
AddItem(new CTouchListItem(L"SIM Cards"));
AddItem(new CTouchListItem(L"User Accounts"));
AddItem(new CTouchListItem(L"Web Sites"));
}

Note that these items are not explicitly delete anywhere in the code because their pointers are reference counted (internally). Finally, let's see how to paint the items:


void CCrypSafeView::DrawItem(HDC hDC, int iItem, CRect &rcItem)
{
CDCHandle dc(hDC);
PTouchListItem pItem = GetItem(iItem);

dc.DrawText(pItem-&gtGetText(), -1, &rcItem, DT_LEFT);
}

Note that the PTouchListItem type is a typedef that denotes the reference-counted version of a pointer to a CTouchListItem object.

As you can see from the image, the result is less than satisfactory. The whole list is painted on an off-screen bitmap that is initialized to solid black (hence the black areas of the screen). The bottom of the list is automatically filled with the background color, but not the individual items - you must fill in the background for yourself. We also need to make the item font larger (possibly bold and with ClearType rendering for a better reading experience). As you can see each row has a height of 40 pixels (80 on high DPI machines) in order to accommodate a 32x32 (64x64 on high DPI machines) image. The text will have to be correctly formatted in order to better fill each row.

For the time being, you can take a peek at the first version of the code here.

P.S.: Anatoly, I have not included all of your changes yet.

Wednesday, June 24, 2009

Back to native

After a few days struggling with the BlackBerry JDK, JDE and Eclipse, it's time to get back to predictability and safe ground. Boy, have I missed Visual Studio!

Now that I have some readers actively using, criticizing and suggesting improvements to the Windows Mobile native framework (thank you so much, Anatoly!), I think now is the time to start exercising the code with a real application. Contrary to my early plans, I will start with something that I really need on a day-to-day basis: a mobile password safe. Nowadays I struggle to remember all the mobile phone PINs and PUKs, debit and credit card PINs, online service passwords, just to name a few. I know there are some excellent applications out there ready to be purchased, but what's the fun in that? My idea is very simple: use an encrypted SQL Compact database to store all the sensitive data. The user will be able to add, modify and delete both data and structure (each information category will be stored in a different table). The user interface must be very simple:
  • A main list containing the user's information categories (credit cards, phone PINs...);
  • A secondary list containing the category details;
  • A dialog for editing the details
So, after committing to this, let me roll my sleeves and head back to VS. On the next post I will start publishing the first version of the code.

Monday, June 15, 2009

A simple GPS viewer

Here's a simple GPS viewer application. I wrote it to help me in testing the transition to reference counted pointers in my budding Windows Mobile native (WTL-based) framework. In the process I have learned a few things about reference counted pointers, especially when NOT to use them.

One of the changes I made to the way the CPropertyListView class is used is that it contains pointers to items created on the heap and not on the stack. This means that you now have to create items like this:

m_pGpsFix = new CPropertyString(L"Fix", L"Unknown");

Note that the m_pGpsFix variable is actually a "smart pointer" and you don't have to worry about deleting it in the destructor. Nor does the list, in fact... When each item's reference count reaches zero, the last smart pointer that references the object will delete it (and that's why you cannot have stack allocated items). This is when you should use smart pointers, so when should you use simple C++ pointers? I found out the hard way when adding these items to the list. My original (and right) prototype was:

void CTouchListBase::AddItem(CTouchListItem* pItem)

When I replaced the C++ pointer with a smart one, I immediately lost one of the best features these things have: the ability of a base class pointer to refer to a derived class object. Understanding that I don't know enough about C++ class templates to make this work (not even sure if that's possible - will have to look at Jossutti's book), I decided to fall back to straight C++ pointers. This poses no problem because the method internally will use the smart pointer class constructor to build a new instance using the raw pointer and add it to the underlying array, so the reference counting is respected.

The sample application just starts the GPSID and displays some data from the GPS on a dialog. As you can see from the ZIP file, there are two additional library projects that make up the framework. Note that these are subject to change and do have bugs!

Sample code: GpsView.zip (93 KB)

Thursday, June 11, 2009

unresolved external symbol CLSID_ImagingFactory

Just started out a new sample project that illustrates how to use the WM libraries I'm writing, and got the following link errors:

1>wmfw.lib(Image.obj) : error LNK2001: unresolved external symbol CLSID_ImagingFactory
1>wmfw.lib(Image.obj) : error LNK2001: unresolved external symbol IID_IImagingFactory


This means that the linker cannot find the symbols CLSID_ImagingFactory and
IID_IImagingFactory, required to use the imaging library on Windows Mobile. If you look at the documentation, you will see that a link to the imaging.lib file is required but it will not work (at least it does not work for me).

The solution I found is to force the inclusion of these symbols using a dummy file that I usually name guids.cpp. Here's the content:

#include "stdafx.h"
#include <initguid.h>
#include <imgguids.h>


The initguid.h include redefines the DEFINE_GUID macro that is used by imgguids.h so that it declares a GUID along with its value instead of making an external reference to the same symbol.

Compile and link and the error goes away.

More native memory in WM 6.x

Here's a very interesting blog post from The Windows Mobile RSS: More Memory For ALL in WM 6.x. As you can see, folks at Microsoft still care about us, native mobile developers.

Wednesday, June 03, 2009

VS 2010 and Smart Device Development

This updated link explains it all: Smart Device development is not supported by Visual Studio 2010 Beta 1, but will (somehow) be supported by the final release. Quoting:

"Microsoft is committed to making Visual Studio a great development tool for the mobile device developer, and will deliver mobile device tools for Visual Studio 2010, but cannot share details now. For existing Visual Studio 2008 mobile developers, Microsoft will release a new Windows Mobile 6.5 emulator in the upcoming months that works with the Windows Mobile 6 SDK."

Now, back to work.