[C#] 攔截並阻擋系統關機程序

 取自:

https://notes.andywu.tw/2018/c-sharp-%E6%94%94%E6%88%AA%E4%B8%A6%E9%98%BB%E6%93%8B%E7%B3%BB%E7%B5%B1%E9%97%9C%E6%A9%9F%E7%A8%8B%E5%BA%8F/

[C#] 攔截並阻擋系統關機程序

前言

會研究這個主題是因為最近在用系上電腦教室挖礦XDD (噓~


但是大約下午沒課後一小時就會有專門的人來一台台關機 (凸 - -" 我才剛開好的說


幸運的是負責關機的人都是按一下電源鍵然後關螢幕就換下一台去了


所以我就想說如果可以攔截開機訊號,阻斷關機繼續進行,我的挖礦程式就不會被關閉了 (太邪惡了lol...

 


以下是效果圖,explorer.exe是我寫的阻止關機程式(故意取這樣的名字,才不會讓人起疑


它會卡著系統不讓系統關閉所有程式

原理解說

在程式實作之前,我們必須先了解一下windows的關機順序


系統在接收到使用者發出的關機訊號後(不管是從開始選單的還是按一下電源鍵),會逐一對所有應用程式發出WM_QUERYENDSESSION訊息,來詢問應用程式在現階段是否可以被關閉


至於WM_QUERYENDSESSION是什麼,以下是MSDN對WM_QUERYENDSESSION的解釋

The WM_QUERYENDSESSION message is sent when the user chooses to end the session or when an application calls one of the system shutdown functions. If any application returns zero, the session is not ended. The system stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.


After processing this message, the system sends the WM_ENDSESSION message with the wParam parameter set to the results of the WM_QUERYENDSESSION message.


翻成中文的意思就是說:


如果有一個應用程式對WM_QUERYENDSESSION回傳0,則系統就不會繼續發送WM_QUERYENDSESSION,關機的程序也就因為那個應用程式而宣告暫停(就會卡在上面那張圖)


p.s. 如果這時按Force Quit,則關閉應用程式就會變成系統主動去kill,完全不會理會應用程式的回應


當送完WM_QUERYENDSESSION,那麼系統就會再接著發送WM_ENDSESSION訊息,來「通知」應用程式是否會關機


注意,WM_ENDSESSION在這邊只有通知用喔,應用程式在這個階段已經沒有決定權了


淺略了解windows關機前的程序後,我們要做的就是在WM_QUERYENDSESSION時給它回傳0,讓系統因為我們而暫時停止關機程序

程式實作

首先先開一個新的專案,類型是視窗應用程式(Windows Forms App)


Layout要怎麼設計隨便,甚至我把它Opacity設0%,隱藏起來


接下來切換到該Form的程式碼頁

 


在創建的class新增下列程式碼,override掉原本的WndProc方法

protected override void WndProc(ref Message aMessage)

{

    const int WM_QUERYENDSESSION = 0x0011;

    const int WM_ENDSESSION = 0x0016;

 

    if (aMessage.Msg == WM_QUERYENDSESSION || aMessage.Msg == WM_ENDSESSION)

        return;

 

    base.WndProc(ref aMessage);

}



這個方法是用來讓系統或硬體跟應用程式溝通的,原本在被override前裡面也已經寫好遇到WM_QUERYENDSESSION及WM_ENDSESSION等等的訊息時要執行的動作


我們現在override後讓他遇到WM_QUERYENDSESSION跟WM_ENDSESSION訊息時直接return,啥都不要做;如果是其他則執行原本被override前的WndProc方法


如果有做到這一步其實就已經算完成了


編譯並執行程式後測試看看,按下登出、關機、重新開機,會發現系統的關機程序卡在像上圖一樣的地方。

 


如果還想要進一步更改提示訊息,我們需要使用ShutdownBlockReasonCreate這個方法


這個方法的用途就跟它名字一樣,應該不用多解釋吧:))


把以下程式碼新增在這個Form的建構子裡面,也就是InitializeComponent();下面,讓Form一初始化完就執行

ShutdownBlockReasonCreate(this.Handle, "這邊填要顯示的提示");


這時Visual Studio應該會報錯,說不認得這個方法


於是我們要告訴程式這個方法的實作已經在user32.dll完成了,去user32.dll裡面找

[DllImport("user32.dll")]

public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);

新增完後記得把動態載入dll所依賴的System.Runtime.InteropServices給補上

using System.Runtime.InteropServices;

到這邊算是第二階段的完成了。

如果想要把該Form從工作管理員隱藏,就把下列程式碼也加進去

protected override CreateParams CreateParams

{

    get

    {

        var cp = base.CreateParams;

        cp.ExStyle |= 0x80;

        return cp;

    }

}

最後附上完整程式碼

using System;

using System.Windows.Forms;

using System.Runtime.InteropServices;

 

namespace NoShutdown

{

    public partial class NoShutdown : Form

    {

        [DllImport("user32.dll")]

        public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);

         

        public NoShutdown()

        {

            InitializeComponent();

            ShutdownBlockReasonCreate(this.Handle, "這邊填要顯示的提示");

        }

         

        protected override void WndProc(ref Message aMessage)

        {

            const int WM_QUERYENDSESSION = 0x0011;

            const int WM_ENDSESSION = 0x0016;

 

            if (aMessage.Msg == WM_QUERYENDSESSION || aMessage.Msg == WM_ENDSESSION)

                return;

 

            base.WndProc(ref aMessage);

        }

 

        protected override CreateParams CreateParams //Hide from Task Manager

        {

            get

            {

                var cp = base.CreateParams;

                cp.ExStyle |= 0x80;

                return cp;

            }

        }

    }

}

小提醒:如果曾經使用過一些工具去優化關機速度的可能就不會被阻擋在那個畫面。因為那些優化為了減少關機時間,不管WM_QUERYENDSESSION回傳什麼會直接kill掉。


2020年8月19日 星期三

visual studio installer programfilesfolder

 https://www.advancedinstaller.com/user-guide/folder-paths.html

Paths of the folders in the "Files and Folders" Page

The folders in the "Files and Folders" page use predefined and custom installer properties which store their paths.

Folder NameProperty NameSample PathComments
Application FolderAPPDIRC:\Program Files\Your Company\Your Applicationthis is the default value and it can be configured
Application Shortcut FolderSHORTCUTDIRC:\Documents and Settings\<username>\Start Menu\Programs\Your ApplicationC:\Users\<username>\Start Menu\Programs\Your Application on Vista or above; this is the default value and it can be configured
Program FilesProgramFilesFolderC:\Program FilesC:\Program Files (x86) on a 64-bit machine
Common FilesCommonFilesFolderC:\Program Files\Common FilesC:\Program Files (x86)\Common Files on a 64-bit machine
Program Files 64ProgramFiles64FolderC:\Program Filesresolved only on a 64-bit machine
Common Files 64CommonFiles64FolderC:\Program Files\Common Filesresolved only on a 64-bit machine
Windows VolumeWindowsVolumeC:\
TemporaryTempFolderC:\Documents and Settings\<username>\Local Settings\TempC:\Users\<username>\Local Settings\Temp on Vista or above
WindowsWindowsFolderC:\Windows
FontsFontsFolderC:\Windows\Fonts
SystemSystemFolderC:\Windows\system32C:\Windows\SysWow64 on a 64-bit machine
System 16System16FolderC:\Windows\systemused on older Windows versions
System 64System64FolderC:\Windows\system32resolved only on 64-bit machines
Start MenuStartMenuFolderC:\Documents and Settings\<username>\Start MenuC:\Users\<username>\Start Menu on Vista or above
ProgramsProgramMenuFolderC:\Documents and Settings\<username>\Start Menu\ProgramsC:\Users\<username>\Start Menu\Programs on Vista or above
StartupStartupFolderC:\Documents and Settings\<username>\Start Menu\Programs\StartupC:\users\<username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup on Vista or above
DesktopDesktopFolderC:\Documents and Settings\<username>\DesktopC:\Users\<username>\Desktop on Vista or above
FavoritesFavoritesFolderC:\Documents and Settings\<username>\FavoritesC:\Users\<username>\Favorites on Vista or above
My DocumentsPersonalFolderC:\Documents and Settings\<username>\My DocumentsC:\Users\<username>\Documents on Vista or above
My PicturesMyPicturesFolderC:\Documents and Settings\<username>\My Documents\My PicturesC:\Users\<username>\Pictures on Vista or above
TemplatesTemplateFolderC:\Documents and Settings\<username>\TemplatesC:\Users\<username>\Templates on Vista or above
Send ToSendToFolderC:\Documents and Settings\<username>\SendToC:\Users\<username>\SendTo on Vista or above
Administrative ToolsAdminToolsFolderC:\Documents and Settings\All Users\Start Menu\Programs\Administrative ToolsC:\ProgramData\Start Menu\Programs\Administrative Tools on Vista or above
Application DataAppDataFolderC:\Documents and Settings\<username>\Application DataC:\Users\<username>\AppData\Roaming on Vista or above
Common Application DataCommonAppDataFolderC:\Documents and Settings\All Users\Application DataC:\ProgramData on Vista or above
Network ShortcutsNetHoodFolderC:\Documents and Settings\<username>\NetHoodC:\Users\<username>\AppData\Roaming\Microsoft\Windows\Network Shortcuts on Vista and above
Recent ItemsRecentFolderC:\Documents and Settings\<username>\RecentC:\Users\<username>\AppData\Roaming\Microsoft\Windows\Recent on Vista and above
Printer ShortcutsPrintHoodFolderC:\Documents and Settings\<username>\PrintHoodC:\Users\<username>\AppData\Roaming\Microsoft\Windows\Printer Shortcuts on Vista and above
Local Application DataLocalAppDataFolderC:\Documents and Settings\<username>\Local Settings\Application DataC:\Users\<username>\AppData\Local on Vista or above
Public DocumentsPublicDocumentsFolderC:\Documents and Settings\All Users\Documents\C:\Users\Public\Documents\ on Windows Vista
Windows LibrariesWindowsLibrariesFolderC:\Users\<username>\AppData\Roaming\Microsoft\Windows\Libraries\C:\Users\<username>\AppData\Roaming\Microsoft\Windows\Libraries\ on Windows 7 or above
IIS WWW RootIIsWWWRootFolderC:\Inetpub\wwwroot

All the above folders are predefined for Windows Installer except for the first two folders which are proprietary for Advanced Installer. When the installation package runs, Windows Installer will automatically resolve their paths according to the target machine's configuration.

Depending on the package type, the paths will change; this means that if the package is per-user the paths will use "...\<username>\..." or if it is per-machine the paths will use "...\Public\..." instead.

If a package is per-machine and shortcuts are present in the AppDataFolder, the system redirects the shortcuts to the ProgramData folder.