Blog

April 4th, 2007

Today I went to the Japanese Embassy in The Hague again, for the third time. The first time was to enquire for information about the MEXT scholarship, the second time was to apply for it, and now the circle is complete: this time I was a MEXT scholarship grantee.

The one notable difference this time around was the weather: it was terrible. Where the last time I didn't mind having to wait outside for the Embassy to open, I was glad that I didn't have to do that this time. I arrived shortly after eleven and applied for my student visa.

After this I walked to the nearby restaurant Shirasagi (which was terrible since it was pooring and my umbrella was destroyed by the wind). Shirasagi turned out to be a quite fancy restaurant and also a real Japanese restaurant (by that I mean it was run by real Japanese, instead of most Japanese restaurants in the Netherlands which are usually owned by Chinese people).

At 12:30 I was joined by a fellow scholarship grantee and two people from the cultural section of the embassy, whom I already knew from the previous visit (and quite a few telephone conversations over the past few months). We had lunch at the restaurant, while we discussed our upcoming trip to Japan. It was quite informal really, and very informative. I got a whole stack of booklets and maps and other information too. After lunch (which was very good) we went back to the Embassy where I picked up my visa.

So what's April 4th? That's the day when I will go to Japan, which I found out only today (this is since the Embassy was responsible for booking the flight and MEXT will pay for it; I had no say in it, I only knew it would be the first week of April). On the morning of April 4th I will take a flight from Schiphol with Lufthansa, first to Frankfurt and from there to Narita International Airport at Tokyo, where I will be met by someone from JASSO. Then I will go by taxi to my new home for the next two years.

So there you have it. In a mere two weeks, my life will change completely. Am I nervous? Definitely. Would I want to trade this for anything? Definitely not!

Categories: Japan
Posted on: 2007-03-20 22:33 UTC. Show comments (3)

A week of fixing Vista problems

It's been a quiet month on the blog front. This is of course because I've got lots of stuff to do to prepare for my departure to Japan next month, including quite a bit of work that needs to be finished at University. Next Tuesday I'm going to an orientation meeting organized by the Japanese Embassy, so I'll be sure to blog about that.

The past week though has been marked by the solution to two problems I've had with Vista. This would hardly qualify as interesting news if it weren't for the fact that one of them I care a great deal about.

Ever since the beginning of the Vista beta, sound has been a problem. The newness of Vista's audio stack combined with crappy Creative drivers have given everybody a lot of headaches (I own a Sound Blaster X-Fi; great card, lousy driver support).

Although it's been mostly ok for a while now (surround sound works, stutters are limited to when there's a lot of hard disk IO, not sure if this is due to the audio or the IDE drivers), there was one thing that didn't work yet. That was SPDIF passthrough.

For the less audio-savvy readers, a quick explanation: normally when you watch a DVD on your computer, the DVD playing software takes care of decoding the Dolby AC3 or DTS audio stream on the DVD. Then your sound card converts it to an analog signal that goes to your speakers. With an expensive sound card like the X-Fi, sometimes the card can do the AC3/DTS decoding as well. But the signal to the speakers remains analog, since the digital SPDIF interface can handle only 2 channels when handling decoded (PCM) audio, not the 6 channels required for your typical DVD. With SPDIF passthrough, the still encoded AC3/DTS signal is sent directly over the SPDIF link to an external decoder. The advantage is that you now have a digital connection up to the external decoder, instead of everything from the computer down being analog, leading to better quality. My speakers, the Logitech Z-5400 (the link is for the Z-5450, which is the same except the Z-5400's rear speakers are not wireless), include such a decoder.

So, being the audio-freak I am, and having paid a neat sum for those speakers, I'd like to be able to use the external decoder. But that was impossible in Vista, since SPDIF passthrough did not work (although for mysterious reasons, it did work from the "test" option in the Control Panel and from Media Center, just not from any other application such as WMP or PowerDVD).

Now, with Creative's new drivers (released March 8th), it finally works. Despite the fact that the release notes for the drivers say that SPDIF doesn't work on x64, it does actually work.

So happy was I that it worked, I even created a silly video to show it.

The second problem I solved had to do with Windows Media Player. For some reason, WMP11 on Vista could synchronize music to my PocketPC's main memory, but it didn't recognize the storage card (strangely, WMP11 on XP had no problems with this). For this, I found this hotfix, which took care of the problem.

Categories: General computing
Posted on: 2007-03-18 11:51 UTC. Show comments (1)

Japanese Input and Dictionary

A long time ago, when I first started to follow Japanese language courses at Leiden University, I was the proud owner of a Palm M100, which I used to run KingKanji (without which it's doubtful I ever would've made it through those courses; I can really recommend that application to anyone who needs to learn kanji). But that was about all I could do because nothing else really fit into it's 2MB memory.

Shortly afterwards I got a HP iPaq h1930. Suddenly I had space for more, and quickly found Mike Johnson's Japanese SIP and dictionary. But these applications, while very useful, did lack certain features I wanted (and the dictionary app was just plain slow, not so much because of the search itself but because of how the results were displayed), so I quickly decided to make some changes.

Some changes turned into a complete rewrite. In the case of the dictionary, I quickly ditched the original Embedded Visual C++ 4 version in favour of the .Net Compact Framework, leaving almost nothing from the original except the EUC to Unicode conversion tables. For the SIP I stuck with the original code for quite a while, but in the end I still rewrote the whole thing (still in C++, since there's no other choice for SIPs) using a much cleaner object-oriented design (imo of course :), and a completely new look. Here only the handwriting recognition algorithm itself (which dates back all the way to Todd David Rudick's JavaDict from 1997, so admittedly it isn't all that advanced) remains, and even that was cleaned up a little.

This was a few years ago, and while the apps were usable enough for me, they didn't quite have the level of polish I require when I put stuff online. Now, since I'm going to Japan next month, I figured it would be a good time to take out those last few rough edges, add a few additional features, and release it.

So today I have two new downloads: Japanese Input and Pocket Dictionary (ultimate proof that I'm even worse at naming applications than Microsoft's marketing department).

Japanese Input and Pocket Dictionary in action

Both work on Windows Mobile 2003 and newer (including Windows Mobile 6), and offer full support for devices with alternative resolutions such as 192DPI (480x640 VGA devices) and 128DPI (the new 320x320 Windows Mobile 6 devices) and of course screen rotation is also supported.

Categories: Software
Posted on: 2007-03-04 16:34 UTC. Show comments (2)

Try/Finally vs. RAII

Developing Find As You Type meant doing something I hadn't done in a while: pure C++ development. I'm also using C++ for some other projects now so I'm really getting back into the unmanaged way of thinking.

As a young whippersnapper I first learned to program in GW-BASIC, which was really easy in terms of memory management: there was none. There were no pointers, and all variables were global. In the early nineties I moved on to Visual Basic which, as long as you know the caveats of reference counting (e.g. the circular reference problem) is also not one of the biggest challenges in that regard. Then of course I started to learn C/C++ and got to deal with the wonders of malloc/free and new/delete.

One of the difficulties here is making sure that no matter what happens your resources get released, especially when using exceptions. How to make sure delete is called even when an exception occurs? And it's not just pointers; things like CloseFile or LeaveCriticalSection are all things that you want to regardless of how and where you exit the function. Of course there is a perfectly elegant way to deal with this, which I will come to later.

When .Net came out I learned about try/finally (which Java also has, but I hadn't really used Java at that time) and wondered why C++ didn't have this. The finally block is always executed. It doesn't matter if the try block was left because of control flow reaching the end of the block, because of a return statement, or an exception thrown; it would be executed. Back then I thought that would be a really useful thing to have in C++.

What I realized later is that the reason C++ doesn't have (or need) try/finally is because it doesn't have the problem try/finally was designed to solve: the lack of deterministic finalization. Since .Net and Java are garbage collected, there's no telling when finalizers will run so they need try/finally to be able to make sure things are cleaned up in a timely fashion. C#'s (and VB2005's) "using" statement is an example where try/finally is used (under the hood) for precisely this purpose.

C++ however does have deterministic finalization: a class variable's destructor will always run when it goes out of scope, and that too will happen for both exceptions and regular return. So the answer to the problem is that whenever you need to make sure something is cleaned up you simply create a wrapper class that does that finalization in its destructor. Of course I wasn't the first to think of that, and this is in fact a well known pattern called Resource Acquisition Is Initialization (RAII for short). C++ even provides one such wrapper class for automatic management of pointers: std::auto_ptr.

The reason I write about this now is because Find As You Type 1.2 is the first project where I really got to use this. For example I used the following two classes to deal with critical sections:

class CriticalSectionLock
{
public:
    CriticalSectionLock(LPCRITICAL_SECTION section) : _section(section)
    {
        if( _section != NULL )
            EnterCriticalSection(_section);
    }

    CriticalSectionLock(const CriticalSectionLock &right) : _section(right._section)
    {
        if( _section != NULL )
            EnterCriticalSection(_section);
    }

    CriticalSectionLock& operator=(const CriticalSectionLock &right)
    {
        if( _section != NULL )
            LeaveCriticalSection(_section);
        _section = right._section;
        if( _section != NULL )
            EnterCriticalSection(_section);
        return *this;
    }

    ~CriticalSectionLock()
    {
        if( _section != NULL )
            LeaveCriticalSection(_section);
    }

    void Leave()
    {
        if( _section != NULL )
        {
            LeaveCriticalSection(_section);
            _section = NULL;
        }
    }
private:
    LPCRITICAL_SECTION _section;
};

class CriticalSection
{
public:
    CriticalSection()
    {
        InitializeCriticalSection(&_section);
    }

    ~CriticalSection()
    {
        DeleteCriticalSection(&_section);
    }

    CriticalSectionLock Enter()
    {
        return CriticalSectionLock(&_section);
    }
private:
    CRITICAL_SECTION _section;
};

This enabled me to do two things: by having the CriticalSection class manage the initialization and freeing of a CRITICAL_SECTION, I could simply create static lifetime variables of that class which meant I no longer had to write code in DllMain to call Initialize/DeleteCriticalSection. It also enabled me to write code like this whenever I needed to enter a critical section:

CriticalSection _section; // global variable managing the lifetime of the critical section itself.

void SomeFunction()
{
    CriticalSectionLock lock = _section.Enter();

    // Do work here.
}

When the function exits, the CriticalSectionLock destructor will run, causing LeaveCriticalSection to be called. This happens even if the code doing the work throws an exception. If I want to leave the section before function exits I can simply call lock.Leave() myself.

So which is better? Try/finally certainly has the merit that you don't need to create a class for every little thing that needs this. The RAII approach feels cleaner to me. I don't know.

What is interesting is that C++/CLI not only brings try/finally to C++, it also brings RAII to .Net. Normally when you want to create a variable of a managed class type in C++/CLI you would use e.g. StreamReader ^reader = gcnew StreamReader(L"test.txt"); and then you'd have to call Dispose on it which is possible to ensure with try/finally in C++/CLI but unfortunately you don't get the convenient using syntax from C#.

But the nice thing is that you can also create the variable like this: StreamReader reader(L"test.txt");. That's using the syntax for stack variables. Of course, you don't actually get a stack variable; it's still a reference type, created on the managed heap. But you do get the semantics of a stack variable; if the class implements IDisposable, Dispose will be called automatically when the variable goes out of scope. And that is very nifty indeed.

Categories: Programming
Posted on: 2007-02-22 11:01 UTC. Show comments (0)

IE add-on development: capturing keyboard input outside tabs

This is the fifth article in a series on IE add-on developpment.

Last time, I explained how you could use windows hooks to capture any key before IE itself got a chance to do anything with it. I also highlighted a problem: it didn't work in IE7 when the focus is not on the tabs. In this article, I'm providing a solution to that problem.

The problem we are running into is quite simple. Each tab run on its own thread, and we're installing thread-specific keyboard hooks. The top-level window, which contains some parts of the chrome that fall outside the tabs such as the back/forward buttons, the address bar, the search bar and the command bar (that's a lot of bars!), runs on a different thread too, so none of the keyboard hooks we've installed will catch that.

The solution is equally simple: we need to install a keyboard hook for the top-level window's thread. It's compounded slightly by three issues: each window can have multiple tabs (thus multiple instances of the BHO), but we only want to install the top-level hook once; each process can contain multiple top-level windows so we can't solve the first problem by using one hook per process; and we need a way to communicate with the active tab. There may be multiple ways to solve all these issues; below I give the ones I used for Find As You Type.

Installing the top-level hook

Before we get to worry about the other issues, let's look at how we install the keyboard hook. Unfortunately, BHOs are tied to a particular tab and its associated thread, so none of our code will ever run on the top-level window's thread. Fortunately, we can easily find the top-level window handle by using IWebBrowser2::get_HWND. Then we can use GetWindowsProcessThreadId to find the thread ID and install the hook. This is done in the BHO's SetSite method, just like setting the regular hook.

HWND hwnd;
if( SUCCEEDED(_browser->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&hwnd))) )
{
    DWORD topLevelThreadId = GetWindowThreadProcessId(hwnd, NULL);
    DWORD currentThreadId = GetCurrentThreadId();
    if( topLevelThreadId != currentThreadId )
    {
        // Important: the hook needs to be unset!
        HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, TopLevelKeyboardProc, NULL, topLevelThreadId);
    }
}

One interesting thing to not is that, before I set the hook, I compare the current thread ID to the top-level thread ID. If these two are the same, it means that either tabs are disabled or the user is running a browser older than IE7. In these cases, the regular hook will suffice so we don't need to install an additional one.

As you can see, in the above example I'm discarding the hook handle so I can't free it (I've made a note of that in the code to make sure nobody copies that sample and subsequently forgets to free the hook). That part is taken care of below.

Preventing multiple hooks

The code above would be run every time an instance of our BHO is created, and that will be done for every tab. As I remarked, one window can have multiple tabs, so we're potentially setting the same hook multiple times. We don't want that. To prevent this from happening, what I did is to use an std::map which stores which thread IDs already have a hook installed. The map is checked, and only when the thread ID isn't present do we set the hook. This prevents duplicate hooks, while still allowing for multiple top-level windows in the same process.

Of course, we also need to unset the hook exactly once. This is done by keeping a reference count (also in the std::map) which is incremented every time a tab is opened and decremented when it is closed. When it reaches zero, we can safely unset the hook.

And since this map will be shared between multiple BHOs on different threads, accessing it must be guarded, for which I use a critical section.

To facilitate all this, we need to add a few members to the BHO's class.

class ExampleBHO : public IObjectWithSite
{
    /* For other members, see the previous article */
private:
    struct HookInfo
    {
        HookInfo(HHOOK hook, HWND window) : Hook(hook), RefCount(1), Window(window) { }

        HHOOK Hook;
        int RefCount;
        HWND Window;
    };
    typedef std::map<DWORD, HookInfo> RefCountedHookMap;

    // This keyboard hook procedure is in addition to the one we used last time;
    // it does not replace it
    static LRESULT CALLBACK TopLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam);
public:
    static CRITICAL_SECTION _topLevelHookLock;
    static RefCountedHookMap _topLevelHookMap;
};

// Code to initialize the critical section omitted.
CRITICAL_SECTION SearchBrowserHelper::_topLevelHookLock;
SearchBrowserHelper::RefCountedHookMap SearchBrowserHelper::_topLevelHookMap;

Now, we can write code in SetSite to properly set, keep track of, and unset the hook.

STDMETHODIMP SearchBrowserHelper::SetSite(IUnknown *punkSite)
{
    // Code from previous article, as well as some error checking code, has been omitted.
    if( _browser != NULL ) // _browser stores the current sites IWebBrowser2 interface, if any
    {
        DWORD topLevelThreadId = GetWindowThreadProcessId(hwnd, NULL);
        DWORD currentThreadId = GetCurrentThreadId();
        if( topLevelThreadId != currentThreadId )
        {
            EnterCriticalSection(&_topLevelHookLock);
            RefCountedHookMap::iterator it = _topLevelHookMap.find(topLevelThreadId);
            if( it != _topLevelHookMap.end() )
            {
                it->second.RefCount--;
                if( it->second.RefCount == 0 )
                {
                    UnhookWindowsHookEx(it->second.Hook);
                    _topLevelHookMap.erase(it);
                }
            }
            LeaveCriticalSection(&_topLevelHookLock);
        }        
    }
    
    if( punkSite != NULL )
    {
        /* Code to retrieve the IWebBrowser2 interface goes here, which is stored in _browser */

        if( SUCCEEDED(_browser->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&hwnd))) )
        {
            DWORD topLevelThreadId = GetWindowThreadProcessId(hwnd, NULL);
            DWORD currentThreadId = GetCurrentThreadId();
            if( topLevelThreadId != currentThreadId )
            {
                EnterCriticalSection(&_topLevelHookLock);
                RefCountedHookMap::iterator it = _topLevelHookMap.find(topLevelThreadId);
                if( it == _topLevelHookMap.end() )
                {
                    HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, TopLevelKeyboardProc, NULL, topLevelThreadId);
                    _topLevelHookMap.insert(std::make_pair(topLevelThreadId, HookInfo(hook, hwnd)));
                }
                else
                {
                    it->second.RefCount++;
                }
                LeaveCriticalSection(&_topLevelHookLock);
            }
        }            
    }
    
    return S_OK;
}

Implementing the hook procedure

Chances are you want to do something whenever you handle whichever key it is you want to handle. Chances also are that that something depends on the current tab (e.g. you want to show a toolbar). From your regular tab's hook procedure this is simple; it's running on the active tab, so we could use Thread Local Storage to get a pointer to the BHO and use that. From the top-level window procedure it's not so easy. We're going to need to find the active tab and communicate with it.

There are multiple ways to do this. One way is that you could use DWebBrowserEvents2::WindowStateChanged to keep track of the currently active tab. I however chose to use EnumChildWindows to find the currently active tab. This is easy to do since the active tab is the only child window of the "TabWindowClass" class that is visible. Then to communicate I re-send the key to the active tab so its own hook procedure will catch it (of course, don't just forward all keyboard messages to the active tab; only do this for keys you want to handle!)

LRESULT CALLBACK SearchBrowserHelper::TopLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
    if( code >= 0 )
    {
        HWND hwnd = NULL;
        EnterCriticalSection(&_topLevelHookLock);
        RefCountedHookMap::const_iterator it = _topLevelHookMap.find(GetCurrentThreadId());
        if( it != _topLevelHookMap.end() )
        {
            hwnd = it->second.Window;
        }
        LeaveCriticalSection(&_topLevelHookLock);
        if( hwnd != NULL && GetActiveWindow() == hwnd )
        {
            if( IsShortcutKeyPressed(wParam) ) // This checks whether it's a key we want to handle
            {
                HWND activeTab = NULL;
                EnumChildWindows(hwnd, FindActiveTabProc, reinterpret_cast<LPARAM>(&activeTab));
                SetFocus(activeTab);
                // Dispatch to that tab's hook procedure
                PostThreadMessage(GetWindowThreadProcessId(activeTab, NULL), WM_KEYDOWN, wParam, lParam);
                return TRUE;
            }
        }
    }
    return CallNextHookEx(NULL, code, wParam, lParam);
}

BOOL CALLBACK SearchBrowserHelper::FindActiveTabProc(HWND hwnd, LPARAM lParam)
{
    WCHAR className[50];
    if( IsWindowVisible(hwnd) && GetClassName(hwnd, className, 50) > 0 && wcscmp(className, L"TabWindowClass") == 0 )
    {
        *reinterpret_cast<HWND*>(lParam) = hwnd;
        return FALSE;
    }
    return TRUE;
}

And that's all there is to it. As usual, you can find the full details in the Find As You Type source code, which is a working implementation of all this.

This is the last article in this series for now. I've covered all I wanted to cover, so until I get a request for more or think of something myself, you'll have to do without.

UPDATE: I have discovered that this method is not entirely fool-proof, particularly the way of communicating with the active tab. The SetFocus method, while it appears to achieve the desired effect, isn't meant to be used across threads as is done here.

Eric Lawrence has alerted me that this also doesn't work in windows without a toolbar; in that case, the FAYT toolbar is not shown (obviously), and (assuming you're using the default keyboard shortcut), neither is IE's own find dialog. I hope to fix this in a future version.

UPDATE 2007-10-17: A better method to communicate with the active tab is described here.

Categories: Programming
Posted on: 2007-02-21 15:43 UTC. Show comments (4)

Latest posts

Categories

Archive

Syndication

RSS Subscribe

;