The reason I said invalid is because the hwnd in the xic callback is not the hwnd stored with IMMGWL_IMC. But it's OK, because ime_ui_wndow_proc will use the correct hwnd value. In my old personal code, I used the value received by ImeSetActiveContext.
Yes we only need to target the right thread with the built-in IME UI messages. Then the currently active input context and its window will be used (there will be some minor things to fix there too).