Welcome to the adventure

Ink for Word preview video

Tuesday June 27, 2006

I’ve finally released a video of what I’m working on. No longer will the question “what are you up to?” be answered with vague references to “digital annotation” and hand-waving explanations of “reflow.” The product is called Ink for Word, and it’s an addon to Microsoft Word that introduces some cool Tablet PC related functionality. More info and a video are at inkforword.com.

Hopefully this application can complement some of the other third party applications for enhancing Office with Tablet PC functionality. Two of the most notable are Josh Einstein’s Tablet Enhancements for Outlook and Loren Heiny’s InkGestures for Word.

Right now we have support for standard ANSI proof-reading marks for research purposes, but I think we’ll transition the editing features to use Tablet PC gestures. They’re more recognizable for users and a lot easier to code.

Ink for Word has been covert for awhile, but now that it’s online, I’ll start writing about the development experience of writing a huge addin to Word and dealing with the Tablet PC SDK. It’s been an interesting ride so far! I’ve written it as a Visual Studio Tools for Office addin for ease of debugging, but we’ll be transitioning to a standard COM addin before release because VSTO v2 doesn’t allow you to deploy application-wide addins. VSTO v3 looks promising in that department, but it looks like it will only include application-wide support for Office 12. Blast! That’s a shame because VSTO rocks. We’d love to keep using it to develop our application.

Piracy

Friday June 23, 2006

What could be more fun than egregious villainy? Arr!


These seas have buried the souls of men
In contention 'tween water and sky.
But across them our vessel does easily wend;
By the row o' th' crew our hull runs high.

This ship is my birth, my voyage craft
On unbounded roads where sky's the path.
Towards plunder and gold sail we fast–
Our greed compels the force of our wrath.

What now – a shore, full and ripe to pluck!
Two shots o' th' cannon to sound our way.
“Flee from my steel and you'll live with luck;
The night is ours, we sail with the day!”

Men make lives for me to tear down;
Why do they build and not steal with their hands?
“Gather up slaves, the rest of 'em drown;
Take what we want, leave nothin' to stand!”

Behind my stern one shot to part,
My lust unquenched, for more we start!

Getting the latest Tablet PC SDK with InkAnalysis

Thursday June 22, 2006

I’m developing an application that makes use of the new InkAnalysis API, and as a result I end up installing the beta Tablet PC SDK on quite a few machines. I can never produce the Microsoft website to get the SDK (it’s one of those websites that “cannot be found except by those who already know where it is”), and googling results in a modicum of information. Well, no longer!

Over the past few months the InkAnalysis bits have been moved around and distributed in a variety of fashions. Currently as of June, they’re bundled with the Windows Vista SDK (some call it .NET 3.0 — it was formerly known as WinFX). You can get the whole package here from Microsoft:

Windows Vista SDK Beta 2.

When installing, make sure you check off the bits for “Mobile devices”; it didn’t occur to me that the Tablet PC stuff was only for Mobile devices.

I would recommend uninstalling all other Tablet PC SDKs. The installer for the new Windows SDK will make you uninstall any old Windows SDKs first.

When all is said and done, surely you’ll want to reference the new InkAnalysis stuff in a build or from within Visual Studio. The library’s location is not obvious. Depending on which SDK you had installed, the managed dlls used to be in something like

c:\program files\microsoft sdks\Mobile PC and Tablet PC\Include\Microsoft.Ink.dll

but they now live in

c:\program files\reference assemblies\Microsoft\Tablet PC\v1.7\

You’ll want to include Microsoft.Ink.dll, Microsoft.Ink.Analysis.dll, and a certain “IALoader” which on my system lives in:

C:\Program Files\Microsoft SDKs\Windows\v1.0\Bin\IALoader.dll

IALoader is used by the InkAnalyzer. My application built fine without a reference to it, but at runtime when I called BackgroundAnalyze on an instance of InkAnalyzer, I got the following FileNotFound exception:

Could not load file or assembly 'IALoader, ...' or one of its dependencies. The system cannot find the file specified.

And there you have it. Getting the latest Tablet PC bits has always been a troubling experience, and I hope its inclusion with Vista will make distribution more consistent from now on.

Some useful links:

“Analyze this” - great overview article on using Ink Analysis, with some code, by Markus Egger

Microsoft.Ink Windows SDK beta 2 online docs

Readonly ranges in Word! Yaaargh!

Tuesday June 20, 2006

One major gripe I have with the Word object model is that I can’t assign to the Range properties of objects to move those objects around. Objects that I wish I could move around include Shapes (not inline shapes), and XmlNodes.

If floating shapes could be moved around, well, that might just make my year. The product I’m working on, Ink for Office, would really love to store its ink as shapes in Word and let Word do all the redrawing/reflowing. We need to use floating shapes because inline shapes take up space in the document. Unfortunately, once you programmatically insert a shape into a document, you can’t anchor it to anything (VSTO doesn’t even provide this API, but the Word’s interop assembly does!). If I could assign the Range property on a Shape and have the floating shape anchor to that range, that would be phenomenal.

XmlNodes have the same problem (both VSTO controls and the Word.Interop.XmlNode class). Their Range properties are read-only, and manipulating the Range with Collapse or Move doesn’t do squat. To change the location of an XmlNode in the document, as far as I know you have to destroy it and create a new one. Yech.

So that’s exactly what I’m doing, with the XmlNodes at least… I’m destroying and inserting new XmlNodes all over the place, which makes the undo history look quite strange. A small hole in functionality like unmoving XmlNodes can really take a long time to work around, and unfortunately the Word object model is riddled with them.

Getting a Linux shell on Windows - Cygwin & rxvt

Sunday June 18, 2006

I do a lot of development on Windows (I love Visual Studio), but I try to spend most of my time on Linux, because I love the usability of the Gnome desktop and the power of its development and CLI tools. So I’ve gotten into this habit of trying to make my Windows XP machine act much like my Linux/Gnome desktop. How am I doing that? So far, it includes getting a unix shell and associated programs running in Windows, and emulating the awesome hotkey and window management I get with Gnome and Metacity. I’ll write a series of posts on how to get this stuff set up.

First is Cygwin. Cygwin is a drop in unix shell environment (it supports X libraries too) which allows you to run unix binaries built for Cygwin and use the wonderful command shells, like bash, in Windows. Cygwin is here and is fairly easy to get going, if you can wade through the blindingly frustrating usability nightmare that is their setup.exe

These are useful apps I always forget to select in setup.exe, as they’re not selected by default, so if you need them, check them off:
nano
openssh
subversion
cvs
rxvt

The real challenge is getting a usable terminal emulator to run Cygwin programs in. Cygwin, by default, opens cmd.exe, which is the Windows command prompt. command.exe is notorious for being quite possibly the worst terminal emulator ever developed. To this day it’s still styled like a Windows 95 window, because it’s skinned using some arcane pre-GDI (?) window border. You have to bring up a dialog box to resize it horizontally, it will not accept most control key combinations and the cutting and pasting leaves much to be desired.

Thankfully it’s easy to replace. You can use the terminal that comes with putty modified for use with Cygwin, or you can use rxvt, which is what I use. rxvt can be installed through Cygwin’s setup.exe, and will be installed to C:\cygwin\bin\rxvt.exe

rxvt is not a pretty program, but it works adequately. The first order of business is to get it to launch your Cygwin environment and to start in your home directory.

In Cygwin, I have my home directory set up as c:\documents and settings\reformist, which is also my home directory for Windows (%userpath%). It makes things easier having them be both the same directory. To do this, while in Cygwin, I symlinked /home/reformist to /cygdrive/c/documents and settings/reformist

With that setup, you can fire up a cygwin environment with rxvt using this command:
C:\cygwin\bin\rxvt.exe -e c:\cygwin\bin\bash.exe --rcfile "~/.bashrc"

Notice I start the bash shell, and I also tell bash to look for my rc file in my home directory. Here’s the contents of my .bashrc for windows:

cd ~
export INPUTRC=$HOME/.inputrc
export EDITOR=nano
PS1='[u|W]$'
PATH=/usr/bin:$PATH

What’s up with that PATH variable? On some of my Windows installs Cygwin (or bash, or rxvt) won’t include /usr/bin in the path, so I add it manually. Strange, I know.

The other thing of note is the INPUTRC line. This is used to ensure that rxvt picks up my home and end keys correctly and does the right thing with them. Here is the .inputrc file I use for rxvt, which resides in my home directory (%userpath%):

# Home Key
"e[7~":beginning-of-line

# End Key
"e[8~":end-of-line

# Delete Key
"e[3~":delete-char

# Insert Key
"e[2~":paste-from-clipboard

The next order of business is to change the assinine default of rxvt to put its scrollbar on the LEFT side of the window, and instead make it show on the right. I also like to change a few display properties, like the title rxvt shows. You can do all of this by putting a .Xdefaults file in your home directory. Here’s mine:

          rxvt*title:             Bash
          rxvt*foreground:        black
          rxvt*scrollBar_right:   true
          rxvt*colorBD:           1
          rxvt*font:              courier
          rxvt*saveLines:         10000
          rxvt.backspacekey:      ^?

And with that, you should have the unix CLI tools at your disposal, usable through an adequate terminal emulator.

References:
Cygwin Bash Shell

Windows Update gripes

Saturday June 17, 2006

What’s with Windows Update taking so many cycles to get my system fully up to date? I just did a few Windows installs and it felt like a broken record of bad usability, doing this crap over and over again.

First you have to navigate to the site through Internet Explorer, and if it’s your first time, you have to give permission (I think twice) to _install_ the latest version of the Windows update software, including “giving trust” to Microsoft.com. Uh, Microsoft, you couldn’t special case this site for us? I mean you hard coded a “Windows Update” menu item into IE’s menubar, and you couldn’t hardcode the answers to these trust questions? (Yes, Microsoft, you made my OS so go ahead and install more on top of it).

Second, they give you a batch of about 40 security updates on a fresh install. I download and install them, fine, but then I have to go back to Windows Update after my system has rebooted (of course) to find MORE UPDATES, as if they couldn’t give them to me all at once. Even if you require multiple restarts for some horrible reason, at least send my computer a list of updates that it still needs to get, and install them, so I don’t have to do this restart and then go back to Windows Update cycle 3 times. Horrible! This is one thing that Linux destroys MS on. Apt and Portage can calculate thousands of package dependencies and install them at once (not in three cycles!), usually without a reboot, unless it’s a kernel upgrade. And even then it doesn’t _force_ you to reboot like Microsoft does!

Amazon.com’s shipping for return items is dang awesome

Tuesday June 13, 2006

I wanted to send back this book I didn’t like and was fearing having to justify my return to someone at Amazon, getting an RMA number, taking it to the post office to mail it, and then paying shipping.

Amazon has a really nice interface for returns, and I selected the item I’m sending back and the reason within seconds. They immediately gave me this label to print out and put it on the box. I’ve never seen anything like it, but maybe that’s because I don’t use the mail much. Check it out:
rml-mediamail.gif

All I have to do is slap this thing on the front of the box, and I can hand it to my mailman. The post office calculates the shipping and sends it to its destination. When Amazon gets it, they subtract the shipping amount from my refund. I don’t have to go to the post office or mess with rates or pay shipping up front.

I love this service!

Checks at the grocery checkout

Saturday June 10, 2006

Today I was hustling through the grocery store, picking up a few choice items like a fiend, because honestly, I really had to get home and go to the bathroom. I cleverly scouted the checkout lines and beat a few mid day shopping pros to the punch. Much to my satisfaction, I chose the line that was not the shortest but progressed the fastest. With my credit card ready to slide and a pen in hand, I waited for the cashier to finish with the lady in front of me and ring my stuff up.

Then she pulls out her checkbook. I watch in dismay as she starts writing the check _well after_ everything has been rung up, instead of preemptively addressing it to Safeway and writing the date. She quibbles over the price of an item while she’s writing, and hands the check to the cashier who just looks at it. He requires ID, and she rummages through her purse to find it. All of the other lines quickly progressed past mine, and my opportunity for a speedy checkout evaporated. I sat breathing anxiously, mere inches from her face, as the cashier slowly wrote her driver’s license on the check, then slid the check into the paper reader, then keyed her driver’s license number into the machine. I watched as a 5 year old who probably didn’t know addition sped through the custom checkout machine while I waited for the cash machine to process her check (who is it talking to!? what is it verifying?).

Finally she got out of my way before my bladder and wrath exploded upon her person.

The first order of business if I ever make it into office will be to decree a public flogging for anyone who attempts to use checks at the checkout line and has the audacity not to start writing it until every item is in a bag.

Remember the position of your Windows Forms (with code)

Saturday June 10, 2006

A core usuability principle is that applications should have good memory. One way to do that is to remember the visual settings and position given to your app by the user. In System.Windows.Forms (SWF), Forms do not remember their last position, and open in a default location every time. This can get annoying.

Here is some simple code without extra cruft to get the job done. It involves saving the position of the form into a file when the form is closed, and restoring that position the next time the file is opened. This toy example saves the program config file in the user’s application data folder (c:\Documents and settings\philc\Application Data\MyApp\config.xml on my computer).

When restoring form position, the form might be off screen because of resolution changes. You probably don’t want to restore a form off screen, where the user can’t see or move it, so there’s some code there to move the form on screen. Give it a try.

This code should also work on systems with multiple monitors.


// Author: Phil Crosby
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

public class Form1 : Form
{
    public Form1()
    {
        this.Load += new EventHandler(Form1_Load);
        this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        LoadConfigFile();
    }

    /// 
    /// Load the application config file and restore form position
    /// 
    private void LoadConfigFile()
    {
        TextReader reader = null;
        Rectangle formBounds = Rectangle.Empty;
        try
        {
            string configFilePath = System.IO.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                @”MyApp\config.xml”);

            // If configuration directory doesn’t exist, create it.
            string configFolder = Path.GetDirectoryName(configFilePath);
            if (!Directory.Exists(configFolder))
                Directory.CreateDirectory(configFolder);

            reader = new StreamReader(configFilePath);
            // Coordinates of the form’s rectangle should be on the first line.
            RectangleConverter converter = new RectangleConverter();
            formBounds = (Rectangle)converter.ConvertFromString(reader.ReadLine());
        }
        finally
        {
            if (reader != null)
                reader.Close();
        }
        if (formBounds != Rectangle.Empty)
        {
            // Get the working area of the monitor that contains this rectangle
            //  (in case it’s amulti-display system)
            Rectangle workingArea = Screen.GetWorkingArea(formBounds);

            // If the bounds are outside of the screen’s work area, move the
            // form so it’s not outside of the work area. This can happen if the
            // user changes their resolution and we then restore the application
            // into its position — it may be off screen and then they can’t see it
            // or move it.
            if (formBounds.Left < workingArea.Left)
                formBounds.Location =
                    new Point(workingArea.Location.X, formBounds.Location.Y);
            if (formBounds.Top < workingArea.Top)
                formBounds.Location =
                    new Point(formBounds.Location.X, workingArea.Location.Y);
            if (formBounds.Right > workingArea.Right)
                formBounds.Location = new Point(formBounds.X -
                    (formBounds.Right - workingArea.Right),
                    formBounds.Location.Y);
            if (formBounds.Bottom > workingArea.Bottom)
                formBounds.Location = new Point(formBounds.X,
                    formBounds.Y - (formBounds.Bottom - workingArea.Bottom));

            this.Bounds = formBounds;
        }
    }
    void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        // Save form position to file, so we can restore it later.
        RectangleConverter convert = new RectangleConverter();
        string formPosition = convert.ConvertToString(this.Bounds);

        TextWriter writer = null;
        try
        {
            string configFilePath = System.IO.Path.Combine(
             Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            @”MyApp\config.xml”);

            // If configuration directory doesn’t exist, create it.
            string configFolder = Path.GetDirectoryName(configFilePath);
            if (!Directory.Exists(configFolder))
                Directory.CreateDirectory(configFolder);

            writer = new StreamWriter(configFilePath);
            writer.Write(formPosition);

        }
        finally
        {
            if (writer != null)
                writer.Close();
        }
    }
}

The Four Steps to the Epiphany review

Wednesday June 7, 2006

I recently purchased Steve Blank’s The Four Steps to the Epiphany (first edition), a book about bringing a product to market. I wasn’t too satisfied with the book, and certainly didn’t agree with the other reviews with claims like “MUST READ” and “ignore it at your peril.” So I wrote this somewhat scathing review:

Not worth reading (1/5 stars)

I’ll say up front that I didn’t make it very far into this book. I usually finish everything I buy, but I forced myself to cut my losses and throw this one away.

The first thing you’ll notice about the book is the shabby editing; it’s very budget. While the paper and cover are cheap, what’s worse for the reader is the poor editing. It looks like this book was thrown together in a few hours on a plane ride somewhere. I groaned immediately upon reading the first two pages of the book. Here are two excerpts:

“Most entrepreneurs travel down the startup path without a roadmap and that no model or template could apply to their new venture.”

“While no one was actually quite that good, but some VCs had ‘golden guts’ for these kinds of operating issues.”

While there are typos in the book, they can be forgiven since it’s clear there was not a full time editor. The real issue is that the English becomes so broken in places that you can’t even infer what the author means; the statements become incomprehensible.

And you’ll be disappointed by the diagrams in this book — my three year old could finger paint better diagrams with a bottle of jam. In fact, the famous bell curve from Crossing the Chasm is reproduced here, and it appears the image was scanned from a crumpled up newspaper article into a 10×10 two color image. 95% of the diagrams are a horizontal line of boxes with arrows pointing left to right, from one box to another. After awhile these diagrams begin to lose their meaning.

Would the book be worth reading if it got a better publisher? I don’t think so. The author clearly has a lot of great real world experience as a serial entrepreneur, and I’m sure he’s fun to listen to, but that does not necessarily mean he can synthesize the wisdom he has effectively into book form. His writing is not compelling or interesting, and the book is written as if he wrote a giant outline and filled in each box separately. Literally. Each chapter is broken down by “Phase 1, Point 2: A, B, C” etc., which gets very tiresome.

The message in the book is good, but it’s not new, nor does it really take 202 pages to explain. The author develops his message in a laborious and tedious fashion that will make you feel like you’re being repeatedly dragged through something you grasped in the first ten pages.

While this book is quite general in its application, I think much more interesting and convincing presentations of similar subject matter have been made in “The Inmates are Running the Asylum” by Cooper (Customers first, interaction design process) and Crossing the Chasm.

I could give it a few more stars if it were affordable enough to buy and simply flip through, but it’s $40. This book is not worth the cheap paper it was printed on.

Somehow it managed to get removed from Amazon.com’s product page.

While I didn’t care for the book, Steve Blank turned out to be a very nice fellow. After I posted the review, he emailed me directly asking if I’d like to read a draft of a second edition he’s working on, or if I’d like a refund. That at least was a pleasant surprise.