Don't assert or get the user data of null surface arguments. When the callbacks are run with a null surface it means the surface was destroyed client-side but the compositor has yet to process the destroy request and has sent events referencing the surface which no longer exists on the client.
The wl_surface pointer also needs to be removed during wayland_surface_destroy to prevent it from becoming a dangling pointer which may be used if text_input_done or text_input_leave is run after the surface is destroyed. While doing so, track the hwnd instead to be consistent with keyboard and pointer.