When an I/O completes (whether synchronously or asynchronously), the event is signaled and completion status notifications are queued. The
GetOverlappedResult/ function can be used to wait on an I/O that has already completed; it will merely return immediately. If you ask
HasOverlappedIoCompleted whether the I/O has completed, and the I/O completed synchronously, it will correctly report, "Yeah, of course it completed. Heck, it completed a long time ago!"
In other words, you can logically treat the case of an asynchronous I/O request completing synchronously as if it had completed asynchronously. It just completes asynchronously before you even blinked.