Recent

Author Topic: [SOLVED] ShutdownBlockReasonCreate and handles...  (Read 9230 times)

nrs1022

  • Newbie
  • Posts: 3
[SOLVED] ShutdownBlockReasonCreate and handles...
« on: July 31, 2014, 02:07:59 am »
Hello everyone! I have an app on Windows without visible windows that runs different background jobs and the app has no user interaction at all (it's like a service).

The app has a thread processing Windows messages like WM_QUERYENDSESSION and WM_ENDSESSION. When user logouts, my app receives the WM_QUERYENDSESSION, but some background jobs on my app needs more than 5 seconds to be cancelled. Because Windows Vista and onwards implements "reasons" to delay shutdown, I wish to implement it on my app but I have a problem.

Declaration for ShutdownBlockReasonCreate is:

Function ShutdownBlockReasonCreate(Handle: hWnd; Msg: lpcwstr): Bool; StdCall; External 'user32';

My problem is with parameter "Handle". According with MSDN http://msdn.microsoft.com/en-us/library/windows/desktop/aa376877%28v=vs.85%29.aspx "This function can only be called from the thread that created the window specified by the hWnd parameter. Otherwise, the function fails and the last error code is ERROR_ACCESS_DENIED.".

Which is the "handle" to use? The handle of my main thread? I've read on Delphi examples using "Application.Handle" as parameter, but I don't find an equivalent on FPC. If I use the thread handle (The thread used for processing the messages) received return code 87 (ERROR_INVALID_PARAMETER), and Hwnd can't be 0 because I received code 5 (ERROR_ACCESS_DENIED).

Thank you to all for your help!!! And sorry for my bad english...

Nicolas.
« Last Edit: July 31, 2014, 10:26:40 pm by nrs1022 »

taazz

  • Hero Member
  • *****
  • Posts: 5365
Re: ShutdownBlockReasonCreate and handles...
« Reply #1 on: July 31, 2014, 04:33:53 am »
You have a thread that handles messages which is impossible with out a window handle, so call it from the thread and passing that window handle in the handle parameter.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: ShutdownBlockReasonCreate and handles...
« Reply #2 on: July 31, 2014, 04:53:08 am »
Use Win32WidgetSet.AppHandle from Win32Int:
Code: [Select]
uses
  .., Win32Int;
...
  ShutdownBlockReasonCreate(Win32WidgetSet.AppHandle,...

or use WidgetSet.AppHandle from InterfaceBase:
Code: [Select]
uses
  .., InterfaceBase;
...
  ShutdownBlockReasonCreate(WidgetSet.AppHandle,...

I guess...

Edit:
If AppHandle didn't work, here is one more guess. Try Application.MainFormHandle

2nd Edit:
Welcome to FPC/Lazarus.
« Last Edit: July 31, 2014, 05:04:39 am by engkin »

nrs1022

  • Newbie
  • Posts: 3
Re: ShutdownBlockReasonCreate and handles...
« Reply #3 on: July 31, 2014, 05:27:15 am »
You have a thread that handles messages which is impossible with out a window handle, so call it from the thread and passing that window handle in the handle parameter.

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.

Use Win32WidgetSet.AppHandle from Win32Int:
Code: [Select]
uses
  .., Win32Int;
...
  ShutdownBlockReasonCreate(Win32WidgetSet.AppHandle,...

or use WidgetSet.AppHandle from InterfaceBase:
Code: [Select]
uses
  .., InterfaceBase;
...
  ShutdownBlockReasonCreate(WidgetSet.AppHandle,...

I guess...

Edit:
If AppHandle didn't work, here is one more guess. Try Application.MainFormHandle

2nd Edit:
Welcome to FPC/Lazarus.

Hello engkin and thank you  :) ! Unfortunately, Application.MainFormHandle and the units are not working because I'm on pure Windows API and I'm not using Lazarus (Only FPC). Until now, I'm out of luck trying to replace the "Application.handle" in my case.

taazz

  • Hero Member
  • *****
  • Posts: 5365
Re: ShutdownBlockReasonCreate and handles...
« Reply #4 on: July 31, 2014, 05:33:44 am »
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.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

nrs1022

  • Newbie
  • Posts: 3
Re: ShutdownBlockReasonCreate and handles...
« Reply #5 on: July 31, 2014, 10:24:47 pm »
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!

 

TinyPortal © 2005-2018