Posts for June 2007

Bitten by COM

It's official: I've been spoiled by the niceties of .Net. In yesterday's IXMLHTTPRequest example, I made a very stupid mistake.

What I did is a mistake that every COM programmer should be aware of: I created a circular reference. Since COM is reference counted, circular references create memory leaks. For those who're not familiar with this particular problem (perhaps because they've never used a reference counted system), here's what happens: when object A is created, its reference count is 1. A creates object B and holds a reference to it; its reference count is also 1. B takes a reference back to A, so its reference count becomes 2. Now the original creator of A is done with it, and releases it: the count for A is now one. But because B still holds a reference to A, its count doesn't reach zero until B is destroyed. But B will not be destroyed until its own count reaches zero, which won't happen until A is destroyed. Neither A nor B ever gets destroyed, so you get a memory leak.

In my case, the event sink object held a reference to the IXMLHTTPRequest, which held a reference to the event sink. In my sample, this wasn't much of a problem since the objects would get forcably released when CoUninitialize was called, which happened only a few nanoseconds after we were done with the objects. But in a real application, this can be a problem.

The solution is fortunately very easy: cheat with the reference count. By having the event sink not call AddRef on the request, the problem disappears. And since we can ensure that the event sink object will never use request object after it's been freed, this is safe.

I've updated the sample code. In addition to this change, I've also made the reference counting of the event sink object thread safe, since it was being used on more than one thread.

Categories: Programming
Posted on: 2007-06-22 07:04 UTC. Show comments (6)

Using IXMLHTTPRequest onreadystatechange from C++

Pete Warden left a comment on my blog that he's porting a Firefox extension to IE and that he appreciates the articles I wrote about IE add-on development. Thanks Pete, good to know they're good for something. :)

Anyway, I was reading his blog and came across this post. He indicates he isn't going to use MSXML's XMLHTTPRequest object, because using the onreadystatechange event from C++ is too complicated. While I agree that it's poorly documented and hampered by the fact that almost all samples that talk about it use ATL, it's not actually that hard to use.

The documentation for onreadystatechange suggests you need to use connection points to get the event, but that isn't true (it doesn't even appear possible as querying an XMLHTTPRequest object for either IConnectionPoint or IConnectionPointContainer fails).

In fact, all you need to do is create a simple IDispatch implementation, and pass this to the onreadystatechange property. It will call Invoke with a dispIdMember of zero every time the onreadystatechange event is raised. The class that receives the event is pretty vanilla:

class XMLHttpEventSink : public IDispatch
{
public:
    XMLHttpEventSink(IXMLHTTPRequest *request) : _refCount(1), _request(request) 
    { 
        // Don't increase the reference count to the request object;
        // doing so would create a circular reference and thus a memory leak.
    }
    virtual ~XMLHttpEventSink() 
    { 
    }

    // IUnknown 
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    // IDispatch
    STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);        
    STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);    
    STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
private:
    ULONG _refCount;
    IXMLHTTPRequest *_request;
};

As you can see, it's a simple class that implements the IDispatch interface. For this example, I'm also storing the IXMLHTTPRequest object itself in a member so we can use it later. The implementations of the IUnknown methods are bog-standard COM, and all IDispatch members except Invoke never get called so they can just return E_NOTIMPL. I won't post that code here, but if you're really interested in it, you can see it in the full sample. An example Invoke implementation that checks the state and prints part of the response when completed is shown below:

STDMETHODIMP XMLHttpEventSink::Invoke(DISPID dispIdMember, const IID &riid, LCID lcid, WORD wFlags,
                                      DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
    // Since this class isn't used for anything else, Invoke will get called
    // only for onreadystatechange, and dispIdMember will always be 0.

    long state;
    // Retrieve the state
    _request->get_readyState(&state);
    std::wcout << L"State: " << state << std::endl;
    if( state == 4 )
    {
        // The request has completed.
        // Get the request status.
        long status;
        _request->get_status(&status);

        std::wcout << L"Status: " << status << std::endl;

        if( status == 200 )
        {
            // Get the response body if we were successful.
            _bstr_t body;
            _request->get_responseText(body.GetAddress());
            std::wstring bodyString = body;

            std::wcout << L"First part of response: " << std::endl;
            if( bodyString.length() > 200 )
                bodyString = bodyString.substr(0, 200);
            std::wcout << bodyString << std::endl;
        }
    }
    return S_OK;
}

Note that this code has no error handling for reasons of readability. In a real application, you will want to add that.

The one thing that remains is the question of how we use this with IXMLHTTPRequest itself. As I indicated, this is much simpler than the documentation makes it out to be. We simply instantiate the event sink object, and pass it to IXMLHTTPRequest::put_onreadystatechange:

// Create XMLHTTPRequest object.
IXMLHTTPRequest *request;
CoCreateInstance(CLSID_XMLHTTP30, NULL, CLSCTX_INPROC, IID_IXMLHTTPRequest, reinterpret_cast<void**>(&request));

// Open the request
_bstr_t method = L"GET";
_bstr_t url = L"http://www.ookii.org/rss.ashx";
_variant_t async = true;
request->open(method, url, async, _variant_t(), _variant_t());

// Hook up the onreadystatechange event handler
IDispatch *sink = new XMLHttpEventSink(request);
request->put_onreadystatechange(sink);

// Send the request
request->send(_variant_t());

Note again that this code has no error handling. You may also note that I use MSXML 3; this version of MSXML is supported, and was included with IE6 so almost everybody has it.

And there you have it. Not quite as difficult as it may seem at first glance.

Download the full sample.

Categories: Programming
Posted on: 2007-06-21 10:10 UTC. Show comments (5)

Entrance exam preparations

Some of you may have noticed that I rarely write about university stuff. The simple explanation is that there's simply not a lot to say yet. I haven't started doing research yet, because I first have to take the PhD student entrance exam in August. Only when I pass that will I be a real PhD student and will the real work start.

So my university life currently consists of studying Japanese and studying for the exam. The latter involves a lot of reading, mostly of stuff that I've done before in the past six years.

And blog posts of the nature "today I read two chapters in book X" wouldn't be very entertaining, now would they? But rest assured, if there is news I'll be sure to say it.

The first "event" I have coming up is the TOEFL test, which is an English language proficiency test I have to do as part of the entrance examinations, so it shouldn't be a problem. That'll be in the morning on July 7th (so that'll be a busy day).

Categories: University, Japan
Posted on: 2007-06-14 07:57 UTC. Show comments (0)

Japan Philharmonic

It is a widely known fact that my primary music preference lies with rock, heavy metal, and associated genres. This isn't however to say I don't also enjoy other types of music, quite on the contrary in fact. It is not so widely known that I also enjoy classical music a great deal (as well as contemporary symphonic music, such as movie soundtracks).

Currently my favourite composer is without a doubt Sergei Rachmaninov. His most well-known piece is Piano Concerto's number 3, which is among my favourites as well.

Yesterday evening I happened to stumble upon an upcoming performance of this piece, along with his Symphony No. 2 (which is also very good), by the Japan Philharmonic Orchestra, on July 7th in Yokohama (less than an hour from here). I have never actually attended a classical performance before (although I have wanted to on a few occasions, I never got around to actually doing it), and this seemed like an ideal opportunity.

My initial plan was to wait until today (it was quite late yesterday when I found this) and ask around if somebody else wanted to go as well (I know several people here who would most likely be interested). Only, then I found out that tickets for the concert had been on sale since January, and that there were only two seats left! And these were in completely different sections, so even asking one other person to come would be a bit pointless.

On a whim, I ordered a ticket anyway. It was too good an opportunity to pass up. And it was probably a good thing too, because I checked this morning, and now it's sold out completely. Yes, I would've preferred to go with someone else, but better luck next time.

So next month I'm going to see this concert. Should be cool! Tanoshimi ni shimasu! (I'm looking forward to it)

Categories: Personal, Japan
Posted on: 2007-06-14 07:46 UTC. Show comments (0)

Updated stroke data for Japanese Input

I have released a (very) small update to my Japanese Input application. The update consists of an update stroke data file. I discovered that the old file did not include the kanji 場 (Unicode U+5384), which is a fairly common kanji (and a jouyou kanji). The new file includes this kanji so you will be able to write it using Japanese Input.

The CAB and source files on the Japanese Input page now include the updated stroke data, so if you downloaded it after this post was made you should be fine. If you're not sure, simply try to write the kanji 場. If it recognizes it, you've got the new version (be sure not to confuse it with the kanji 揚, which the old (and new) version does recognize).

If you have the old version, you can either download the updated CAB file and reinstall (I recommend you soft-reset your device before doing this), or you can manually update the stroke data file, using the procedure described below.

  1. Soft-reset your device (this is to ensure the file is not in use).
  2. Download the updated strokedata.txt file (right-click, save as).
  3. Copy the file to your device (e.g. using ActiveSync or Windows Mobile Device Center), and place it in the "\Program Files\Japanese Input" folder, overwriting the strokedata.txt file that is already there.

If you are using Japanese Input and notice any other common kanji (especially if they are jouyou kanji) that are missing, please let me know.

Categories: Software
Posted on: 2007-06-08 09:52 UTC. Show comments (45)

Latest posts

Categories

Archive

Syndication

RSS Subscribe

;