Posts for January 2007

Finally, DVDs on Vista

Cyberlink released an update for PowerDVD today that fixes some of the issues it had with Windows Vista. The problems I had with blocky video are gone, and DVD-Audio works properly now.

My main complaint about SPDIF not working still isn't fixed though, but I'm not sure if it's PowerDVD or the driver writers at fault here. I logged a support incident with Cyberlink, we'll see what they have to say.

At least I won't need to boot into XP anymore for DVD-Audio and DVDs where the sound isn't that important (e.g. most older TV series). But unfortunately I'll still need XP for movies where the soundtrack is important.

At least it's a start.

Categories: General computing
Posted on: 2007-01-31 18:19 UTC. Show comments (0)

IE add-on development: globally capturing keyboard input

A long time ago, in the third article in my series on IE add-on development, I mentioned a way to globally handle keyboard input in an Internet Explorer add-in using a BHO. In this fourth installment I will talk about this.

The first thing we will need to do in order to handle keys with a BHO (Browser Helper Object) is actually write a BHO. Instead of wasting space here explaining how to do that, I will refer to this MSDN article on BHOs. That article uses ATL, while I do not, but it doesn't matter in this case.

Unfortunately the IE add-on model doesn't really offer any built-in methods for handling key input globally. What we need to do then is to use a keyboard hook, which allows us to intercept keyboard messages before they reach IE. In order to do this we must add an instance variable of type HHOOK to the class that implements our BHO (in the MSDN example this is CHelloWorldBHO, in my Find As You Type add-on it is SearchBrowserHelper; here I will call it ExampleBHO). We also need to add a static method that matches the signature of the KeyboardProc callback (if you use ATL the class definition and constructor will look different, but the rest remains the same; you must still add a HHOOK member and initialize it to NULL):

class ExampleBHO : public IObjectWithSite
{
public:
    ExampleBHO() : _hook(NULL)
    {
        /* Remaining constructor code omitted */
    }
    /* Other members omitted */
private:
    static LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);
    HHOOK _hook;
public:
    static DWORD TlsIndex; // I will explain this further down.
};

DWORD ExampleBHO::TlsIndex = 0;

We then add the following code to the implementation of IObjectWithSite::SetSite, and we implement the KeyboardProc as well:

STDMETHODIMP SearchBrowserHelper::SetSite(IUnknown *punkSite)
{
    if( _hook != NULL )
    {
        // Remove any existing hooks
        UnhookWindowHookEx(_hook);
        _hook = NULL;
    }
    
    if( punkSite != NULL )
    {
        /* Code to retrieve the IWebBrowser2 interface goes here */
        
        _hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, GetCurrentThreadId());
    }
    
    return S_OK;
}

LRESULT CALLBACK ExampleBHO::KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
    // Code < 0 should be passed on without doing anything according to the docs.
    if( code >= 0 )
    {
        MessageBox(NULL, TEXT("Keypress detected"), TEXT("ExampleBHO)", MB_OK);
    }    
    return CallNextHookEx(NULL, code, wParam, lParam);
}

Let's look at that code, shall we. A browser helper object gets instantiated for each browser window or tab. Every browser window or tab running in the same process gets its own thread, and the BHO is instantiated on that thread. So we install a keyboard hook that will get the keyboard messages for that thread by passing in the result of GetCurrentThreadId() as the last parameter.

It should be noted that if you decide to cancel key propagation (by not calling CallNextHookEx) this means the keys for which you do this will lose their original function in IE.

One thing you likely want to do in the KeyboardProc however is interact with the BHO object. But since it's a static method, that's not possible (and it has to be static since you can't create a function pointer to an instance method, as you probably know). In the earlier examples with the toolbar we solved this problem by storing a pointer in the toolbar's window data, but a BHO has no window so we can't use that approach here. And since each thread has its own BHO we can't use a global variable either. Fortunately, a solution to this problem exists with Thread Local Storage. That's what the mysterious TlsIndex member I added above was for.

To use this, we must first allocate the storage we want to use, which must be done in the DllMain function:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch( ul_reason_for_call )
    {
    case DLL_PROCESS_ATTACH:
        ExampleBHO::TlsIndex = TlsAlloc()
        break;
    case DLL_PROCESS_DETACH:
        TlsFree(ExampleBHO::TlsIndex);
        break;
    }
    return TRUE;
}

We can now store a pointer to the BHO. Since we can guarantee our BHO will be created only once for each thread the most logical place to do this is the BHO class's constructor:

ExampleBHO() : _hook(NULL)
{
    /* Remaining constructor code omitted */
    TlsSetValue(TlsIndex, this);
}

Now we can retrieve the pointer in the KeyboardProc:

LRESULT CALLBACK ExampleBHO::KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
    // Code < 0 should be passed on without doing anything according to the docs.
    if( code >= 0 )
    {
        ExampleBHO *bho = static_cast<ExampleBHO>(TlsGetValue(TlsIndex));
        
        /* Do something with the BHO */
        
        MessageBox(NULL, TEXT("Keypress detected"), TEXT("ExampleBHO)", MB_OK);
    }    
    return CallNextHookEx(NULL, code, wParam, lParam);
}

There remains however one problem. As I said earlier, in IE7 each tab has its own thread and each BHO will set the hook on that tab's thread. Unfortunately some of the browser's chrome such as the address bar that falls outside the tabs runs on yet another thread. This thread has no browser object associated with it, so it gets no BHO, and thus no hook. Find As You Type 1.1 has this very problem, which is why the CTRL-F shortcut for Find As You Type doesn't work if the address bar has focus.

But there is a way to solve this. It involves getting the top-level window handle, retrieving its thread using GetWindowThreadProcessId, installing a hook for that thread, and using some hocus-pocus to communicate with the currently active tab and to make sure we correctly handle the existence of multiple top-level windows in the same process. That will be the topic of the next article in this series (which hopefully will not take as long as this one). And I'm pleased to say that this solution has been implemented in the soon-to-be-released Find As You Type 1.2.

Categories: Programming
Posted on: 2007-01-24 10:43 UTC. Show comments (2)

I'm going to Japan!

As some of you may know last July I have requested the Monbukagakusho (MEXT) scholarship to go to Japan for two years, to do research at Kitsuregawa Lab at Tokyo University. As I wrote earlier, I had already passed the preliminary selection in August last year, and had been accepted into Tokyo University shortly after. The only thing I was still waiting for was the final approval from the Japanese government that I would get the scholarship.

That approval has not yet officially arrived, however a recent e-mail from Tokyo University implied that they believed I had been accepted, which prompted me to call the Japanese Embassy, who called MEXT in Japan, and told me that it was true: I've got the scholarship!

The paperwork isn't done yet, which is why neither me nor the Embassy had been informed yet, but it is official. Next April I will fly to Tokyo, Japan, where I will stay for two years. I can hardly believe that it is really happening, but it is!

You will believe I'm more than a little elated about this! Finally I have certainty after months of waiting!

Because the paperwork isn't finished, I don't have all the details yet. For instance, although I know I'll be leaving in the first week of April, I don't yet know the date or other flight details. I also don't know precisely where in Tokyo I will live, although it's likely I will end up in an international house (special housing for international students), one of which is on the same campus as Kitsuregawa Lab, so that would be very convenient.

Of course, this blog is the place where I will keep all those who are interested up to date on all this. In fact, the possibility that I would be going to Japan was one of the main reasons why I started a blog in the first place.

Now however comes the really hard part. I have to focus on my work for the remainder on the day while what I really want to do is stand on the roof and shout it: I'm going to Japan!

Categories: Japan
Posted on: 2007-01-23 11:21 UTC. Show comments (1)

Day NaN: New toys!

Okay, they're for work, so they're technically not toys and they're also not actually mine, but this is still neat.

As some of you might know, the one thing that was still noticably absent from my desk at University was a PC. I had to use my own (old, slow) laptop to do my work, not exactly ideal.

Now, I finally got a PC. And quite a nice one it is too; quite a bit faster than the one I have at home. It's got an Intel Core 2 Duo 6600 (2.4GHz) CPU, 2GB DDR2 667MHz RAM, an nVidia GeForce 7950GT with 512MB RAM and two 250GB SATA hard disks. It far exceeds what I actually need, but you don't hear me complaining. :)

Perhaps the most amazing piece of equipment however is the monitor. It's a Samsung 225BW 22" widescreen LCD panel:

My desk at University

It's huge! The picture just doesn't convey how big it truly is. Working with it is like sitting front row in a cinema. I realize this may be old hat for a lot of people, but it's the biggest monitor I've ever worked with. When I came home today I couldn't help but think how small my own 17" CRT really is. :P

And it appears a fairly decent monitor in other aspects as well (especially considering its price). Response time is great, and colour clarity is good; definitely more than adequate for what I'm going to be using it for. The only drawback is that at 1680x1050 I think its native resolution is on the low side for a monitor this size. A bit higher, like 1920x1200, would've come a long way. But, I suppose that would've made it more expensive.

You may notice I'm running Vista on it. Unfortunately this is not because Leiden University is so up to date with their OS support: it's because due to a miscommunication they didn't have any Windows CD and key for me yet, so I temporarily used my own Vista DVD, installing it without a key (so it's not activated). In a few days I should get the proper XP CD and it'll be bye-bye to Vista. A shame, really, since this kind of machine is what Vista's made of, and not surprisingly it runs beautifully on it.

Categories: University
Posted on: 2007-01-08 17:30 UTC. Show comments (0)

Latest posts

Categories

Archive

Syndication

RSS Subscribe

;