Blog

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)

E-mail etiquette

Raymond Chen talks about using very long e-mail signatures, and on the most part I agree with him.

However, he makes one complaint that I must object against. In particular, he says "we already know your name and email address since it's in the message header". Yes, you do, but isn't it common courtesy to sign a message with your name?

The addressee knows his/her own name too, but I still think it's a good idea to start with "Hello X" or "Dear Y", or "Dear sir/madam" if I'm not sure.

Personally I think most people treat e-mail very loosely, at least in the Netherlands. If I send e-mail to a person or company that I don't know, I will treat the e-mail as if it was a letter. I will open with "Dear sir/madam" etc. But invariably I get a message back starting with "Hi Sven". Now I don't mind that sort of thing, but it's a strange assumption to make. Certainly if it was a letter people wouldn't automatically assume they could be so informal.

The Japanese live at the other end of the spectrum. Using first names is a big social faux-pas anyway over here (especially fun since no one here can pronounce my last name), except among very close friends. But many Japanese break Raymond's rules even more drastically by telling me my name, their name, the message, and then their name again.

Typically the messages will end up looking something like this:
"X-San

Y here from the office of Z.

Message goes here.

Regards,
Y"

Well, at least there's no doubt over who sent the message. :)

Categories: Personal, Random stuff
Posted on: 2007-06-07 13:47 UTC. Show comments (1)

Latest posts

Categories

Archive

Syndication

RSS Subscribe

;