Thursday, July 29, 2004

Enjoying MobiPocket and the Argument for Ebooks

Since getting my Smartphone in May, I have been searching for the right reader application for it. I'm a huge fan of electronic books - they are obviously much more portable than their paper equivalent - to put some real numbers on their portability, I've come up with a portability index, which a weight ratio between the ebook and paper book version, I weighed my Smartphone (130g), the SD card that it takes (2g, which stores 1GB of data), and my Apress book (640g). Assuming 5MB storage for my book, I can hold 200 copies of it on my phone (ignoring internal storage), which comes to 0.66g per ebook. So, based on weight, the electronic form would be 970 times more portable (640/.66). Even if you use a laptop as a reader (say the chunky Dell Inspiron 8600 at 3.1kg) and reserving a modest 5GB for ebooks (so you could store 1000 total books), the portability index still comes out a 206 compared to paper. This portability index obviously ignores cost, but as I'd have a phone capable of installing applications and a laptop anyway, cost isn't a relevant factor for me

Back to the Smartphone - I actually find it a great reading surface. All readers have annotation abilities, so I have a virtual (if somewhat slow) pen with me at all times. The device is a lot lighter than a paper book, and the in-built lighting capabilities is great for reading in dim places. As mobiles are a carry-everywhere device for me most of the time, I have the convenience of having a book with me all the time. I was initially really disappointed (and am still pretty disappointed) to find that Microsoft doesn't provide a version of Reader for the Smartphone. It makes a mockery of the marketting spin that porting apps between Windows CE configurations is easy (if it is, why haven't they done it?), and seems to be an ongoing attempt to kill their own product. I was on the review team for Improving .NET Application Performance and Scalability, and my suggestion that a Reader version be made available (in addition to the PDF and HTML version) was summarily ignored.

The reason that I was so keen to get Reader was the largish library of books available from Amazon in Reader format. The PDF library is larger, but secure PDFs aren't supported on the PocketPC version of Adobe Acrobat Reader, and Adobe doesn't have a Smartphone version at all. My first thought was to use a third party reader with no library support, and attempt to work around the security features of books that I bought to get them into a Smartphone-compatiable form. I initially used RepliGo, which comes with a print driver that allows you to print documents to the RepliGo Reader. The reader software is excellent, and I used it to read a few books on the Smartphone that I could print from either Word or Acrobat. After exhausting the small number of books I could process in this manner, I starting trying to get secure PDFs to somehow print to RepliGo. There doesn't appear to be anyway to do this, so I then went in search of a new reader - enter MobiPocket.

MobiPocket is similar to RepliGo from a software perspective, but also has a small but adequate library of titles that are available for the reader. I purchased a copy of Benjamin Franklin - An American Life from MobiPocket (I already had purchased it in PDF form from Amazon), and have been really happy with the reading and licensing experience so far. A book is locked to a maximum of two devices, which isn't too bad considering the ebooks are pretty cheap, and the reader itself is reasonably priced. The reader also supports the consumption of most of the AvantGo feeds, so if you are one of those folks waiting for AvantGo to bring out a Smartphone edition, give MobiPocket a go instead.

I'd love to see more publishers making their books available in electronic format. As a purchaser, I favor books that have an electronic version available, and when choosing between two comparable titles on .NET, the MSPress version will always win out if it has a CHM version available on the accompanying CD-ROM. Getting CHM back to the original HTML source is trivial, and then I usually suck the lot into Word using a macro and print to MS Reader, PDF or RepliGo as required. Working on a client's site (as I do about half the time) generally means that the only technical books that are useful to me are those that are directly relevant to the project (meaning I have lugged them on site), and ebooks. The rest sit at home lonely and unused.

At the moment I'm enjoying Shadow Divers on MobiPocket, and look forward to working my way through a few other titles they have on offer.

Another Tip Thanks to Dan - Making Debugging Easier

Dan (know as .NET Dan to his family and groupies) came up with another great idea that I thought was worth sharing. The project I'm working on at the moment is a validation framework that essentially involves a whole heap of plumbing code to allow strongly-typed rules written in compiled code to check an arbitrary data source. I inherited the project from Mitch, so if its a dumb idea, let him know.

I have been focussed on making the development-time friendliness of the framework better over the last month, and one of the problems we faced is that it can be difficult for a developer to track a validation failure back to a rule. When a rule fails, a particular method is called by the rule to signify the failure. Dan's idea was to output a message to the VS.NET Output window similar to a compilation error, allowing the developer to double-click the message and be instantly transported to the line where the validation failure is signalled. The code to do this is:

if (System.Diagnostics.Debugger.IsAttached){
  StackTrace st = new StackTrace(true);
  for(int ix = 0; ix < st.FrameCount; ++ix){
    StackFrame sf = st.GetFrame(ix);
    if (sf.GetMethod().Name == "Validate")
      string sfMessage = String.Format("{0} ({1}, 0): Validation failed: {2}", sf.GetFileName(), sf.GetFileLineNumber(), message);


I'm obviously looking for the frame in the stack where a method called Validate is but you get the idea. Formatting a stack frame this way makes it automatically navigatable from the Output window.

Tuesday, July 20, 2004

Two Quick .NET Tips for Smoother Team Development

While doing some work with Dan the other day, we both ended up showing each other a hidden .NET feature that, although they both had existed since .NET's release, the other party was unaware of. Given the general usefulness of the features (especially in a team environment), I thought them worthy of a quick post.

Nick's Tip - Config File Overrides

It is not uncommon in team situations for the config file to become a real source of contention, with developers checking in changes that are only relevant for their PC. Also common is the the config file thrashing between test and staging server settings. To avoid this problem, it is possible to locally override appSettings settings in the config file by using the file attribute of appSettings element. The app.config or web.config file that lives in VSS would look something like:

<?xml version="1.0" encoding="utf-8" ?>
 <appSettings file="development.config">
  <add key="DBSever" value="Staging Server Name Here" />

Locally, outside of source control, a developer can (but doesn't have to) create a file called development.config, and override appSettings settings as desired. If this file doesn't exist, the main config file is used. The development.config file would look like:

 <add key="DBSever" value="Local Server Name Here" />

That's it for development.config - there is no other elements like configuration in the file.

As an interesting side story, at one (unnamed) telco where I did some performance consulting earlier this year, the connection details to the real database ended up in VSS during the final stages of a deployment, and when contractor did a get latest and ran a cleansing script that is usually run against the test database, a heap of real data was deleted. While most data was recovered from backups, a contractor ended up being sacked, but it ended up being the wrong guy, so the company had to pay out his contract. The morale: pay attention to config file settings!

Dan's Tip - Setting Up Web Projects from VSS for the first time

Getting a web project from VSS and getting it running on a developer box that it was created on is one of the great challenges of the current Visual Studio.NET release. Visual Studio will attempt to add the file to a folder in the c:\inetpub\wwwroot folder if you simply do a get latest and open a solution containing a web project. This will upset relative references, and is pretty untidy, as you end up with two copies of the files on disk, and two folder where VSS is putting files. To avoid this, do a get latest, map the web folder into ISS with the same vdir name as the original developer used, and then delete the files from the mapped folder. The last stage is critical (and was the missing link that Dan provided) as, if the files do exist, VS will attempt to create a new vdir with an "_1" appended to it, and with the file going to c:\inetpub\wwwroot. Thankfully, Whidbey fixes this problem completely.

Sunday, July 18, 2004

MSDN Masked Edit Control C# Sample Doesn't Work Too Well

I recently used the Masked Edit Control using .NET Framework Regular Expressions with C# sample as the base class for a Textbox control that automatically added data entry masking based on the data type of the column that it was databound to. To be fair to the sample's author, the Masked Edit Control is advertised as only forming the "basis" of a masked edit control, but doesn't go into a lot of detail about what parts of the sample need further development to arrive at a commercial-strength offering.

One part of the sample that is definitely lacking is the way the key press event arguments are used to construct a representation of the contents of the Textbox should the key press be allowed. The sample assumes the user is entering characters in order, doesn't used delete or backspace, doesn't use the clipboard or undo operations, and doesn't highlight any text. For the application I was developing, these assumption were too limiting. and I wrote a small method that added handling for text highlighting, backspaces and insertion at any location in the textbox. The method takes the original Text of the TextBox(this.Text), the new character (e.KeyCode), the caret position (this.SelectionStart), and the length of text selected (this.SelectionLength).

protected string GetSting(string originalString, char newChar, int startSelection, int selectionLength)
 //TODO: undo, delete, cut, copy, paste
 if (Char.IsControl(newChar) && newChar != '\b')
  return originalString; //give up - catch any errors on exit

 if (newChar == '\b') //backspace
  if (selectionLength == 0)//lose char left of selection point (if there is any)
   if (startSelection == 0)
    return originalString;
    string s = originalString.Substring(0, startSelection - 1) +
    return s;
  else//lose selected chars
   string s = originalString.Substring(0, startSelection) +
    originalString.Substring(startSelection + selectionLength);
   return s;
  if (selectionLength == 0)//insert
   string s = originalString.Substring(0, startSelection) +
    newChar.ToString() +
    (startSelection < originalString.Length ? originalString.Substring(startSelection) : "");
   return s;
  else//lose highlighted chars
   string s = originalString.Substring(0, startSelection) +
    newChar.ToString() +
    originalString.Substring(startSelection + selectionLength);
   return s;

The method doesn't handle delete (which doesn't raise a KeyPress event), and clipboard operations. Moving to KeyUp/ KeyDown event handling would allow the full range of input operations to be caught, but is about two orders of magnitude more complex. If you are using this sample, these enhancements will cover about 80% of the masked edit functionality ...

Friday, July 09, 2004

An Exercise in Vanity

I finally saw my book on the shelves of a physical bookstore today. I usually try to resist the urge to actively seek out book stores in an attempt to find my book, mainly because it is slightly disappointing to not find it. Today I was buying Test Driven Development in Microsoft.NET, and, to my surprise, I found my book sitting prominently on the shelf. Apress often doesn't get the decent run it deserves (especially compared to against Microsoft Press), but this Dymocks had a great range of Apress titles.

Well, now I can stop looking ....

Wednesday, July 07, 2004

Running as a local admin - who cares?

There has been a fair bit of hype over the last couple of years about developers not running as local admins. The push has been so successful (from a PR perspective at least) that not running as a local admin has been elevated into the same political correctness stratosphere as aplogising to indigenous populations, vegetarianism, and Michael Moore films.

Before tackling the issue head-on, it is worth stepping back a bit, and looking what achieving good security is all about. Security is an exercise is risk management, and the end goal is all about beating the bad guys at a minimal cost. Accepting some risk is OK - we do it all the time in our real life. Not carrying all your credit cards is more secure, but nearly all of us do it because the risk of being mugged and someone making effective use of all those credit cards is low. We could have our machine disconnected from the network except when we absolutely need a network resource, but this would be a pain, and the risk of being passively compromised on a corporate network is pretty low.

As a developer, not running as a local admin has two aspects - avoiding risk, and writing better software that doesn't need to run as a local admin. Both arguments don't cut it for me.

The risk aspect doesn't make a lot of sense. Firewalls and virus scanners deal with the risk of viruses quite adequately for me. I understand enough about what is and isn't risky behaviour to deal with it. I actually think the reverse proposition gives you better security - when you are engaging in risky activity such as browsing less-than-reputable websites or installing untrusted shareware, use a VMWare or Virtual PC session that you throw out when your done (kudos to Mark Brindle for this practice.) If you're a developer, and you can't work out what behaviour is risky, you're a mug - try a different game, or get some training.

The better software aspect has some merit to it, but if you don't fully understand what you're doing, it can give you a false sense of security. Take event sources - you need to be a local admin to create these, but not to use them. I've watched developers not running as local admin, and their first reaction to "funny" behaviour is to try the same action as a local admin. In the event source creation scenario, the code will now work because the event source can be created, and when they switch back out of local admin, the code will now work. I would argue that a developer's machine is so atypical of an average PC or server, trying to get a feel for security and configuration bugs that a user will experience in mostly a waste of time. Not always, but mostly.

If you have successfully moved to a lifestyle of a non-local admin developer, I admire your patience, and hope you find the trade-offs worthwhile. Please continue as is - I'm not here to tell you to switch back. But don't be too righteous pushing your views down the throats of others.

The Illustrious Leader gets Google Bombed

When it comes to humor, I'm pretty low brow. Therefore, it comes as no surprise that I find the rather childish practice of Google bombing pretty funny, especially when it started as my joke. So, this morning, when I tried, and saw who was as the top, I had quite a good laugh. Thanks Mitch and Mark for your part in elevating the Illustrious Leader to the top of the charts.

Sunday, July 04, 2004

Smartphone Transport Times v0.1 Done!

To those people who emailed and aked me in person how the smartphone app was going (thanks to both of you for your interest), I am happy to announce that the first release is done. Overall, I'm very happy with the finished product - it looks and acts like the other homescreen plug-ins that shipped with the phone, and I have found it useful in working out when the next train is.

The plug-in looks like:

Selecting the plug-in brings up a message box with more info:

The app ships with the timetable for trains between Martin Place and Cronulla, but it's pretty quick to enter your own public transport details (the file is installed to \Storage\Application Data\Home\tt.csv). It took me less than 10 minutes to enter mine. Make sure the data is is 24 hr format, and use the xx:xx format for all times - the parsing is pretty primative.

The timetable file also includes data that nominates how long it takes to get to the transport pick-up spot. If you are too late to catch up transport, but it hasn't left yet, the transport's time of deperature is shown in brackets, as can be seen in the home screen image.
V2 will include support for setting alarms to get you to work or home at a partcilular time, as well as multiple timetable support.

Installation is a simple matter of downloading the HME file, executing it in a file exporer or browser application(using the sytax file://\temp\tpttime.hme, where \temp is the location of the file in this case). Then select Start->Settings->Home, and adjust the Home screen layout option. The application installs five home screen definitions - "Windows Default - TT", "Windows Basic - TT", "Windows Simple - TT", "Large Font - TT" and "Transport Time". The first four are the standard layouts from my Smartphone2 with the Transport Time plug-in added beneath the time. The last layout has the MRU bar, the carrier/date/ time plug-in, and the Transport Time plug-in.

To add the Transport Time plug-in to another home screen layout file, add the following XML to its definition file (it will be called XXX.home.xml, where XXX will be something similar to the layout title shown in the Home screen manager):

<plugin clsid="{0C0F7EDE-B0BB-46e0-82C7-27752D3A3126}" name="Transport Timetable" height="40" refresh="1"/>

Heights of 20 and 40 pixels are supported (I haven't tested anything else), and refresh determines how often the screen is updated (in minutes). 1 is the maximum, but if you are extremely sensitive to battery use, you can bump this up. I've been running at 1 minute refreshes, and haven't noticed any decreased battery life.

PermCalc is Cool

I've been playing around with Beta 1 of Visual Studio 2005, and am happy to report that PermCalc is working fine now. To use it, bring up the security tab for a project, select "Enable ClickOnce Security Settings", select (Custom) as the Zone, and hit the "Calculate Permissions" button. A full static analysis of the project and the code paths that it will call is performed (including dependant assemblies), and a grid will be filled that shows the required permissions for the application, as shown below. A green tick indicates that permission is required, and clicking on the details tab will bring up the details for that permission.

If an application is defined as going out to a particular zone, and the permissions for that zone are less than the application requires, the developer is alerted to the problem:

PermCalc can also be used from the command line, and the description it outputs to the console reads: "PermCalc is a tool that estimates the permissions required by assemblies or public entry-points. If the "-Library" switch is not used, it estimates the permissions that must be granted to each assembly in an application in order to execute with no security exceptions. If the "-Library" switch is used, it estimates the permissions that must be granted to the caller of each public entry-point. (Note that this may not include all the permissions that the library itself must be granted in order to execute.)"

The output generated by the tool is an permission request set in the form of an XML file. An example file is shown below:

<?xml version="1.0" encoding="utf-8"?>

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2">



  <PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom">

   <IPermission class="System.Security.Permissions.FileDialogPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Access="Open" />

   <IPermission class="System.Security.Permissions.IsolatedStorageFilePermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Allowed="DomainIsolationByUser" UserQuota="10240" />

   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, Execution" />

   <IPermission class="System.Security.Permissions.UIPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Window="SafeTopLevelWindows" Clipboard="OwnClipboard" />

   <IPermission class="System.Windows.Forms.WebBrowserPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Level="Restricted" />

   <IPermission class="System.Drawing.Printing.PrintingPermission, System.Drawing, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" version="1" Level="SafePrinting" />


 <defaultAssemblyRequest permissionSetReference="Custom" />