How to wait for a timer-controlled process to complete

In my desktop app, the user can launch a process whereby 2-way communication with a device occurs, and this process takes about 30 seconds to complete.
I implemented the process with a separate window, which pops up, creates a timer, runs the process, and then stops with a “complete” status.
I want the main window to detect the complete status and act upon it. But it cannot just wait in a loop for that status, because then nothing happens…the program just locks up. In the past, I would have put a DoEvents call in that loop, but I understand now that is no longer supported.

I can see this same functionality could be implemented in other ways. For instance, implement the process with a container control and have it generate an event when complete. Or, as the Window object has event definitions, perhaps the process window can raise an event that the main window can handle (though I have no clue as to how to attach the handler in this circumstance).

Also I would sooner block the main window while the process completes.

What is the best way to implement this?

Add a completed method to your main window that will be called by the separate window, at the same time it stops with its complete status.

OK that works…should have thought of that.
What if I want to block any further activity on the main window? Without having to give it a state and then wrap every action it performs in an If().
Perhaps making the popup window modal?