Pues como te lo puse. Las funciones reales serían:
/* PeekMessage para no bloquear la ejecucion si no hay mensajes */
if (PeekMessage(...)) {
TranslateMessage(...);
DispatchMessage(...);
/* Aqui retornamos justo despues de procesar el mensaje */
}
Ahora, cierto que en las aplicaciones de Windows tenemos un bucle principal de eventos, normalmente con GetMessage, pero no sé por qué piensas que estaríamos entrando de nuevo en él. Aquí lo que hacemos es simplemente verificar la cola de mensajes, y si hay alguno, DispatchMessage se encargaría de que se invoque nuestro
procedimiento de ventana (no el bucle principal, que me parece que es tu confusión), y lo procese, y luego retornamos a donde te puse, a seguir con la tarea pesada.
En cuanto a lo otro, eso depende del programa. Algo común es que, una vez que se presiona un botón para una acción así, éste se deshabilite para evitar múltiples pulsaciones, y sólo se habilite de nuevo una vez finalizada la tarea. Alternativamente, algunos programas hacen que el mismo botón sirva para iniciar la ejecución de la tarea, y para cancelarla. Si se presiona mientras ya se está ejecutando la tarea, provocaría que sea cancelada.