Friday, July 06, 2007

Still Recovering

A new HP Compaq 6710b business notebook arrived at work the other day. It was very shiny, had plenty of grunt, and was preloaded with Vista... apparently. Somehow, during the excitement, the notebook was turned on for the first time and then the lid was closed again before Windows had started. We didn't want to go through the initial setup just then, we had more important things to do.

Later, the time finally came to setup the new notebook and install and configure all the usual goodies. Unfortunately, just after the BIOS POST and before Vista started loading, we were greeted with an Vista boot loader error message: "\windows\system32\winload.exe could not be loaded because the application is missing or corrupt". All other options in Windows Boot Manager lead to the same result and no amount rebooting was going to help.

The answer to this problem, as described on the Boot Loader error screen, is to boot from the Windows installation disc. However HP like many OEMs today, do not ship any CDs with the hardware. To get the recovery disc you would normally burn them after setting up Windows for the first time (Catch-22) or order them from HP (takes about three business days).

Next idea: to be able burn the recovery discs after setting up Windows, HP must, like other brand notebooks, have the recovery images on the hard drive in a hidden partition. I downloaded the user guide from the HP website to find out how to use the recovery images on the hard drive. Option 1, run the HDD based recovery tool from the Start Menu (uh...) or Option 2, press F11 while booting to start the recovery tool without Windows. Excellent.

F11, F11, F11, F11,... doesn't work. POST screen lists others but not F11. Googling suggests that the HP boot-time recovery tool is not a BIOS feature but a boot loader on the recovery partition and the active partition is set wrong if F11 doesn't work. Ok, what is the easiest way to change the active partition on a non-booting PC?

We booted from a Windows XP install disc to use the Windows Recovery Console. XP install couldn't detect a hard drive in the notebook and refused to go any further. We created a bootable floppy with a USB floppy drive on an XP machine and copied diskpart.exe to it. Diskpart requires the full Win32 environment to work. We created a bootable Windows ME boot floppy but FDISK is unusable on drives larger than 137GB.

Lastly, we waited for the Ultimate Boot CD to download from a very slow mirror and we got Ranish Partition Manager running on the notebook. Ranish showed the notebook's hard drive correctly as a 160GB drive. It also showed that there was a single 40GB active partition formatted as NTFS and the rest of the drive was unpartitioned. Bugger.

We are now waiting for the recovery discs to arrive in the post from HP. I'm guessing that the guys at HP who setup the initial Vista image for this notebook range forgot to leave the recovery partition intact. Just goes to show though, shut down your PC properly.

 Tuesday, July 03, 2007

Spend More

Ferrari I've always maintained an interest in the current PC hardware scene. I like to keep abreast of the performance, prices, and problems with the various components available. I've built many PCs for myself, my friends, my employer, and even registered a business and sold a few to the public.

Understandably people often ask for my opinion when they are looking to buy a PC for themselves. I'm very very slowly coming to the realisation that I need to stop "helping" these people. Most of the time I have recommended components or systems that I have personally owned but even then their experience isn't necessarily the same as mine and then I feel responsible when it doesn't work out.

I have stopped operating my personal business and now I pay retail for all my hardware instead of going to wholesalers. I have also stopped building my own PCs and my last three purchases have been big name, off the shelf computers. It just isn't worth my time anymore to save a few bucks wherever I can.

From now on, my advice to myself, and to anyone else who asks, is to spend more. Looking for a new computer, LCD monitor, or video card? Spend more. Not everyone can afford it, it's not going to give you the best grunt for your money, but it sure has saved me a lot of time messing around. It's also a lot more affordable than buying the cheap option only to discover it sucks and you need to buy the expensive model too.

 Monday, July 02, 2007

Dreams and Mistakes

Firstly, in my recent post about the new .Net DateTimeOffset class I mentioned that I would love to see the SQL Server team include this type in databases. My wishes have been answered, we can expect to see this type and some other very interesting additions in the next CTP/Beta of SQL Server 2008. Unfortunately, all of our clients have bought into SQL Server 2005 and won't be interested in upgrading anytime soon so I'll have to find a new project to try all the new toys.

Secondly, also in a recent post I complained about the CollectionBase type being left behind when generics were added to .NET 2.0. I've since discovered the new Collection<T> class tucked away in the System.Collections.ObjectModel namespace. It doesn't offer all the events that the previous equivalent did but it is inheritable and overridable so it should do the job nicely. I obviously didn't search very hard for it all the other times I looked; very embarrassing.

Death, Taxes and Software

Tax Calculator The new 2007/2008 financial year has begun and as promised the Australian Taxation Office released the latest version of their e-tax software on July 1st. As I have for the past several years, I downloaded and installed the software and have started entering my income and deductions for the last 12 months.

When the official paperwork arrives, I'll confirm all my figures and submit my tax return electronically and receive my rebate usually within a week, deposited directly to my bank account. Considering the complexity of the income tax system, the software is excellent for non-accountant-types to complete their own tax return.

Unfortunately, e-tax 2007 is still stuck in the obsolete Windows administrator user world. Installation defaults to "c:\etax2007\". It has been over twelve years since Windows 95 was released and the standard was set for software to install into Program Files.

A single e-tax installation on a PC allows multiple people to fill in and submit their tax return, saving their work in progress locally until it is ready to send. However, the software assumes the user is an administrator and writes the *.tax progress file to the installation folder instead of Documents & Settings.

At several stages throughout the questionnaire, summaries and important details are presented to the user with a recommendation to print the information. However, the software always uses the default printer with the default settings, offering no dialogs, and only picking up changes to the default printer after restarting the software.

One of the biggest reasons why e-tax is so great is because the questions are presented in easy to understand language. Whenever more detail is required there are always hyperlinked keywords or a help button leading to a more extension definition with examples. Sadly, it's all useless under Vista because they've stayed with the deprecated WinHelp format for the documentation.

Lastly, for users of Apple computers (and presumably other OSes), the official solution is to use virtualization. I wonder if the purchase price of VMWare or Parallels and a Windows licence can be claimed as a cost of preparing the tax return.

By all appearances e-tax is a full Win32 application, probably written in C++ at first glance, and is expected to continue in that style for the majority of users next financial year too. Perhaps by 2009, they will have moved to a web-based client, which will open the system to non-Windows users but probably introduce other problems along the way.

 Wednesday, June 27, 2007

Ecstatic About NStatic

Ecstatic MascotWesner Moise is getting ever closer to public release of his very promising NStatic static analysis tool for .NET. In general static analysis tools are very expensive but as part of Wes' plans, a lower price to achieve market penetration is most likely. In fact, until he finds a suitable publisher he expects to selling independently for a few months, during which time we might be lucky to pick it up for a "bargain" price.

So far I think NStatic only supports C# 2.0 but there are plans to add support for C# 3.0 features and maybe VB.NET too if the demand is there. I, for one, sure hope that VB support becomes a reality, I think our current suite of software could really benefit from some in depth analysis.

Keep a close eye on Wesner's blog for the latest information.

DasBlog Flip Flop

A few months ago I upgraded this web site from the DasBlog 1.8 installed by my ISP to the latest version at the time, 1.9.6. It was remarkably easy to merge my web.config and site.config files and upload all the new binaries.

Yesterday Scott Hanselman announced DasBlog 1.9.7 had been released. Last night I tried to upgrade again, following a very similar procedure as I did the last time. Being a point release, I expected even less effort and was happy to find that very little merging was required with the config files.

Unfortunately, once I had uploaded the new files to my site I found I could no longer log in. I refreshed the browser several times, edited and uploaded the siteSecurity.config file several times and tried the default file with the admin/admin credentials. Nothing would let me login and all I had was a SecurityFailure message in the event log.

This took an hour or so and I eventually gave up and completely restored the backup I made before attempting the upgrade. Guess I'll have to configure IIS locally and experiment until it works.

On a better note, Scott says this is the final release for ASP.NET 1.1 and another release due very soon will be completely ASP.NET 2.0 and support Medium Trust. I was annoyed last time I downloaded the source and discovered that I would need to install VS2003 to work with it but finally I'll be able to contribute to the project.

 Tuesday, June 26, 2007

DateTimeOffset Is The New DateTime

SundialJustin Van Patten neatly summarises the new DateTimeOffset class introduced in .NET 3.5. In short, this new class combines the year, month, blah, blah, second storage of the DateTime with a time zone offset. The most important point to take from Justin's article is that apart from a few exceptions (which he describes), you should always use DateTimeOffset in new code instead of the old DateTime.

Naturally there will continue to be situations where you need to pass a DateTime but the DateTimeOffset will always be able to scale back to suit. It is much harder to infer time zone information from a DateTime to provide a DateTimeOffset. I'd love to see the SQL Server team introduce this data type concept to databases.

CollectionBase and Generics

In .NET 1.1 the Framework included an abstract class System.Collections.CollectionBase. The idea was that you could extend it to create your own custom collections to hold certain types. The Add, Remove, and other methods were overridable (to perform object validation or filter duplicates) and several events also existed to enable listening for changes.

Cardboard Box Most importantly it provided the mind-numbing mapping from the IList, ICollection and IEnumerable interfaces to the internal storage mechanism (which happened to be an ArrayList). When I created a new collection derived from CollectionBase I could override the OnValidate method to only accept a certain type and I was done.

Sadly, I'm left stranded in my .NET 2.0 world with Generics and an untyped CollectionBase. I cannot inherit from List<T> because none of it's methods are virtual and none of it's fields are protected. Ultimately, I'm stuck with writing my own class with a private List<T> field and coding most of the methods on the various interfaces as redirections to the private field. No thanks, that was one of the biggest reasons for moving from VB6 to .NET.

Interestingly, the SharePoint fellows noticed the same problem with CollectionBase's obsolescence in .NET 2.0, and cleverly decided to provide the more up-to-date CollectionBase<T>. Of course, not only did it end up in the Microsoft.SharePoint.Publishing assembly that I'm reluctant to reference and probably unable to distribute, but they also implemented only ICollection and IEnumerable<T>. I was dumbfounded that IList<T> and ICollection<T> had been missed and that they had also removed IList.

Why am I still forced to code this junk myself?

Windows Vista, UAC, Flame On!

If you are running Windows Vista and are bothered by "too many" UAC dialogs on a regular basis to the point that you want to turn UAC off, the problem is that you are futzing with your PC instead of doing real work.

 Saturday, June 23, 2007

Crashing Visual Studio Unit Testing

Yesterday I managed to crash vstesthost.exe, the program that runs Visual Studio Unit Tests when you press Ctrl+Shift+X. A few tests in my suite would run and pass, then BAM, fatal error. I ran the tests again, this time in debug mode and the tests broke into the debugger with a StackOverflowException, due to a poorly implemented interface in a mock object.

According to some searching, some exceptions including StackOverflowException, just cannot be caught in .NET 2.0 and I'm not sure it would be smart to try. Unfortunately when it happens in testing, the whole suite fails. In my case, I was able to pave over my mistake in the code and move on with my life.

The vstesthost crashing problem also happens when an exception is through on a secondary thread though. Testing asynchronous UI or background processing code could also kill the process when any exceptions occur, and these might be expected exceptions for a particular tests.

I haven't needed to use it yet, but there is a workaround to avoid the whole test suite falling over. It involves editing the vstesthost.exe.config file to enable the legacy unhandled exception policy as used by the earlier CLR versions. You will need to be careful to synchronise your threads though to ensure any exceptions are assigned to the correct test in the results.

 Friday, June 22, 2007

Feature Suggestion For DotNetKicks

DonkeyGavin Joyce announced a few months ago that the DotNetKicks community website will be going open source. Gavin has since created a DotNetKicks project on Google Code with some placeholders and has asked for people interested in contributing to join. One thing that isn't clear is whether the engine will be open source for others to build their own sites or if all the updates will get deployed back to DotNetKicks.com.

Regardless, I already have one idea in mind. In a moment of complete clumsiness, while trying to quickly submit a post to DotNetKicks before going to bed, I associated the wrong Title and Description with the wrong Url. Unfortunately, even though I had submitted the item, I was unable to correct the Title or Description and I was unable to delete the submission altogether and start again. I unkicked the post back to zero kicks but that didn't help.

My suggestion therefore, is that the submitter of an article should be able to delete that submission. Perhaps, to be safe, it could be restricted to only allow deletion if no one else has kicked it.

Until then, I'll just have to live with looking stupid for my story on DotNetKicks which, strangely, someone other than me has kicked anyway.

Drive By PowerShelling

I have been using an external USB hard drive to take backup copies of certain files on several machines. Each machine has different drive configurations though so the USB drive will be assigned different drive letters on each machine.

I could have found an unused drive letter common to all the machines and assign it to USB drive on the first use but that's no fun. I decided to do it the PowerShell way. I wrote a small function to find a System.IO.DriveInfo object by providing the volume label and then I can get the drive letter and pass it to Copy-Item to do the work.

function Get-DriveInfo ([string] $label = $(throw "Please specify a volume label.")) { 
   [System.IO.DriveInfo]::GetDrives() | ? { $_.IsReady -eq $True -and $_.VolumeLabel -match $label }
}

 Wednesday, June 20, 2007

Beware The Evil Shadow

Evil Shadow Object-oriented programming principles have been an excellent addition to software development but one component that inevitably appears in OO languages has confounded me by it's uselessness. In VB.NET it is known as the "Shadows" modifier, in C# it is found in class member declarations sharing the name "new".

The purpose of this modifier keyword is to allow a subclass to redefine a property, field, or method of the base class where the base class has not been declared "Overridable" or "virtual" in VB.NET or C# respectively. Unfortunately it suffers from a major drawback, as demonstrated by the following code:

class Base
{
   virtual public string Extendable() { return "Extend"; }
   public string Locked() { return "Lock"; }
}

class Foo : Base
{
   override public string Extendable() { return "Food"; }
   new public string Locked() { return "Picked"; }
}

Base b = new Base();
b.Extendable(); // returns "Extend"
b.Locked(); // returns "Lock"

Foo f = new Foo();
f.Extendable(); // returns "Food"
f.Locked(); // returns "Picked"

Base bf = new Foo();
bf.Extendable(); // returns "Food"
bf.Locked(); // returns "Lock" !!!

As you can see, if the Foo methods are called via a Foo-typed variable, there is no difference between shadowing and overriding. However, as soon as you call a Foo method via a Base-typed variable, or pass a Foo instance to another class expecting a Base, you lose the functionality of Foo.

If "new" is omitted from Foo's implementation of Locked, Visual Studio reports an error: The keyword 'new' is required on 'Locked' because it hides method 'Base.Locked()'. It is very easy for someone to simply add the keyword as required with realising the consequences.

Occasionally, all you might want to do is utilise some existing behaviour in a base class and add some more features and shadowing or member hiding is fine. The fact that you have used shadowing is not obvious in the calling code though.

Most of the time, I want to alter the behaviour of a base class and pass my new subclass to existing code, perhaps in the Framework, that is only expecting the base type. Beware.

Waste Management

The script in my last post for removing old files from the temporary folder is only necessary because so many applications don't clean up after themselves. Hopefully, if the applications you are developing are doing the right thing they will be using in memory streams where ever possible. Only write to disk when absolutely necessary, creating random temporary files in the environment temp folder, not program folders with restricted access to non-admin users:

string myTempFile = System.IO.Path.GetTempFileName();

However, remembering to track and delete these files when you are finished requires more effort and is often ignored, creating the ever growing temp folder problem. There is a lesser known class in the framework that can help you though:

var myTempColl = new System.CodeDom.Compiler.TempFileCollection();
string myTempImageFile = myTempColl.AddExtension("png");

Excuse the C# 3.0 syntax in the last snippet, I hate the redundancy of repeating long type names, especially on the same line. When you have finished using all the temp files you created with the TempFileCollection, you can dispose it explicitly, automatically deleting the files, or if you're really lazy, let the GC take care of it.

myTempColl.Dispose();

PowerCleaning

I've often wanted to easily delete all old files below a folder that haven't been modified for a while. I've written a very small PowerShell function to do just that. By default it emulates the Disk Cleanup tool in Windows and deletes all files older than one week from the environment temp folder.

function Remove-TemporaryItems ([string] $path = ($env:TEMP), [TimeSpan] $age = (New-Object System.TimeSpan 7, 0, 0, 0) ) {
    $files = Get-ChildItem $env:TEMP -recurse | `
        Where-Object { ! $_.PSIsContainer -and $_.LastWriteTime.Add($age) -le [DateTime]::Now };
    $files | Remove-Item;
    $files;
}

 Tuesday, June 19, 2007

Malware And Least Privilege, Secure Enough?

Jeff Atwood had some trouble with malware last week. His digging led him to blame a particular website for infesting his system. In a comment on his post, I proposed, based on my experience, that simply running as a non-administrator user instead on his clean unpatched Windows XP SP2 installation should have protected him for the most part.

I'm not suggesting that patching is a low priority but from my (potentially outdated) understanding of malware attack vectors, running as a least privileged user would have gone a long way. I tried to find some good websites to verify my assumptions but didn't have much luck. What follows is my interpretation of the situation, please leave a comment if I have underestimated the capabilities of today's malware.

  • Ethernet connector virus figure Most malware wants to get installed on your PC and survive a reboot: A non-admin user only has privileges to write to "safe" areas of your file system and registry. Malware would be unable to replace commonly used system files. It would be unable to install itself as a driver or service with higher privilege. It would be unable to schedule itself to run when another user logs on. It would be unable to place shortcuts in an area that another user would see in their profile. Lease privilege users cannot install browser plugins. System level root-kits should be unable to hook in and a reboot with a Live CD should be able to see and remove anything evil.
  • Most malware wants to provide remote access to your PC: XP SP2 ships with the firewall enabled. Malware would be able to phone home but would be unable to open a port and await incoming connections. Modern broadband routers naturally prevent incoming connections too. The malware would still only be able to give the remote user least privilege access to the system.
  • Most malware wants you to give it something: As a non-admin malware would not be able to modify your drivers/etc/hosts file to redirect network traffic. It would be able to spawn many popup windows attempting to sell you something but this would be nothing more than annoying. It could scan your user documents for email addresses but hopefully your contact list is online (eg Gmail) or in Outlook (which warns the user when accessed programmatically). It could log key presses and grab sensitive passwords, which is definitely a concern, but this may be reduced by the "remember my password" features in software.

Jeff's situation was an extreme example of an unprotected system. Personally, I'm using Vista 64-bit which immediately reduces the amount of malware that is actually compatible. I'm also running non-admin with UAC on so anything questionable needs my permission. I have Internet Explorer 7 which displays the Information Bar whenever something wants special permission. Data Execution Prevention and ASLR are on by default to minimise exploitation of buggy system code. I still have Windows Defender and run Ad-Aware occasionally. Every installed application is patched to the latest update. Lastly, I avoid questionable material and have another separate non-admin user account if I really need to try something.

I'm sure I'm not 100% safe, but I don't think that's currently attainable. Any machines I remove malware from for friends get returned with a non-admin account and they only come back to me with more problems after sheepishly admitting they went back to an admin account. I have read that the new hardware-virtualization features in new CPUs (which I have enabled) could allow malicious code, and then there is everything else I haven't heard of.

I think I've rambled enough and probably missed many things but I'm interested in reading your thoughts on the matter. If you can recommend a good source for the latest PC security information I'd appreciate that too.

 Monday, June 18, 2007

ClickOnce and Terminal Services

Under just the right conditions that I have been lucky enough to meet, .NET applications deployed by ClickOnce will not start under a Terminal Services session. At the heart of the problem is this error message:

Shortcut activation from http/https or UNC sources is not allowed.

I could not find anything in Google, on the MSDN forums or in the Microsoft Support Knowledge Base. With some trial and error and a little reflection I've tracked it down to this very special combination:

  • ClickOnce offline install mode is enabled
  • and the application is started via the Start Menu shortcut
  • and the user is logged into a Terminal Services session
  • and Terminal Services is redirecting the Start Menu to a UNC.

Changing any one of these conditions is enough to avoid the problem and would probably explain why it is documented anywhere. The error message is triggered by code in the System.Deployment assembly and it it cannot be overridden by a system setting either.

Redirecting the Terminal Services Start Menu to a UNC is also a common practice when running multiple terminal servers, or a shared Start Menu for all users (as was my case).

I will be recommending users simply start the apps via the same ClickOnce deployment URL that was used for the initial install and try to disable TS folder redirection where possible.

It seems ClickOnce uses the shortcut location later in the bootstrap process and the problem exists in Orcas too so I don't think Microsoft will be fixing this one.