PortableApps / Launcher

The PortableApps.com Launcherâ„¢ allows developers, publishers and even technical end-user to portablize apps in PortableApps.com Format without needing to write any code.
https://portableapps.com/apps/development/portableapps.com_launcher
GNU General Public License v2.0
47 stars 13 forks source link

Improve Windows Shutdown handling #1

Open GordCaswell opened 7 years ago

GordCaswell commented 7 years ago

https://portableapps.com/comment/223241#comment-223241

daemondevin commented 7 years ago

Try something like this:

;=== Prevent Win Shutdown
!include nsDialogs.nsh
!define /ifndef WS_POPUP 0x80000000
Function CreateShutdownBlockReason
    StrCpy $1 $hwndParent
    ${If} $1 Z= 0 ; $hwndParent is 0, create a new window for silent installers.
        System::Call 'USER32::CreateWindowEx(i0,t"STATIC",t"$(^Name)",i${WS_CHILD}|${WS_POPUP},i0,i0,i0,i0,pr1,i0,i0,i0)p.r1'
    ${EndIf}
    System::Call 'USER32::ShutdownBlockReasonCreate(pr1,w"$AppNamePortable is running and still needs to clean up before shutting down!")'
FunctionEnd

What this does is allows for sufficient time for the portable to exit (I believe the default is 5 seconds, which should allow enough time to close). This default value of 5 seconds can be changed in the Registry (what reg key it is escapes me right now, however I don't think tampering with this key is a good idea either--plus it would need admin rights I believe anyway). This is just a quick answer ..it's not meant to be a full blown solution as I have not tested this fully in regards to having multiple PAFs open at once. This fix still needs work, I'm sure.

Now I'm not sure of a better place to call this function other than Function .OnInit. I'm assuming it should be used inside the Function .OnInit as this is a callback function and runs (obviously) on initialization which is what we want.

You can add language support as well instead of using just that English string at the end; something like:

    ;= other code here blah blah
    System::Call 'USER32::ShutdownBlockReasonCreate(pr1,w"$(LauncherPreventShutdown)")'
FunctionEnd

Where $(LauncherPreventShutdown) holds the string for different languages. I'm sure you can take it from here.

3D1T0R commented 7 years ago

It's been a while since I looked into this, but if I remember correctly there's a way to postpone the shutdown for as long as necessary for it to clean up & exit properly, as long as the end user doesn't tell windows to force an immediate shutdown. I'll have to check on it again.

daemondevin commented 7 years ago

@3D1T0R Can you explain to me what you think the code I shared actually does?

I don't mean to seem out of sorts here but the code I shared does exactly what you just said. You can tell because I explained the usage underneath the code snippet.

3D1T0R commented 7 years ago

You stated that it will make it wait 5 seconds (unless some registry key is altered, which probably resides in part of the Registry that we'd need Admin privileges to alter, which makes that something we wouldn't want to touch, let alone rely on).

The issue I'm bringing up is that 5 seconds is not always enough time (especially for apps which have to copy potentially large amounts of data, e.g. OperaPortableLegacy12) and if I remember correctly, there is another way to go about it, which can do a better job of what we want here. I'll look it up and post more info on it when I have a chance.

daemondevin commented 7 years ago

I should have probably explained this better but the default 5 seconds is just the default allotment for any open application when the end-user decides to shutdown their PC (applies to Vista+). I might have missed something in my research which may be what you're referring to but in my travels I found that for Windows XP, NSIS already handles WM_QUERYENDSESSION on its own. So not much we can do there and Windows XP is a dying breed anyway.

However, for Windows Vista and later, we need to create a hidden window which is what is used to prevent the default 5 seconds by the system entirely. So with what I was saying earlier about the 5 seconds mechanism is frivolous because I forgot to outline that we use the hidden window along side of the system plugin call to USER32 for a ShutdownBlockReasonCreate and pretty much prevents/cancels the shutdown process (this doesn't help if the end-user decides to do a hard-restart/shutdown though lol) until our portable is exited.

I'm sorry for my lack of explanation earlier; to my defense I was tired.. Lol.