Hello taazz! That's great and works. Thanks! Thread receives the message WM_QUERYENDSESSION, and I can use the function: String is displayed as reason and Windows waits to my app. Unfortunately, the thread is locked waiting for jobs to finish without sending FALSE as response to WM_QUERYENDSESSION to Windows. Apparently Windows continues to wait (I can't test it enough to verify), but according to MSDN app could be forcely closed because FALSE has not been sent.
How about change the wait code to add some time out and respond to messages, then check if the threads have ended and restart wait with time out again.
Well, finally I've solved the question. My solution has been setted in the following way:
1- My App has a main thread and other threads. One of these threads manages Windows messages like WM_QUERYENDSESSION and WM_ENDSESSION (Let's say, this thread is my "Messages Thread").
2- When WM_QUERYENDSESSION is received, "Messages Thread" enables a flag so my main thread is warned about Windows is shutting down. "Messages Thread" waits until Main Thread answers (My main thread is essentially a loop, so anwser is done inmediately). When answer is received, "Messages Thread" uses function "ShutdownBlockReasonCreate" to define a reason and finally "Messages Thread" returns 0 (or FALSE) to Windows.
3- My main thread (already warned about shutdown) begins to cleanup all tasks (And Windows displays "my reason to delay shutdown"). When all tasks are done, I need to destroy the "Reason" previously defined. So, I need to call to this function:
Function ShutdownBlockReasonDestroy(Handle: hWnd): Bool; StdCall; External 'user32';
The handle for both functions is the handle returned by "CreateWindow" when I've created the thread.
Just like "ShutdownBlockReasonCreate", I can't use ShutdownBlockReasonDestroy outside "Messages Thread" so I defined a new message (e.g. WM_USER) on "Messages Thread" so I can use that function too.
4- Finally, before shutting down, I post a new message to "Messages Thread" with
PostMessage(Handle_to_my_thread,WM_USER,0,0);
so ShutdownBlockReasonDestroy is called... and all done!
Thank you very much to taazz and engkin for your help!