Blog › August 2006 Archives

Desert Island Discs
Apparently Desert Island Discs is the longest running music programme in the history of radio, having been running since 1942. Despite not yet being a celebrity, I thought I'd jot down my choice of music, not forgetting my book and luxury item.
  1. Tonight Is The Night I Fell Asleep At The Wheel
    Performer: Barenaked Ladies
    CD Title: Maroon
  2. Mr Jones
    Performer: Counting Crows
    CD Title: August and Everything After
  3. The One I Love
    Performer: David Gray
    CD Title: Life in Slow Motion
  4. Iris
    Performer: Goo Goo Dolls
    CD Title: Dizzy up the Girl
  5. Nightswimming
    Performer: R.E.M.
    CD Title: Automatic for the People
  6. I Hope That I Don't Fall In Love With You
    Performer: Tom Waits
    CD Title: Closing Time
  7. Who's Gonna Ride Your Wild Horses
    Performer: U2
    CD Title: Achtung Baby
  8. Meditation (from Thaïs)
    Performer: Herbert von Karajan
    Composer: Jules Massenet
    CD Title: Meditation
Record: Achtung Baby
Book: Hearts in Atlantis by Stephen King
Luxury: An unlimited supply of Skittles (the sweets), and a set of false teeth
23 August, 2006 at 21:58 1 Comment
The size of space
I'm reading Bill Bryson's A Short History of Nearly Everything. It's been on my bookshelf for a while but I've finally gotten around to it. I've just read the chapter on the solar system, and quite frankly, it's mind-blowing. I am pretty ignorant regarding astronomy, but it seems to me that I should know a lot more than I do about our little planet and its place in the universe. Anyway, this little section on relative scale was pretty interesting:
On a diagram of the solar system to scale, with the Earth reduced to about the diameter of a pea, Jupiter would be over 300 metres away and Pluto would be two and a half kilometres distant (and about the size of a bacterium, so you wouldn't be able to see it anyway). On the same scale, Proxima Centauri, our nearest star, would be 16,000 kilometres away. Even if you shrank down everything so that Jupiter was as small as the full stop at the end of this sentence, and Pluto was no bigger than a molecule, Pluto would still be over 10 metres away.
Kind of makes you appreciate how inaccurate those solar system diagrams you saw at school really were, doesn't it?

It got me thinking - instead of reducing Earth to the size of a pea, how about you expand a pea to the size of Earth - how big would the elements of the solar system be in that scale?

Well... fear not because I've done the maths for you. If a pea were the size of Earth, then in that scale, Mercury could be represented by a Grape Nut™ - if you don't know what Grape Nuts are, you need to investigate the cereal aisle at your local supermarket; a cricket ball would be about the size of Jupiter; and one of those weird exercise balls you see at gyms would be the same size as the sun.

But get this - and remember our scale of a pea representing Earth - the Milky Way would be 1/10th the diameter of our solar system*. I have to use a distance in space as the equivalent because there's simply nothing else big enough. So that makes our galaxy... quite big.

*This is using the distance of Pluto from the sun as the diameter - actually the solar system is even bigger than this if you go out as far as the Oort cloud or beyond.
19 August, 2006 at 00:18 0 Comments
Customising the AxWebBrowser
I recently needed to use AxWebBrowser component to do some automation of web page form filling. I wanted to capture Javascript alert boxes, grab the text from the alert box, and return it as an error to the user of my application.

I also wanted to disable the loading of images and Flash animations. The code for this is below, in the IDispatch_Invoke_Handler method.

It took me a long time to track down the method of doing this, so I thought I'd put it here in case anybody else needs the same info.

First, some links I found useful:
The following code shows how to setup the web browser such that you are alerted when Javascript popups are shown.

First, you need to define some constants and interfaces.

public enum ComConstants : uint
{
DLCTL_DLIMAGES = 0x00000010,
DLCTL_VIDEOS = 0x00000020,
DLCTL_BGSOUNDS = 0x00000040,
DLCTL_NO_SCRIPTS = 0x00000080,
DLCTL_NO_JAVA = 0x00000100,
DLCTL_NO_RUNACTIVEXCTLS = 0x00000200,
DLCTL_NO_DLACTIVEXCTLS = 0x00000400,
DLCTL_DOWNLOADONLY = 0x00000800,
DLCTL_NO_FRAMEDOWNLOAD = 0x00001000,
DLCTL_RESYNCHRONIZE = 0x00002000,
DLCTL_PRAGMA_NO_CACHE = 0x00004000,
DLCTL_NO_BEHAVIORS = 0x00008000,
DLCTL_NO_METACHARSET = 0x00010000,
DLCTL_URL_ENCODING_DISABLE_UTF8 = 0x00020000,
DLCTL_URL_ENCODING_ENABLE_UTF8 = 0x00040000,
DLCTL_NOFRAMES = 0x00080000,
DLCTL_FORCEOFFLINE = 0x10000000,
DLCTL_NO_CLIENTPULL = 0x20000000,
DLCTL_SILENT = 0x40000000,
DLCTL_OFFLINEIFNOTCONNECTED = 0x80000000,
DLCTL_OFFLINE = 0x80000000
}


public enum DialogBoxCommandId
{
Ok = 1,
Cancel = 2,
Abort = 3,
Retry = 4,
Ignore = 5,
Yes = 6,
No = 7,
TryAgain = 10,
Continue = 11
}


using System.Runtime.InteropServices;
using mshtml;

[ComImport,
Guid("C4D244B0-D43E-11CF-893B-00AA00BDCE1A"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDocHostShowUI
{
[PreserveSig]
uint ShowMessage(IntPtr hwnd,
[MarshalAs(UnmanagedType.LPWStr)] string lpstrText,
[MarshalAs(UnmanagedType.LPWStr)] string lpstrCaption,
uint dwType,
[MarshalAs(UnmanagedType.LPWStr)] string lpstrHelpFile,
uint dwHelpContext,
out int lpResult);

[PreserveSig]
uint ShowHelp(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszHelpFile,
uint uCommand, uint dwData,
tagPOINT ptMouse,
[MarshalAs(UnmanagedType.IDispatch)] object pDispatchObjectHit);
}


using System.Runtime.InteropServices;
using System.Windows.Forms;
using mshtml;

public enum DOCHOSTUITYPE
{
DOCHOSTUITYPE_BROWSE = 0,
DOCHOSTUITYPE_AUTHOR = 1
}

public enum DOCHOSTUIDBLCLK
{
DOCHOSTUIDBLCLK_DEFAULT = 0,
DOCHOSTUIDBLCLK_SHOWPROPERTIES = 1,
DOCHOSTUIDBLCLK_SHOWCODE = 2
}

public enum DOCHOSTUIFLAG
{
DOCHOSTUIFLAG_DIALOG = 0x00000001,
DOCHOSTUIFLAG_DISABLE_HELP_MENU = 0x00000002,
DOCHOSTUIFLAG_NO3DBORDER = 0x00000004,
DOCHOSTUIFLAG_SCROLL_NO = 0x00000008,
DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE = 0x00000010,
DOCHOSTUIFLAG_OPENNEWWIN = 0x00000020,
DOCHOSTUIFLAG_DISABLE_OFFSCREEN = 0x00000040,
DOCHOSTUIFLAG_FLAT_SCROLLBAR = 0x00000080,
DOCHOSTUIFLAG_DIV_BLOCKDEFAULT = 0x00000100,
DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY = 0x00000200,
DOCHOSTUIFLAG_OVERRIDEBEHAVIORFACTORY = 0x00000400,
DOCHOSTUIFLAG_CODEPAGELINKEDFONTS = 0x00000800,
DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8 = 0x00001000,
DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8 = 0x00002000,
DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE = 0x00004000,
DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION = 0x00010000,
DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION = 0x00020000,
DOCHOSTUIFLAG_THEME = 0x00040000,
DOCHOSTUIFLAG_NOTHEME = 0x00080000,
DOCHOSTUIFLAG_NOPICS = 0x00100000,
DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000,
DOCHOSTUIFLAG_DELEGATESIDOFDISPATCH = 0x00400000
}

[StructLayout(LayoutKind.Sequential)]
public struct DOCHOSTUIINFO
{
public uint cbSize;
public uint dwFlags;
public uint dwDoubleClick;
[MarshalAs(UnmanagedType.BStr)] public string pchHostCss;
[MarshalAs(UnmanagedType.BStr)] public string pchHostNS;
}

[StructLayout(LayoutKind.Sequential)]
public struct tagMSG
{
public IntPtr hwnd;
public uint message;
public uint wParam;
public int lParam;
public uint time;
public tagPOINT pt;
}

[ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
GuidAttribute("bd3f23c0-d43e-11cf-893b-00aa00bdce1a")]
public interface IDocHostUIHandler
{
[PreserveSig]
uint ShowContextMenu(uint dwID, ref tagPOINT ppt,
[MarshalAs(UnmanagedType.IUnknown)] object pcmdtReserved,
[MarshalAs(UnmanagedType.IDispatch)] object pdispReserved);

void GetHostInfo(ref DOCHOSTUIINFO pInfo);
void ShowUI(uint dwID, ref object pActiveObject, ref object pCommandTarget, ref object pFrame, ref object pDoc);
void HideUI();
void UpdateUI();
void EnableModeless(int fEnable);
void OnDocWindowActivate(int fActivate);
void OnFrameWindowActivate(int fActivate);
void ResizeBorder(ref tagRECT prcBorder, int pUIWindow, int fRameWindow);

[PreserveSig]
uint TranslateAccelerator(ref tagMSG lpMsg, ref Guid pguidCmdGroup, uint nCmdID);

void GetOptionKeyPath([MarshalAs(UnmanagedType.BStr)] ref string pchKey, uint dw);
object GetDropTarget(ref object pDropTarget);
object GetExternal();

[PreserveSig]
uint TranslateUrl(uint dwTranslate,
[MarshalAs(UnmanagedType.BStr)] string pchURLIn,
[MarshalAs(UnmanagedType.BStr)] ref string ppchURLOut);

IDataObject FilterDataObject(IDataObject pDO);
}

[ComImport(),
GuidAttribute("3050f6d0-98b5-11cf-bb82-00aa00bdce0b")]
public interface IDocHostUIHandler2: IDocHostUIHandler
{
void GetOverrideKeyPath([MarshalAs(UnmanagedType.BStr)] ref string pchKey, uint dw);
}


using System.Runtime.InteropServices;

[ComImport,
Guid("00000118-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleClientSite
{
void SaveObject();
void GetMoniker(uint dwAssign, uint dwWhichMoniker, ref object ppmk);
void GetContainer(ref object ppContainer);
void ShowObject();
void OnShowWindow(bool fShow);
void RequestNewObjectLayout();
}


using System.Runtime.InteropServices;

[ComImport,
Guid("b722bcc7-4e68-101b-a2bc-00aa00404770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleDocumentSite
{
void ActivateMe(ref object pViewToActivate);
}


using System.Runtime.InteropServices;
using System.Windows.Forms;

[ComImport,
Guid("00000112-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleObject
{
void SetClientSite(IOleClientSite pClientSite);
void GetClientSite(ref IOleClientSite ppClientSite);
void SetHostNames(object szContainerApp, object szContainerObj);
void Close(uint dwSaveOption);
void SetMoniker(uint dwWhichMoniker, object pmk);
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void InitFromData(IDataObject pDataObject, bool fCreation, uint dwReserved);
void GetClipboardData(uint dwReserved, ref IDataObject ppDataObject);
void DoVerb(uint iVerb, uint lpmsg, object pActiveSite, uint lindex, uint hwndParent, uint lprcPosRect);
void EnumVerbs(ref object ppEnumOleVerb);
void Update();
void IsUpToDate();
void GetUserClassID(uint pClsid);
void GetUserType(uint dwFormOfType, uint pszUserType);
void SetExtent(uint dwDrawAspect, uint psizel);
void GetExtent(uint dwDrawAspect, uint psizel);
void Advise(object pAdvSink, uint pdwConnection);
void Unadvise(uint dwConnection);
void EnumAdvise(ref object ppenumAdvise);
void GetMiscStatus(uint dwAspect,uint pdwStatus);
void SetColorScheme(object pLogpal);
}


Now, you can define the object that will host the web browser, using the interfaces you have just declared.

using System.Runtime.InteropServices;
using System.Windows.Forms;
using mshtml;

public class WebBrowser:
IOleClientSite, // so MsHtml uses IDocHostUIHandler
IDocHostUIHandler,
IOleDocumentSite, // so MsHtml uses IDocHostShowUI
IDocHostShowUI
{
#region IOleClientSite methods

void IOleClientSite.SaveObject() {}
void IOleClientSite.GetMoniker(uint dwAssign, uint dwWhichMoniker, ref object ppmk) {}
void IOleClientSite.GetContainer(ref object ppContainer) {ppContainer = this;}
void IOleClientSite.ShowObject() {}
void IOleClientSite.OnShowWindow(bool fShow) {}
void IOleClientSite.RequestNewObjectLayout() {}

#endregion

#region IDocHostUIHandler methods

public uint ShowContextMenu(uint dwID, ref tagPOINT ppt, object pcmdtReserved, object pdispReserved)
{
//const int MenuHandled = 0; // uncomment this line, and comment the next one, to show the context menu
const int MenuNotHandled = 1;
return MenuNotHandled;
}

public uint TranslateAccelerator(ref tagMSG lpMsg, ref Guid pguidCmdGroup, uint nCmdID)
{
//const int KillAccelerator = 0;
const int AllowAccelerator = 1;
return AllowAccelerator;
}

public object GetDropTarget(ref object pDropTarget)
{
return pDropTarget;
}

public object GetExternal()
{
return null;
}

public uint TranslateUrl(uint dwTranslate, string URLIn, ref string URLOut)
{
//const int Translated = 0;
const int NotTranslated = 1;
return NotTranslated;
}

public IDataObject FilterDataObject(IDataObject pDO)
{
return null;
}

public void GetHostInfo(ref DOCHOSTUIINFO theHostUIInfo) {}
public void ShowUI(uint dwID, ref object pActiveObject, ref object pCommandTarget, ref object pFrame, ref object pDoc) {}
public void HideUI() {}
public void UpdateUI() {}
public void EnableModeless(int fEnable) {}
public void OnDocWindowActivate(int fActivate) {}
public void OnFrameWindowActivate(int fActivate) {}
public void ResizeBorder(ref tagRECT prcBorder, int pUIWindow, int fRameWindow) {}
public void GetOptionKeyPath(ref string pchKey, uint dw) {}

#endregion

#region IOleDocumentSite methods

public void ActivateMe(ref object pViewToActivate) {}

#endregion

#region IDocHostShowUI methods

public uint ShowMessage(IntPtr hwnd, string msgText, string msgCaption,
uint dwType, string lpstrHelpFile, uint dwHelpContext,
out int lpResult)
{
// msgText is the contents of the MessageBox
// msgCaption is the text on the MessageBox caption bar

// this is where you can deal with javascript popup boxes and simulate clicking different buttons
lpResult = (int) DialogBoxCommandId.Ok;

// return one of these values
const int MessageHandled = 0; // MsHtml won't display its MessageBox
//const int MessageNotHandled = 1; // MsHtml will display its MessageBox
return MessageHandled;
}

public uint ShowHelp(IntPtr hwnd, string pszHelpFile, uint uCommand, uint dwData,
tagPOINT ptMouse, object pDispatchObjectHit)
{
// pDispatchObject will reference an object of
// type mshtml.HTMLDocumentClass, or other class
// representing something on the HTML page.

// return one of these values
//const int HelpHandled = 0; // MsHtml won't display its Help window
const int HelpNotHandled = 1; // MsHtml will display its Help window

return HelpNotHandled;
}

#endregion

#region IDispatch methods

[DispId(-5512)] // DISPID_AMBIENT_DLCONTROL = -5512
public int IDispatch_Invoke_Handler()
{
// I have found that DLCTL_NO_CLIENTPULL means that things like meta refreshes are not executed
int lReturn = (int) (ComConstants.DLCTL_PRAGMA_NO_CACHE | ComConstants.DLCTL_SILENT | ComConstants.DLCTL_NO_BEHAVIORS | ComConstants.DLCTL_NO_JAVA | ComConstants.DLCTL_NO_FRAMEDOWNLOAD);
if (!Configuration.LoadActiveXControls)
{
lReturn |= (int) (ComConstants.DLCTL_NO_DLACTIVEXCTLS | ComConstants.DLCTL_NO_RUNACTIVEXCTLS);
}
if (Configuration.LoadImages)
{
lReturn |= (int) ComConstants.DLCTL_DLIMAGES;
}
return lReturn;
}

#endregion
}


In my code, I have a member variable mWebBrowser, of type AxWebBrowser, inside my WebBrowser class. After I've created it, the following lines are necessary to "register" the WebBrowser class as the host:

IOleObject lOleObject = (IOleObject) mWebBrowser.GetOcx();
lOleObject.SetClientSite(this);
15 August, 2006 at 15:22 1 Comment
iLyrics
So, it turns out the iTunes COM API is incredibly simple to use - even with C#. It's only taken me half an hour to write a little app that grabs the selected track from iTunes, searches a lyrics website to grab the lyrics, and adds the lyrics to the track info in iTunes.

Here's a screenie:


At the moment it's really basic - it will only work for one track. But it will be easy enough to make it work for any number of selected tracks.

Let me know if you're interested - I'm quite willing to publish the source and binaries.
14 August, 2006 at 23:49 0 Comments
Getting setup with iTunes
I'm on the verge of buying a 60gb iPod Video. This immediately raises a problem, since I have all my music (around 400 CDs) in WMA format, as I've always been strongly in the Microsoft camp. I could use iTunes to convert WMA to MP3 or AAC, but since I've got it in 64kbps WMA, it won't sound that great if it's converted to another lossy format.

So I'm going to take the opportunity to re-rip all my CDs into a new format. Given that I want to play the music on iPod, I obviously can't use WMA, but I've still got to choose between AAC or MP3 (yes, okay, I could use Apple Lossless, but I want to fit more than 3 songs on my iPod).

I have considered ripping to a Lossless format, which would mean I'd never (in theory) need to rip from my CDs again. Then I could down-convert to AAC for putting on the iPod. However, I don't currently have enough money for a new hard disk, which I'd need in order to store all my music in a lossless format. So at the moment, although this is definitely a good idea, I'm going to have to stay with a lossy format.

I found this page which contains a helpful discussion on compression formats and which sounds better.

I am going to go with Marc's conclusion, and use AAC 224kbps as my format of choice. Hopefully this will sound good through both headphones and hi-fi when played on the iPod.

While I'm at it, and as much for my own reference as anything else, here's the tools I'm finding useful to help with this whole iTunes / iPod transition:
  • Lyrics
    I'm aware there's plenty of programs that claim to be able to download lyrics into iTunes automatically. I've tried several of these, but none of them seem to do the job I want. What I want is to select a track in iTunes, click "search" in the lyrics program, get a list of possible matches, select the right one, and click OK. So I'm going to write a little utility app that does this - if you think you might find it useful, let me know and I'll develop it into a proper application that I can distribute.
  • iTunes Art Importer (free)
    Uses iTunes COM and Amazon Web Services to automatically find album art
  • iPodRip
    I haven't used this yet, but it would be incredibly useful should my desktop PC ever crash, and I needed to copy music from the iPod to PC

14 August, 2006 at 21:01 0 Comments
Christianity - a new religion?
First some facts about Christianity:
  • There are roughly 33,830 Christian denominations
  • There are an estimated 2.1 billion adherents in the world, making Christianity the world's largest religion
Anyway, the reason for this post is that I had a sudden realisation when I was mulling over religions - Christianity as I know it (i.e. the type I was raised with, Protestantism) has only existed since the 16th century! Protestants consider their separation from the Catholic church to have taken place in the 16th century, at the time of the Reformation. I always used to think that before that, there was still a "real" Christianity, it just wasn't very popular. But I've been doing some research, and my findings have challenged that point of view.

Before the Reformation, the Church used to sell indulgences. An indulgence (apparently) allows a person to skip the wages of sin, that would usually be paid for in purgatory. The Church was probably making a tidy profit on this business, but then along came a man named Martin Luther who put together a paper now known as the "95 Theses", in which he said the sale of indulgences was basically A Bad Thing. The reigning Pope, Pope Leo X, wished for Martin Luther to recant 41 of the Theses. He refused (he publicly burned the papers containing the request from the Pope), and was ex-communicated by the Catholic Church. When I initially did some research for this post, I thought I would find that those 41 theses that the Pope wished for Martin Luther to recant contained beliefs that modern Christianity would find abhorrent. However, this was not the case - in fact, many of Luther's own theses contain statements that modern Protestantism would probably have a hard time agreeing with. Here's a few of Luther's theses:
  • Salvation can be sought for through the Church as it has been granted this by Christ
  • It is clear that the power of the Church is adequate, by itself, for the forgiveness of sins
  • The pope should rebuild St Peter's with his own money
  • You should feel guilt after being pardoned
  • Souls in purgatory need to find love - the more love the less their sin [interestingly, the Pope in his response pointed out that Purgatory can't actually be proved from Scripture]
It's easy enough to pick holes in Luther's theses, and also the response from the Pope (known as Exurge Domine). But my point in all this rambling is that these events make up some of the foundation stones of modern Christianity (at least, the Protestant variety of it) - and if I was a Christian, I'd be looking pretty seriously at where my religion came from. It seems to me that "Christianity", as we known it, has only been around for a few hundred years - and before that, it contained so many conflicting doctrines that one has to question whether it was really "Christianity" at all - at least by modern standards - how much can a religion change before it's not the same religion?

(It's not particularly related to this topic, but let's not forget that Martin Luther also wrote about the Jews, proposing that their homes be destroyed, synagogues and schools burned, money confiscated, and rights and liberties be curtailed.)
13 August, 2006 at 13:30 0 Comments
French holiday

I have just spent a week with my flatmate, Zoe, and her family in France. Zoe's parents own a farm in Alsace, which they are gradually renovating. One of the things I helped with was removing an old floor. This was a lot of fun - my appetite for destroying things was temporarily appeased. Here's a somewhat sped-up version of how we did it (press play to start, has sound):


12 August, 2006 at 23:27 3 Comments
This ungodly blog
Have you ever heard the word ungodly used as an adjective for anything other than "hour"? According to dictionary.com, the definition of ungodly is:
  • Not revering God; impious.
  • Sinful; wicked.
  • Outrageous: had to leave for work at an ungodly hour.
Personally, I've only ever heard it used in the third way.
03 August, 2006 at 10:57 0 Comments
Paedophile Island
It's surely only a matter of time until somebody comes up with a reality TV show based around putting criminals into a house or onto an island and filming them until one of them commits a crime.

I personally think that, within 10 years, the Daily Mail will have successfully campaigned for legalisation of on-the-spot killing of paedophiles. You'll be able to go up to people, say "Are you a paedophile?", and if the answer is affirmative, you'll have the legal right to get a mob together and stone the evil bast**d. It won't matter whether he (I say he, only because I don't know too many cases of female paedophiles) has been to prison and served his time - this is irrelevant in the New Daily Mail World Order.

Anyway, back to my reality TV show idea - think Love Island meets The Running Man. I'm still working on the fine details, but I think it's got potential.
02 August, 2006 at 14:03 1 Comment