Thanks for clarifying, Jonney. I also tried the sample project you provided, and even after trying many things, I couldn't find a way to successfully trap WM_IME_KEYDOWN.

I have no idea why that message isn't being captured. I think LaVolpe's suggestion in your other thread, to just use a temporary TextBoxW, is the best solution.
For what it's worth, I did find some bugs in your ImmGetCompositionString code. Change the declaration to this:
Code:
Public Declare Function ImmGetCompositionStringW Lib "imm32.dll" (ByVal himc As Long, ByVal dw As Long, ByVal lpv As Long, ByVal dw2 As Long) As Long
Whenever you pass a pointer directly to an API (StrPtr, VarPtr), you need to change the API parameter to be ByVal instead of ByRef.
Another bug is this: when you pass 0 as the length to ImmGetCompositionString, so it will return the size of the string buffer, the buffer size is returned in
bytes, not characters, and it doesn't include the null-terminating character. Because of this, you might find it easier to pass the function a byte array instead of a VB string, then convert the byte array after the API has filled it.
However, even with these changes, I still don't get useful results from the function. It could possibly be an ANSI/Unicode issue, or maybe there is another bug I haven't caught...?