Friday, June 30, 2006

How to rescue a Delphi project

Delphi has been around a long time and there is a lot of Delphi code around but there aren't so many people around to work on it anymore. Developers are moving onto more modern technologies. To me it looks like the people who continue to maintain this code aren't always the most technically proficient so due to this and the fact that the code is getting long in the tooth means projects are becoming a bit of a mess. These days if I'm asked to look at some Delphi application, it is invariably in a bit of a bad state. So how to deal with this situation? How can these ill projects be rescued? These are the steps I've been taking with the latest bit of code I've been asked to look at. First up, I added all the source to source control. Without source control, you're doomed. There are plenty of source control products around, many of them free. I've been using SourceGear Vault, because it's free for a single user and does averything I need. Next, I attempted to compile the project. The main problem here was libraries I didn't have. Fortunately these were all available free, so I could compile it quite easily. Now it was time to see what the code was actually like. Unsurprisingly it was a bit of a mess. Compiling with hints and warnings on generated several hundred warnings and this was before I noticed somebody had put the {$WARNINGS OFF} compiler directive in several files... Warnings are there to help and can generally be fixed pretty easily, so don't hide them! Fixing these errors took some time but helped to learn about the code. I'd recommend removing all code that is never called and all commented out code, there is no point learning about code that is never actually called. And it's always recoverable from source control. Also searches through the project that throw up commented out code are generally pretty annoying. Another great tool for finding problems in Delphi code is Pascal Analyzer, which finds lots of things that the compiler will miss. Even the trial version has enough functionality to be useful. Reading the code can give you clues about a few things as well. Given that the developers of this code had a habit of leaving in lots of commented out code, my guess is they didn't use any source control. I'm also guessing they started work on this a long time ago, with lots of pointer based operations and references to WinTypes and WinProcs (which if I remember correctly was removed after Delphi 1). So this is where I'm at now. What I need to do now is take this Windows application and convert some parts of it into a web service. This is where it could get interesting...

Tuesday, June 20, 2006

What is System.RuntimeType?

I was trying to get the metadata for a query coming back from SQL Server. I'm not interested in the data, I just wanted to know what the columns were in a particular table. So I was executing a query like so - 'SELECT * FROM blah WHERE 1=0'. When I executed it, I took the DataReader returned and used GetName to get the names of the columns and GetFieldType to find out the types. Perhaps there is a better way to do this but I'm unaware of it. But weirdly, GetFieldType returned System.RuntimeType for every column. I thought WTF is that? A quick Google then a quick Yahoo and quick MSN didn't show up anything useful. The only thing I could find was the comments from the MS Rotor source which said

"RuntimeType is the basic Type object representing classes as found in the system. This type is never creatable by users, only by the system itself. The internal structure is known about by the runtime. __RuntimeXXX classes are created only once per object in the system and support == comparisions."

But this still wasn't much help. So I thought I'd have a hack around. The reason it isn't documented and doesn't show in many searches is because it's an internal class, which makes it a bit surprising I'm seeing at all. But it does have a useful property called UnderlyingSystemType that returns the type I'm interested in. Of course because it's internal I can't access that property. The way round this is via the best thing since sliced bread, reflection. So here is the litle snippet of code I came up with to do just that.
object val = reader.GetFieldType(index);
Type runtimeType = val.GetType();
PropertyInfo propInfo = runtimeType.GetProperty("UnderlyingSystemType");
Type type = (Type)propInfo.GetValue(val, null);

Update - As mentioned in the comments (only took me three years to respond!), this code is actually pointless. The thing I hadn't noticed is that RuntimeType inherits from Type, so although it isn't possible to deal with an instance of RuntimeType directly, you can just treat it as an instance of Type instead.

Sunday, June 18, 2006

The construction of a disco shed

Here are some photos of the construction of my disco shed. I'm very pleased with the final outcome and I learnt a few things on the way. First I discovered that air-raid shelters are very difficult to pull down, especially when the bolts are all rusted in. Cutting through them with a hacksaw takes a flipping long time. Then I learnt that laying a concrete slab is a pretty big job. When I calculated I needed 68 bags of ballast (which is sand mixed with gravel) I thought I'd made a mistake. In fact it turned out I actually needed more. A cement mixer was pretty much essential as well. Also, getting the base level is quite important. Mine is a little bit out so my chair rolls down the slope when I'm sat at my desk. Not so bad that I fly out the door, but if I'd made more of an effort to get the base exactly level I wouldn't have the problem.
Finally, a disco ball is absolutely essential for the modern disco shed...

Thursday, June 15, 2006

The story of an SL-1210

When I was 17, my main ambition in life was to own two Technics SL-1210s and be a world famous DJ. The SL-1210 is a design classic. It has been around in one form or another for over 30 years and it is built to last. Everything about it is industrial strength, except the tone arm which by its nature has to be pretty fragile. The most impressive thing is when you lift up the platter and there isn't any kind of belt, just what looks like a magnet and some coils. I think this was the first direct-drive record deck and although it has been imitated many times, the SL-1210 is still the de facto standard in the world of DJing. But this design comes at a cost. When I was looking to buy one, they cost £400. I scrimped and saved and finally got together the money. In fact I only paid £360, since I was paying in cash. But I only had one, which was pretty useless when you want to be a DJ. Which is where Ali comes in. Ali was a friend of mine at school. I don't remember when he told me he was HIV positive but it was pretty soon after meeting him. He was a haemophiliac and had contracted HIV from a contaminated clotting factor injection, before testing for HIV had begun. The government had compensated all those who had contracted HIV, so Ali was a well-off young man, though one with a potentially terminal illness. So Ali bought himself two Technics decks and even got them put in flight cases, for the professional DJ look. We weren't great friends at shool but we ended up at the same university (Newcastle) doing the same degree so ended up becoming good friends. We also started DJing together, after getting an amp and some very big speakers. We were a good pairing, he did bang bang dance music and I did Indie pop with some mainstream pop music. When I finished uni after four years, Ali had missed a year due to illness and was still trying to finish his degree off. He never got the chance to though. I last saw him during the Christmas holiday of '94. He was in bed and was unable to come out for Christmas drinks, but I presumed it would be another passing illness, like the ones in the past. But not long after he was dead. At his funeral, Ali's dad told me that Ali had left me his decks. After leaving uni, DJing had dried up, not least because Ali wasn't around to get the contacts, since he was always much more gregarious than me. But I obviously wasn't going to say no. So now I had three decks, which was too many even if I was still DJing. So I gave my SL-1210 to another of Ali's friends and kept the other two for myself. Time went on and the DJing thing was obviously never going to happen so I gave one of the decks to my brother Simon, with the proviso he didn't sell it on eBay. And the other one has been mostly been doing nothing but gather dust for the last ten years. CDs and MP3s have replaced records in my life. And now I have a shed and space to spare, so out has come the SL-1210. I cleaned it up and threw on one of my ten-year old records and the deck still works perfectly. So thank you Technics and thank you Ali.

Saturday, June 10, 2006

HTTPS and stupid error messages

Ever seen this dialog box appear in Internet Explorer? Chances are you have. And guess what, most people who see it don't have a clue what it means and just get scared that the website they are on isn't as secure as they thought it was. And know what else? It's wrong most of the time when it appears. It will appear when there is a standard link to a non-secure page. Yeh, the other page may not be secure but the user isn't looking at any content from that page. Since it will appear whenever there is a link to a non-secure page, it's very easy to accidentally add stuff to your page that will cause this to show up. I wonder how much time has been wasted by developers getting rid of this? And IE7 doesn't fix it either...

Wednesday, June 07, 2006

Server-side view state

There was a reason for adding the user-agent string to my ASP.NET error handling code, some errors are browser specific. One bug that has been biting me is view state getting corrupted. View state is a big chunk of base-64 encoded data that gets passed from the server to the browser in a hidden field. The browser does nothing with it (or at least it shouldn't) except pass it back to the server in a post-back. Unfortunately it seems some bug in FireFox causes the data to get corrupted for some of our pages which then causes our app to blow up when the data gets posted back. But more weirdly, there doesn't seem to be any mention of this bug when I Google for it. The conspiracy theorist in me thinks this may have something to do with the geek community not liking to say anything bad about FireFox, but it's more likely that this is is just a very uncommon bug. Anyhoo, there seems to be a pretty good fix for this. This article describes how to store view state server-side. Not only does this solve the problem, it also reduces page size quite dramatically. Of course the downside is that server memory usage is increased.

Monday, June 05, 2006

Handling errors in ASP.NET

It would be nice if my sites never crashed, but unfortunately they occasionally do. First off I don't want users to see the ugly ASP.NET error page, so I add this to web.config. <customErrors mode="RemoteOnly" defaultRedirect="error.html"> <error statusCode="404" redirect="index.aspx" /> </customErrors> I redirect to a HTML page, just in case ASP.NET is so ill it can't display an ASPX page (although whether it will be able to redirect at all is open to question). The exception to this is 404 errors which are redirected to the home page. The code below is what I use to handle unexpected errors. This is added into global.asax. Some people will say log errors to the event log but I prefer logging to the database because it's easier to configure. By default, the ASP.NET user can't write to the Application event log. You can set up your own event log, but again this requires some configuration. Most projects have a database back-end, so I just need to add another table. I also send out an email so if there is a serious problem, I get notified pretty quickly. Note, the error also includes the full URL so if a test server or development machine starts sending out error emails, it's clear it's not a real problem. You could also configure this from web.config. Update - Now logs more information about the error, such as the type of browser making the request and any session data. Any objects being stored in session data must have a sensible ToString() implementation
public static void LogError(string errorMessage)
{
// log error to database
using (SqlConnection connection = new SqlConnection())
{
connection.ConnectionString = ConfigurationSettings.AppSettings["connectionString"];
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "INSERT INTO Log VALUES (GETDATE(), @Error)";
command.Parameters.Add("@Error", errorMessage);
command.ExecuteNonQuery();
}
}

// send email
SmtpMail.Send("webserver@initech.com", "doogal@doogal.co.uk", 
"IniTech web server information", errorMessage);
}


protected void Application_Error(Object sender, EventArgs e)
{
// log exceptions
Exception ex = Server.GetLastError().GetBaseException();

StringBuilder errorMessage = new StringBuilder();
errorMessage.AppendFormat("An unexpected error occurred{0}", Environment.NewLine);
errorMessage.AppendFormat("Type: {0}{1}", ex.GetType().ToString(), Environment.NewLine);
errorMessage.AppendFormat("Source: {0}{1}", Request.Url.AbsoluteUri, Environment.NewLine);
errorMessage.AppendFormat("Message: {0}{1}", ex.Message, Environment.NewLine);
errorMessage.AppendFormat("Browser: {0}{1}", Request.UserAgent, Environment.NewLine);
errorMessage.AppendFormat("Stack trace: {0}{1}{2}", Environment.NewLine, ex.StackTrace, Environment.NewLine);
errorMessage.AppendFormat("Session data: {0}", Environment.NewLine);
foreach (string key in Session)
{
  string val = string.Empty;
  if (Session[key] != null)
    val = Session[key].ToString();
    
  errorMessage.AppendFormat("  {0}: {1}{2}", key, val, Environment.NewLine);
}

LogError(errorMessage.ToString());
}

Friday, June 02, 2006

Skype rocks

OK, so I'm about 12 months late but I've only just got round to using Skype on a regular basis and it's great. Most importantly it just works. I've had long conversations with people in the US and Australia and it drops out very rarely. Compared to my experiences with Yahoo Messenger (where conversations tended to consist of 'what was that?', 'you still there?', 'I'll call you again, see if it's any better', 'can you type out whatever you're trying to say', 'I give up, I'll call you on the landline') this is very pleasing. Any negatives? Sending files can sometimes be very slow (but this is still better than MSN which sometimes just refuses to accept files) and I can't seem to find a way to search through past chats. And it's written in Delphi, so perhaps there is life in the old dog yet.

Tuesday, May 30, 2006

DCOM from .NET

It's not well advertised but it is possible to use DCOM from .NET. It may not be as popular as the more recent RPC mechanisms but I still need to use it occasionally. So here's some C# code that should do the trick. The COM type library must be registered on the client machine. ComObject is the type of the COM object that you've imported into an interop assembly.
Type type = Type.GetTypeFromProgID(progId, serverName);
if (type == null)
throw new Exception("Unable to find the object, ensure the type library is registered");
Object objTest = Activator.CreateInstance(type);
ComObject comObject  = (ComObject)objTest;

Thursday, May 25, 2006

Apple finally gets it

Apple have always annoyed me. Many many years ago the original Mac was ahead of its time but slowly Windows caught up and eventually the old Mac OS was looking pretty dated. But still the Apple zealots would ramble on about how great Macs were. We had one of the original iMacs but it just wasn't very reliable, even though it looked quite photogenic. Which was another reason for not liking Macs. Even though 95% of the worlds' computers were Windows PCs, every film with a computer always had a Mac. I recently upgraded that old iMac to MacOS X and was quite impressed. Of course the problem was all the software I wanted to run was Windows software so it wasn't much use to me, so it is still languishing in the loft. But first Apple decided to switch to Intel processors (and seem to have admitted in the process that they are much better than the old PowerPC processors). Then they released software to allow Apple computers to run Windows XP, which solves the major problem for anybody coming from the Windows world. And now they've released a laptop costing as little as £749, which solves one of the other major problems with the Mac, the price premium. It's still there but it's much less than it used to be and I have to admit that if I do ever purchase a laptop, I will now consider an Apple. And that iMac in the loft will be moving into my new office very soon.

Sunday, May 21, 2006

A better link: search

I've known for some time that Google lies when I do a link: search to see which sites link to my sites. Even though I know of sites that link to mine, Google doesn't list them. So I was very pleased to discover that it's possible to use @: instead of link: and many more sites are listed, although it still doesn't show some sites I know link to mine.

Saturday, May 20, 2006

An alternative to Environment.NewLine

Looking through my logs is always an interesting way to find out how people end up at my blog. One of the most searched for terms is 'Environment.NewLine alternative'. I'm not entirely sure why that would bring you here but anyway, what alternatives are there to Environment.NewLine? On Windows, Environment.NewLine is simply "\r\n", so you could use that, which would save a few key presses possibly (which is the only reason I can think of for wanting to find an alternative). If you're one of the brave people trying to develop a cross-platform app with Mono, then Environment.NewLine will be "\r" on Linux and other Unix platforms. So depending on what you're trying to achieve you may want to go with Environment.NewLine anyway or you may want to hardcode your newlines to "\r\n" or "\r".

Friday, May 19, 2006

Not Google site: bug

So after looking more closely at what I thought was a bug with Google, it turns out it's not. site:http://www.randompubfinder.com/ returns only the pages in Google's main index, site:http://www.randompubfinder.com returns all pages, including supplemental results. What are supplemental results? Basically pages that might show up in search results if Google can't find anything better. So we now have 4 pages in the main index! Unsurprisingly our hits are way down, since most of our traffic is driven by Google. So why did this happen? It seems that Google now won't store all pages in the main index if your site isn't popular enough. By popular, I mean having lots of inbound links. We don't so we get the big heave-ho. Doing searches now that used to bring up links to us now actually shows less relevant results, so I'm not entirely convinced this is helping improve the user's experience. Somebody at Google has written a fairly lengthy article about the latest updates there, with lots of unhappy people leaving comments. Here's a blog post from somebody in a similar position to ourselves.

Wednesday, May 17, 2006

Weather Bonk

Bonk probably has a different meaning in the US, but other than the strange name, this website is pretty good. I think it's pushing AJAX and Google Maps to its limits, as moving around can get pretty slow, but it has all the weather info you could ever need along with links to webcams. And even better, you can plug it into your own website in about two minutes.

Google site: bug

So there I am panicking because the Random Pub Finder seems to be disappearing from Google and today it got worse. Only 58 pages in the Google index apparently. Then I looked at the search string, site:http://www.randompubfinder.com/ So I tried site:http://www.randompubfinder.com and there are 639 pages. Panic over. So it looks like Google has a bit of a bug in its search engine and in Google Sitemaps, which provides the first URL as a link to tell you how many of your pages are indexed.

Friday, May 12, 2006

SEO made easy

I think I've made a reasonable job of optimising the Random Pub Finder for search engines. Our average hits are over three times what they were before I did any SEO on the site. I've not done anything dodgy and it's cost nothing. At this point I could claim to be a genius or I could tell the truth and just admit to reading this book. There are plenty of guys out there who will do the SEO work for you (for a price), but it's probably cheaper just to read the book. The disclaimer at this point has to be that the rules for search engines are changing all the time, so this book may well be out of date already...

It's a small virtual world

This image shows where the hits to my main website are coming from. I'm blown away by the fact that my crappy little site can attract hits from so many places on earth. OK, people mostly come from the US and Europe, which I guess is due to the higher levels of internet connectivity in those areas, but I've managed to get hits from every continent (OK, if you want to be pedantic I probably haven't had any hits from Antartica but Google Analytics seems to ignore it so I don't know for sure). My guess is that when air travel becomes too expensive for the average man in the street (which will be pretty soon I reckon) this kind of virtual travel will be the best way to see what goes on in the rest of the world.

Thursday, May 11, 2006

The crazy world of Google

A few weeks ago the Random Pub Finder had over 600 pages indexed in Google, pretty much the whole site, then a week ago it was down to just over 200. Now its bounced back to over 300, but where are the other 300? Who knows. The site has hardly changed during that time so I don't think it's anything I've done. The more I learn about search engines, the less sense they make.

Saturday, May 06, 2006

Milton Keynes are relegated

Football isn't generally any kind of morality play, good things don't always happen to good people and vice versa. But it did today. The most disliked team in England were finally relegated to the 2nd division. Why are they disliked? They uprooted the club and moved it across the country to Milton Keynes from South West London. This may be a common occurrence in the US, but franchising of clubs here has never happened here in the past. Why do I care? If they had been successful then they may have been the first of many clubs moving just to get a few more bums on seats and to hell with the club's fans. Not only that, but the club set up by the fans, AFC Wimbledon, is ten minutes down the road from our house. Unfortunately they missed out on promotion this year, but they are still one division closer to their nemesis.

Monday, May 01, 2006

Pennine Lancashire

If you're of a certain age and were brought up in the North West of England, Tony Wilson was probably a big part of your formative years. Not only was he constantly on the local TV news, he also ran one of the coolest record labels of the time and owned the hippest nightclub. Well now he's going to try to help regenerate the rundown parts of East Lancashire. This part of the world is close to my heart and it certainly has some things going for it, it has beautiful scenery, it's very cheap to live there and, OK, I can't think of anything else. Tony certainly has a bit of a challenge on his hands. The towns around East Lancashire have never really recovered from the industrial decline in the latter half of the 20th century. I went to school in Blackburn and of the people I've remained in contact with, only one still lives in the area. My family have also all moved away, so it's no wonder there's a problem with negative equity. I went to a pretty decent school, so all my friends are well educated and probably just the kind of people the area needs to help regenerate it. But they've all moved to well-paid jobs in the South East (except for one friend who's moved to Lancaster, one part of Lancashire that does seem to be doing quite well for itself). That's the main problem Tony needs to solve, getting these kind of people moving back to their roots. Manchester and Liverpool managed to recover from their apparent terminal decline, so I'm sure it will be possible.