Saturday, July 25, 2009

Trust but Validate

The phrase "trust but verify" came out of the cold war. I learned SGML while working at ATLIS Systems. For many years ATLIS was a leader in SGML. One phrase coined by ATLIS was, "If a system is not based on a DTD and checked by an SGML parser, it is NOT SGML." In essence, you had to validate each and every instance. HTML (up through version 4) is not XML. HTML (up through version 4) is an SGML application. XML replaced SGML. I am amazed at how few XML aware applications never bother to create a DTD or Schema for the XML.

Years ago, I created a tool to help maintain my websites. The tool initially started out in Python. I really like the way the regular-expression library integrates with Python. Python refers to everything as an object. This allows putting function pointers into dictionaries and passing them to other functions. This was an important feature in the tool I created to maintain my websites. I created the user interface in Delphi. There is a mechanism to integrate Python and Delphi. I could quickly prototype the core regular expression replacements in Python and use that code in the finished user interface application.

I rewrote the Delphi code in C#. Although I thought the code was relatively clean, there were a few minor points that needed refactoring. I considered integrating my Python into C#. Instead, I found that the C# regular-expression library uses delegates. C# delegates are similar to function pointers in C/C++. Delegates allow you to pass function pointers to the regular-expression library just like you can do in Python. The C# syntax is a bit more wordy (verbosity never bothers me) than Python but a lot more strict. Python gives you enough rope to hang yourself by its lack of type checking. C# is a much strong typed language. I refactored my old Delphi and Python program into C#.

Microsoft added a lot of support for XML and HTML to .Net. One feature I did not have in the old version of my tool was a mechanism to validate the document. The code below shows how to validate a document in C#.

StringReader sr = new StringReader(WebPage);
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.ValidationEventHandler += new ValidationEventHandler(PageValidationEvent);
XmlReader xvr = XmlReader.Create(sr, settings);
try
{
while (xvr.Read())
{
// do nothing
}
}
catch (XmlException e)
{
// handle any validation errors
}

The code below handles a single error.

public static void PageValidationEvent(object sender, ValidationEventArgs args)
{
// code to handle each error
}

Microsoft's validation is only mediocre. It catches most errors but not all. But for a few simple lines of code it is worth the effort.

I try to be very careful and ensure that my documents are correctly formed and valid. I started a major redesign of one of my websites. I originally built the site using my Delphi-Python tool. I had not done any major work on the site in years. When I started rebuilding the site using the C# version of my tool I found a lot of validation errors. Even though I tried to be careful I made some simple mistakes.

Those mistakes are the reason why I decided to write this article I titled "Trust but Validate". Now that I think about it, don't both with the trust, just validate your HTML and XML.

Tuesday, July 14, 2009

Developing using C# for Windows Mobile Suddenly Got Easier

I complained Microsoft did not make all the GDI and Win32 equivalent for C#. Well they are. Microsoft just didn't bother to make it easy to find. For me, it took a couple of days of searching before I stumbled on this great article: Optimize Your Pocket PC Development with the .NET Compact Framework. The title does not sound that important. This article gives you lots and lots of code you need if you want to develop using C# on Windows Mobile. For example, it provides a mapping of a large number of Win32 equivalent calls providing all the P/Involk code, constants, and enumerations. It also provides a Gdi class that maps a lot of the GDI calls. I wish I had found this article a couple of days ago.

The article does not describe everything included in the source code. It contains libraries Brushes, Fonts, Font Cache, GDI, Pens, the Registry, and Win32 calls. If you are developing for Windows Mobile and using C# you need to download the source code and look at all the hidden goodies.

Monday, July 13, 2009

Developing using C# for Windows Mobile is harder than it should be

I got side tracked today and starting playing with Quakk, a Twitter client for Windows Mobile. It was a good time to peak under the hood and learn how the Twitter API worked as well as see how someone implemented a Windows Mobile client. Quakk compiles and runs under Visual Studio 2008 once you get all the mobile development tools downloaded, installed, and configured. Microsoft makes that harder than it should. For example, in order to connect your mobile VM to the Internet you have to install Microsoft Virtual PC. Microsoft used to allow you download the network drivers. Now you have to install their entire Virtual PC in order to use the network drivers for the Windows Mobile VMs.

The Mobile VMs allow you to scale up the VM so it easier to read. Otherwise I would be stuck with 240x240 pixel emulation on a large screen. After you make the change you need to save the configuration or it will revert back. The same is true with the network settings.

Once I got Quakk running I took a good look at the code. Parts were well comments. Parts use lots of "magic numbers". For example, there were several places where the code would subtract 13 from the width of the panel. The default width of a vertical scroll bar is 13 pixels on Windows Mobile. At a bare minimum, that should have been a constant. It was not.

I decided to start removing the "magic numbers". This was a lot harder than it sounds. If you develop for Windows, then the System.Windows.Forms.SystemInformation class provides a great deal of information. Unfortunately, if you develop for Windows Mobile, Microsoft decided to lobotomize this class. This means for most applications you need to use the lower level GetSystemMetrics. This is fine if you are programming in C++. But if you are using C#, well things are harder than they should be. After much searching, I found the code to P/Involk the GetSystemMetrics call. Pinvolk.net is a useful resource, but as I write this, they did not document the Windows Mobile version of the GetSystemMetrics call; which is slightly different than the GetSystemMetrics call for Windows. Again, Microsoft made things a bit harder than they should be by changes the DLL that contains GetSystemMetrics when they ported it to Windows Mobile. My code for GetSystemMetrics is below.


using System;
using System.Runtime.InteropServices;

namespace WindowsAPI
{
public static class WinAPI
{
/// <summary>
/// Call the system metrics function
///
/// Windows mobile uses coredll.dll and not user32.dll
/// </summary>
/// <param name="smIndex">The value to return</param>
/// <returns>Integer value requested</returns>
[DllImport("coredll.dll")]
public static extern int GetSystemMetrics(SystemMetric smIndex);

/// <summary>
/// Windows mobile uses coredll.dll and not user32.dll
///
/// Flags used with the Windows API (User32.dll):GetSystemMetrics(SystemMetric smIndex)
///
/// This Enum and declaration signature was written by Gabriel T. Sharp
/// ai_productions@verizon.net or osirisgothra@hotmail.com
/// Obtained on pinvoke.net, please contribute your code to support the wiki!
/// </summary>
public enum SystemMetric : int
{
/// <summary>
/// Width of the screen of the primary display monitor, in pixels. This is the same values obtained by calling GetDeviceCaps as follows: GetDeviceCaps( hdcPrimaryMonitor, HORZRES).
/// </summary>
SM_CXSCREEN = 0,
/// <summary>
/// Height of the screen of the primary display monitor, in pixels. This is the same values obtained by calling GetDeviceCaps as follows: GetDeviceCaps( hdcPrimaryMonitor, VERTRES).
/// </summary>
SM_CYSCREEN = 1,
/// <summary>
/// Width of a horizontal scroll bar, in pixels.
/// </summary>
SM_CYVSCROLL = 2,
/// <summary>
/// Height of a horizontal scroll bar, in pixels.
/// </summary>
SM_CXVSCROLL = 3,
/// <summary>
/// Height of a caption area, in pixels.
/// </summary>
SM_CYCAPTION = 4,
/// <summary>
/// Width of a window border, in pixels. This is equivalent to the SM_CXEDGE value for windows with the 3-D look.
/// </summary>
SM_CXBORDER = 5,
/// <summary>
/// Height of a window border, in pixels. This is equivalent to the SM_CYEDGE value for windows with the 3-D look.
/// </summary>
SM_CYBORDER = 6,
/// <summary>
/// Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border.
/// </summary>
SM_CXDLGFRAME = 7,
/// <summary>
/// Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border.
/// </summary>
SM_CYDLGFRAME = 8,
/// <summary>
/// Height of the thumb box in a vertical scroll bar, in pixels
/// </summary>
SM_CYVTHUMB = 9,
/// <summary>
/// Width of the thumb box in a horizontal scroll bar, in pixels.
/// </summary>
SM_CXHTHUMB = 10,
/// <summary>
/// Default width of an icon, in pixels. The LoadIcon function can load only icons with the dimensions specified by SM_CXICON and SM_CYICON
/// </summary>
SM_CXICON = 11,
/// <summary>
/// Default height of an icon, in pixels. The LoadIcon function can load only icons with the dimensions SM_CXICON and SM_CYICON.
/// </summary>
SM_CYICON = 12,
/// <summary>
/// Width of a cursor, in pixels. The system cannot create cursors of other sizes.
/// </summary>
SM_CXCURSOR = 13,
/// <summary>
/// Height of a cursor, in pixels. The system cannot create cursors of other sizes.
/// </summary>
SM_CYCURSOR = 14,
/// <summary>
/// Height of a single-line menu bar, in pixels.
/// </summary>
SM_CYMENU = 15,
/// <summary>
/// Width of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value.
/// </summary>
SM_CXFULLSCREEN = 16,
/// <summary>
/// Height of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value.
/// </summary>
SM_CYFULLSCREEN = 17,
/// <summary>
/// For double byte character set versions of the system, this is the height of the Kanji window at the bottom of the screen, in pixels
/// </summary>
SM_CYKANJIWINDOW = 18,
/// <summary>
/// Nonzero if a mouse with a wheel is installed; zero otherwise
/// </summary>
SM_MOUSEWHEELPRESENT = 75,
/// <summary>
/// Height of the arrow bitmap on a vertical scroll bar, in pixels.
/// </summary>
SM_CYHSCROLL = 20,
/// <summary>
/// Width of the arrow bitmap on a horizontal scroll bar, in pixels.
/// </summary>
SM_CXHSCROLL = 21,
/// <summary>
/// Nonzero if the debug version of User.exe is installed; zero otherwise.
/// </summary>
SM_DEBUG = 22,
/// <summary>
/// Nonzero if the left and right mouse buttons are reversed; zero otherwise.
/// </summary>
SM_SWAPBUTTON = 23,
/// <summary>
/// Reserved for future use
/// </summary>
SM_RESERVED1 = 24,
/// <summary>
/// Reserved for future use
/// </summary>
SM_RESERVED2 = 25,
/// <summary>
/// Reserved for future use
/// </summary>
SM_RESERVED3 = 26,
/// <summary>
/// Reserved for future use
/// </summary>
SM_RESERVED4 = 27,
/// <summary>
/// Minimum width of a window, in pixels.
/// </summary>
SM_CXMIN = 28,
/// <summary>
/// Minimum height of a window, in pixels.
/// </summary>
SM_CYMIN = 29,
/// <summary>
/// Width of a button in a window's caption or title bar, in pixels.
/// </summary>
SM_CXSIZE = 30,
/// <summary>
/// Height of a button in a window's caption or title bar, in pixels.
/// </summary>
SM_CYSIZE = 31,
/// <summary>
/// Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border.
/// </summary>
SM_CXFRAME = 32,
/// <summary>
/// Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border.
/// </summary>
SM_CYFRAME = 33,
/// <summary>
/// Minimum tracking width of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message.
/// </summary>
SM_CXMINTRACK = 34,
/// <summary>
/// Minimum tracking height of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message
/// </summary>
SM_CYMINTRACK = 35,
/// <summary>
/// Width of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within the rectangle defined by SM_CXDOUBLECLK and SM_CYDOUBLECLK for the system to consider the two clicks a double-click
/// </summary>
SM_CXDOUBLECLK = 36,
/// <summary>
/// Height of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within the rectangle defined by SM_CXDOUBLECLK and SM_CYDOUBLECLK for the system to consider the two clicks a double-click. (The two clicks must also occur within a specified time.)
/// </summary>
SM_CYDOUBLECLK = 37,
/// <summary>
/// Width of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of size SM_CXICONSPACING by SM_CYICONSPACING when arranged. This value is always greater than or equal to SM_CXICON
/// </summary>
SM_CXICONSPACING = 38,
/// <summary>
/// Height of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of size SM_CXICONSPACING by SM_CYICONSPACING when arranged. This value is always greater than or equal to SM_CYICON.
/// </summary>
SM_CYICONSPACING = 39,
/// <summary>
/// Nonzero if drop-down menus are right-aligned with the corresponding menu-bar item; zero if the menus are left-aligned.
/// </summary>
SM_MENUDROPALIGNMENT = 40,
/// <summary>
/// Nonzero if the Microsoft Windows for Pen computing extensions are installed; zero otherwise.
/// </summary>
SM_PENWINDOWS = 41,
/// <summary>
/// Nonzero if User32.dll supports DBCS; zero otherwise. (WinMe/95/98): Unicode
/// </summary>
SM_DBCSENABLED = 42,
/// <summary>
/// Number of buttons on mouse, or zero if no mouse is installed.
/// </summary>
SM_CMOUSEBUTTONS = 43,
/// <summary>
/// Identical Values Changed After Windows NT 4.0
/// </summary>
SM_CXFIXEDFRAME = SM_CXDLGFRAME,
/// <summary>
/// Identical Values Changed After Windows NT 4.0
/// </summary>
SM_CYFIXEDFRAME = SM_CYDLGFRAME,
/// <summary>
/// Identical Values Changed After Windows NT 4.0
/// </summary>
SM_CXSIZEFRAME = SM_CXFRAME,
/// <summary>
/// Identical Values Changed After Windows NT 4.0
/// </summary>
SM_CYSIZEFRAME = SM_CYFRAME,
/// <summary>
/// Nonzero if security is present; zero otherwise.
/// </summary>
SM_SECURE = 44,
/// <summary>
/// Width of a 3-D border, in pixels. This is the 3-D counterpart of SM_CXBORDER
/// </summary>
SM_CXEDGE = 45,
/// <summary>
/// Height of a 3-D border, in pixels. This is the 3-D counterpart of SM_CYBORDER
/// </summary>
SM_CYEDGE = 46,
/// <summary>
/// Width of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. This value is always greater than or equal to SM_CXMINIMIZED.
/// </summary>
SM_CXMINSPACING = 47,
/// <summary>
/// Height of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. This value is always greater than or equal to SM_CYMINIMIZED.
/// </summary>
SM_CYMINSPACING = 48,
/// <summary>
/// Recommended width of a small icon, in pixels. Small icons typically appear in window captions and in small icon view
/// </summary>
SM_CXSMICON = 49,
/// <summary>
/// Recommended height of a small icon, in pixels. Small icons typically appear in window captions and in small icon view.
/// </summary>
SM_CYSMICON = 50,
/// <summary>
/// Height of a small caption, in pixels
/// </summary>
SM_CYSMCAPTION = 51,
/// <summary>
/// Width of small caption buttons, in pixels.
/// </summary>
SM_CXSMSIZE = 52,
/// <summary>
/// Height of small caption buttons, in pixels.
/// </summary>
SM_CYSMSIZE = 53,
/// <summary>
/// Width of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels.
/// </summary>
SM_CXMENUSIZE = 54,
/// <summary>
/// Height of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels.
/// </summary>
SM_CYMENUSIZE = 55,
/// <summary>
/// Flags specifying how the system arranged minimized windows
/// </summary>
SM_ARRANGE = 56,
/// <summary>
/// Width of a minimized window, in pixels.
/// </summary>
SM_CXMINIMIZED = 57,
/// <summary>
/// Height of a minimized window, in pixels.
/// </summary>
SM_CYMINIMIZED = 58,
/// <summary>
/// Default maximum width of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message.
/// </summary>
SM_CXMAXTRACK = 59,
/// <summary>
/// Default maximum height of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message.
/// </summary>
SM_CYMAXTRACK = 60,
/// <summary>
/// Default width, in pixels, of a maximized top-level window on the primary display monitor.
/// </summary>
SM_CXMAXIMIZED = 61,
/// <summary>
/// Default height, in pixels, of a maximized top-level window on the primary display monitor.
/// </summary>
SM_CYMAXIMIZED = 62,
/// <summary>
/// Least significant bit is set if a network is present; otherwise, it is cleared. The other bits are reserved for future use
/// </summary>
SM_NETWORK = 63,
/// <summary>
/// Value that specifies how the system was started: 0-normal, 1-failsafe, 2-failsafe /w net
/// </summary>
SM_CLEANBOOT = 67,
/// <summary>
/// Width of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins, in pixels.
/// </summary>
SM_CXDRAG = 68,
/// <summary>
/// Height of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins. This value is in pixels. It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.
/// </summary>
SM_CYDRAG = 69,
/// <summary>
/// Nonzero if the user requires an application to present information visually in situations where it would otherwise present the information only in audible form; zero otherwise.
/// </summary>
SM_SHOWSOUNDS = 70,
/// <summary>
/// Width of the default menu check-mark bitmap, in pixels.
/// </summary>
SM_CXMENUCHECK = 71,
/// <summary>
/// Height of the default menu check-mark bitmap, in pixels.
/// </summary>
SM_CYMENUCHECK = 72,
/// <summary>
/// Nonzero if the computer has a low-end (slow) processor; zero otherwise
/// </summary>
SM_SLOWMACHINE = 73,
/// <summary>
/// Nonzero if the system is enabled for Hebrew and Arabic languages, zero if not.
/// </summary>
SM_MIDEASTENABLED = 74,
/// <summary>
/// Nonzero if a mouse is installed; zero otherwise. This value is rarely zero, because of support for virtual mice and because some systems detect the presence of the port instead of the presence of a mouse.
/// </summary>
SM_MOUSEPRESENT = 19,
/// <summary>
/// Windows 2000 (v5.0+) Coordinate of the top of the virtual screen
/// </summary>
SM_XVIRTUALSCREEN = 76,
/// <summary>
/// Windows 2000 (v5.0+) Coordinate of the left of the virtual screen
/// </summary>
SM_YVIRTUALSCREEN = 77,
/// <summary>
/// Windows 2000 (v5.0+) Width of the virtual screen
/// </summary>
SM_CXVIRTUALSCREEN = 78,
/// <summary>
/// Windows 2000 (v5.0+) Height of the virtual screen
/// </summary>
SM_CYVIRTUALSCREEN = 79,
/// <summary>
/// Number of display monitors on the desktop
/// </summary>
SM_CMONITORS = 80,
/// <summary>
/// Windows XP (v5.1+) Nonzero if all the display monitors have the same color format, zero otherwise. Note that two displays can have the same bit depth, but different color formats. For example, the red, green, and blue pixels can be encoded with different numbers of bits, or those bits can be located in different places in a pixel's color value.
/// </summary>
SM_SAMEDISPLAYFORMAT = 81,
/// <summary>
/// Windows XP (v5.1+) Nonzero if Input Method Manager/Input Method Editor features are enabled; zero otherwise
/// </summary>
SM_IMMENABLED = 82,
/// <summary>
/// Windows XP (v5.1+) Width of the left and right edges of the focus rectangle drawn by DrawFocusRect. This value is in pixels.
/// </summary>
SM_CXFOCUSBORDER = 83,
/// <summary>
/// Windows XP (v5.1+) Height of the top and bottom edges of the focus rectangle drawn by DrawFocusRect. This value is in pixels.
/// </summary>
SM_CYFOCUSBORDER = 84,
/// <summary>
/// Nonzero if the current operating system is the Windows XP Tablet PC edition, zero if not.
/// </summary>
SM_TABLETPC = 86,
/// <summary>
/// Nonzero if the current operating system is the Windows XP, Media Center Edition, zero if not.
/// </summary>
SM_MEDIACENTER = 87,
/// <summary>
/// Metrics Other
/// </summary>
SM_CMETRICS_OTHER = 76,
/// <summary>
/// Metrics Windows 2000
/// </summary>
SM_CMETRICS_2000 = 83,
/// <summary>
/// Metrics Windows NT
/// </summary>
SM_CMETRICS_NT = 88,
/// <summary>
/// Windows XP (v5.1+) This system metric is used in a Terminal Services environment. If the calling process is associated with a Terminal Services client session, the return value is nonzero. If the calling process is associated with the Terminal Server console session, the return value is zero. The console session is not necessarily the physical console - see WTSGetActiveConsoleSessionId for more information.
/// </summary>
SM_REMOTESESSION = 0x1000,
/// <summary>
/// Windows XP (v5.1+) Nonzero if the current session is shutting down; zero otherwise
/// </summary>
SM_SHUTTINGDOWN = 0x2000,
/// <summary>
/// Windows XP (v5.1+) This system metric is used in a Terminal Services environment. Its value is nonzero if the current session is remotely controlled; zero otherwise
/// </summary>
SM_REMOTECONTROL = 0x2001,
}
}
}

Now I was able to remove one set of magic numbers from Quakk. I run Quakk on an old Treo 700w. The Treo has a 240x240 screen. If you tweet using Quakk on a 240x240 device the system displays a horizontal scroll box. Quakk made some incorrect assumptions about screen size. I was able to fix the horizontal scroll bar problem with some minor code changes. In that same code, Quakk makes some assumptions about the font size and placement of the input boxes. The correct way to fix that is to call the SHGetUIMetrics to get the current system font size. SHGetUIMetrics is not available without using a P/Involk. I found one article with the sample code.

I thought I would make a few changes. I did, but it was a lot harder than it should have been.


Sunday, June 7, 2009

Technical Challenge of Multiple CPUs

One of the biggest technical challenges in developing software is taking advantage of multiple CPUs. Processor speed has basically stalled. Intel and AMD are putting more and more CPUs into the same chip. Right now dual and quad core chips are becoming common. If you are talking two years away, then by Moore's Law, you will be seeing eight or more cores in most systems. If it is three years away, you could be seeing sixteen or more cores.

Currently, only very high end systems have multiple GPUs. We had one system at a company I used to work for that had four GPUs (all very high end stuff doing medical imaging). But just like CPUs, multiple GPUs are going to be more and more common.

The challenge of writing code that supports multiple processors working in parallel is the real challenge. Some argue that current computer languages do not support that well. In my experience, threads (which are supposed to be light weight processes) do not scale well on multi-core CPU systems. We had a Java application with six main threads running on a system with two dual core chips (total of 4 cores) and we saw almost no performance gain for that application over running on a single core CPU. The system performed better because the system basically gave one CPU to the SQL server and another to the OS, but our multi-threaded application did not get any faster. You could blame that on Java, but putting the blame there does not solve the problem. Also we had similar problems with a multi-threaded application written in C++. The current state of compiler and operating system support for multiple CPUs is limited.

Right now I am drooling over the new Alienware M17x. You can get a laptop with a quad core CPU and dual GPUs. That would be a good replacement for aging Alienware laptop. It has been a great system, but it is getting old.

I hope that the operating system and programs will take full advantage of the 16 CPUs and 8 GPUs I hope to have in the computer I hope to have in a couple of years.

First Impression of Windows Mobile 6.5 Developer Tool Kit

I downloaded and installed the Windows Mobile 6.5 Developer Tool Kit. My first impression is yawn. I am putting a lot of emphasis on Windows Mobile but I found the 6.5 developer tool kit to be a big disappointment. The tool kit includes two new features: gesture API and widgets.

Personally, I think the gesture API is a yawn. I don't mind using a stylus. I have a nice set of pens that can print in black, red, pencil, or act as a stylus. People don't complain about using a pen on a piece of paper; why do they complain about using a stylus on a device? With a multi-function tool that can act as a pencil, pen, or stylus, I don't have to put the tool down to use a phone or PDA. I will have to play with the gesture API, but at this point it is just a yawn.

My first thought about widgets was so what? My second thought was about the same. The only reason widgets are at all interesting is they point out the capabilities of the new browser included on Windows Mobile 6.5. It is too early for me to tell, but that may be a reason alone to upgrade to 6.5. The only thing that worries me is the example widget posted by Microsoft does not use cascading style sheets or JavaScript. The "hello world" example makes me worry that the support for CSS and JavaScript may still be a little lacking. I will wait until someone else spends the time and effort documenting what works and what does not before do anything serious with widgets. One interesting thing about widgets is Microsoft actually points to the W3C standard for Widgets. A Google search about Widgets pulls out this gem: Apple threatens to block W3C widget standard. I am not worried that Apple's attempt to block the W3C will have any impact on Microsoft. After all, Microsoft will do what it has always done, create a non-standard way. But this time Microsoft could say, "Don't blame us, Apple forced us to."

The 6.5 tool kit screams, "I was pushed out quickly!" A lot of documentation about 6.5 on the MSDN site is missing. I found several broken links just trying to find out what was new. Another thing that reinforces that is the DRK or Developer Resource Kit will not be available until July. Microsoft is going to charge $9.99 for the DRK. I was going to order a copy. However the MSDN order site asked for my credit card without using a secure web page. The page does not display the little lock icon in IE8. This is probably another bug caused by pushing out the release. Until Microsoft fixes this, I will not put my credit card information into an unsecure web page. I discourage anyone from ordering the DRK until you can order it from a secure web page.

Unless you are hot for the gesture API or want to explore the capabilities of the new browser there is little need to download the Windows Mobile 6.5 Developer Tool Kit.

Friday, June 5, 2009

Converting Campaign Cartographer Files to XAML Revisited

I have spent a lot of time working with Campaign Cartographer 3, Adobe Illustrator CS, Corel Draw 12, and Expression Blend 3. I finally came up with a solution on how to create a XAML file from Campaign Cartographer 3. CC3 will export a Windows Metafile (.emf). Adobe Illustrator CS sometimes has problems with these files. The solution is to open the .emf file in Corel Draw and save the result as an Adobe Illustrator file. This also offers the opportunity to convert all the text to curves. Adobe is very proprietary about fonts. Converting text to curves fools Adobe Illustrator and you have no more issues with fonts, at the cost of a bigger file.

After saving the file as an Adobe Illustrator file from Corel Draw you need to load the file into Adobe Illustrator and save it out again. Expression Blend 3 will not load the files created by Corel Draw. Adobe Illustrator adds "[converted]" to the file name when it saves the file.

Now you can load the converted Adobe Illustrator file directly into Expression Blend. You may need to do a few transformations to move and scale the map but it works.

If you export something small from CC3, then you must scale it up in Corel Draw. Full maps work without the need to scale it up.

Thursday, June 4, 2009

Why Windows Mobile?

One of the questions I always get when I present the business concept for JSM Software is "why did you choose Windows Mobile?" Some are even less subtle and ask, "Why not develop for the iPhone instead?" They usually follow up with the story about how a friend of a friend made a lot of money selling some application on the iPhone.

Anecdotal evidence is not a good reason to start a company. I know a friend of a friend that won the lottery. It makes as much sense spending all my time, effort, and money trying to win the lottery as it does trying to make a lot of money creating applications for the iPhone. Both have the same anecdotal evidence.

I am trying to build a company, not win the lottery. I worked for a company that tried to "win the lottery". They came up with wonderful ideas that would change the entire company. None of it ever came to fruition. I want to emulate the conservative playbook of Woody Hayes, "three yards and a cloud of dust". Another description was "crunching, frontal assault of muscle against muscle, bone upon bone, will against will." Paraphrasing Woody Hayes, "a company will not succeed unless they regarded the challenge positively and would agree to pay the price that success demands of a team."

My business philosophy is simple: I want to grow a dedicated customer base by continually creating quality products. Sure I would like to make a lot of money. Everyone does. I will only focus on a market I know will provide adequate compensation for my effort.

One reviewer wrote me, "The iPhone market is so oversaturated with bad games, it's unbelievable." The vast number of cheep bad games put tremendous downward pricing pressure. Rick Storm wrote in his blog The Incredible App Store Hype, "The hype surrounding the iPhone App Store continues to persist." Rick Storm has an application is listed as #34 on the social networking chart. According to his blog that makes him a little over $20 per day. That is a little over $7000 per year if sales continue at that rate. That is not a lot of money to me.

Owen Goss documented his success with his game Dapple on his blog. Owen Gloss wrote about developing applications for the iPhone, "...I suspect we'll see fewer and fewer stories about people getting suddenly very rich." (The Numbers Post (aka Brutal Honesty)). Owen Gloss spent $32,000 developing Dapple and made a total of $535 in revenue. Playing the lottery sounds like it has a lot better odds than that. I fully agree with Owen Gloss, "My hope is that we'll start seeing more developers putting out quality titles in the hopes of gradually growing a sustainable business." Owen Gloss strongly implies developing games for the iPhone is not currently a sustainable business.

This reminds me of a stanza from one of my favorite poems, "The Gods of the Copybook Headings" by Rudyard Kipling:

With the Hopes that our World is built on they were utterly out of touch.
They denied that the Moon was Stilton; they denied she was even Dutch.
They denied that Wishes were Horses; they denied that a Pig had Wings.
So we worshiped the Gods of the Market Who promised these beautiful things.

I hear a lot of people worshiping the Gods of the Market in the form of praising the iPhone App Store.

Before deciding on Windows Mobile I did a lot of research. This is something it appears many jumping into the fray of developing software for mobile devices do not do. Denise Marcus, a friend of mine, always said, "Do the numbers." I have always been amazed at how many people fail to do the numbers.

What are the numbers? According to wmpoweruser.com (Windows Mobile hits 50 million lifetime sales ) Microsoft has sold over 50 million Windows Mobile devices. Of that, approximately 30 million are currently in use. These numbers make sense. According to Gartner, Microsoft has been selling over 4 million windows mobile devices every quarter since 2007 (Gartner Says Worldwide Smartphone Sales Reached Its Lowest Growth Rate). Most mobile contracts are two years long. 4 million per quarter times 4 quarters per year times 2 years equals 32 million. The 30 million number may be a bit low, but it is a reasonable starting point.

According to Entertainment Software Association 36% report they play games on a wireless device such as a cell phone or PDA (Essential Facts About the Computer and Video Game Industry). That means that 10.8 million Windows Mobile Users play games. The Entertainment Software Association also said that 7.6% of people who play games play role playing games. Conservatively the market for the type of games created by JSM Software is eight hundred and twenty-one thousand (821,000). If JSM Software reaches a one half of one percent market penetration, 0.5%, the sales projection is four thousand one hundred units (4,100).

My budget for creating a game is about $20,000. That means I need to make about $5 per unit sold. That does not include all the overhead costs in addition to the $20,000 budget. The interesting point is the average price of a role playing game for Windows Mobile on Handango is about $20. After crunching the numbers and using the wonderful spreadsheet provided by SCORE I determined I could make a living if I sold the game for $15 and sold a total of about 4,100 units over the lifespan of the game which I estimated to be one year. I bounced these numbers off of the CEOs of two other game companies. One CEO said my figures were "spot on".

Owen Goss said he needed to sell 9,150 units of Dapple before he would break even. I leave it to the reader to figure out what percentage of the market Dapple would require to break even. I am pretty sure it would be much larger than 0.5%.

The thing that puzzles me the most is why some people are so adamant I should develop for the iPhone? It seems they are trying to evangelize me to the iPhone religion. They believe all the hype and anecdotal stories. My choice to develop for Windows Mobile is an informed decision based on research. I am not embarking on creating a company based on anecdotal stories.