These types of issues fall under the canopy of 'Windows Synchronization Objects' and lead into such topics as Mutexes (Mutual Exclusion Synchronization Objects) and semiphores. In the program I posted yesterday there was a very simplistic method of not allowing the user to launch additionl threads until the one underway was finished by simply disabling the button control that starts the thread until the thread is finished, and then re-enabling it. If you want something more sophisticated, such as the ability to cancel mid way through, then you need the signaling potentials of the above listed sychronization topics.
I'm personally just beginning to use these things - not so much mutexes, but threads & such. Up to this point most of my apps are single threaded. When lengthy procedures are running I usually just change the cursor to an hourglass or use a progress bar, and most of my computations with the speed of modern computers only take several seconds.
However, if you want to get into this the last chapter of Brent E. Rector and Joseph M. Newcommer's 'Win32 Programming' book cover Synchronization objects in pretty gory detail. One place I've used mutexes successfully is I create one based on a file name chosen by the user in an open file dialog box, and I don't let the user open a second invocation of the same file. This I do in my Windows CE data recorder programs. The object is in a signalled state and that can be tested for every file the user tries to open. It essentially creates a global entity within the Windows Operating System. Hope this info helps.
Another thought, rather than getting into the whole data synchronization topic, and if you're willing to entertain simplistic solutions, is just to use the EnableWindow(), IsWindowEnabled() Api functions, as I previously alluded. Simply disable the button or menu command until the process is finished, then re-enable it. Also check out the IsWindowEnabled() function. It is essentially your TRUE/FALSE switch in a more elegant costume.