因為有時下載東西的時候,不想讓電腦自動深入睡眠,所以就開啟了離開模式。這樣不但不節能環保,而且到真正想要睡眠的時候就是一翻蛋疼。
改過自新,關閉了離開模式,同時無操作30分鐘後也會進入睡眠模式。但是在下載的時候怎麼辦呢?反正也是閒著,就寫了這東西:
增加了合上蓋子時保持喚醒功能,截圖懶得換了。
程序在最後面。
下面是實現(其實寫這個程序的目的之一就是為了學習C#……):
(所謂的)是調用這個API ( MSDN的介紹) :
EXECUTION_STATE WINAPI SetThreadExecutionState( _In_ EXECUTION_STATE esFlags );
這個API作用是允許程序通知系統在使用某些資源,以阻止系統進入睡眠或關閉顯示器。
參數esFlags是以下選項的組合:ES_AWAYMODE_REQUIRED, ES_CONTINUOUS,ES_DISPLAY_REQUIRED,ES_SYSTEM_REQUIRED。
按字面意思理解選項即可。其中ES_CONTINUOUS表示在下一次調用該API前,本次設置會一直生效。所以在大部分情況下,加上這個選項的話,只需調用一次API即可。(這個API是針對每個線程而言的,只要這個線程不退出,和CONTINUOUS一起設置的選項就會一直生效)。
若是單獨使用ES_CONTINUOUS選項,則會恢復睡眠策略。
using System.Runtime.InteropServices; // 按照API原型,將類型轉換C#的類型聲明即可 [DllImport("kernel32.dll")] static extern uint SetThreadExecutionState(uint esFlags); // 選項所用到的常數 const uint ES_AWAYMODE_REQUIRED = 0x00000040; const uint ES_CONTINUOUS = 0x80000000; const uint ES_DISPLAY_REQUIRED = 0x00000002; const uint ES_SYSTEM_REQUIRED = 0x00000001;
C#所有的方法變量都必須聲明在一個類裡。我把這些東西聲明到一個叫Public的類。聲明後,就可以直接調用該方法了。
該程序可以通過主界面以及托盤彈出的菜單進行選擇的設置,所以需要同步這兩個地方的狀態,Checkbox該自動打鉤時打鉤,該取消時取消等等。為了寫代碼時,不需要考慮這些東西,就抽象出了一個Option類(每次起名的時候就痛恨自己英文太差)。通過該類可以設置選項,同時也可以在裡面注冊一個委托,當選項有變時,會調用這些委托。同時,該類也會負責在設置選項時自動通知系統。注:在析構函數中,以參數ES_CONTINUOUS調用一次該API恢復原來的休眠配置。
主界面就是拉拉控件,處理下事件。注意,Checkbox的選項值可能會因為鼠標點擊以外的原因改變,所以選擇監聽鼠標點擊事件。為了處理事件時少粘貼點代碼,我用一個Dictionary將每個CheckBox和一個選項值綁定在一起。然後使用同一個事件處理函數,在函數裡,根據sender確定是哪個Checkbox發送的,再根據那個Dictionary確定需要設置什麼樣的值。 然後向Option類注冊一個委托,在選項有變時改變Checkbox到正確的狀態。
最小化時直接隱藏窗口,而不是縮小的任務欄:可以選擇監聽Resize事件,在事件中判斷窗體是不是處於最小化的狀態,是的話就隱藏窗體。更徹底的是重載窗體類的消息處理函數,並自己處理最小化消息。
protected override void WndProc(ref Message m) { const int WM_SYSCOMMAND = 0x112; const int SC_CLOSE = 0xF060; const int SC_MINIMIZE = 0xF020; const int SC_MAXIMIZE = 0xF030; if (m.Msg == WM_SYSCOMMAND) { if (m.WParam.ToInt32() == SC_MINIMIZE) { this.Hide(); return; } } base.WndProc(ref m); }
托盤:使用NotifyIcon控件。注意,這個控件必須設置ICON才能顯示。添加一個ContextMenuStrip對象作為右鍵點擊時的彈出菜單。為了讓點擊托盤時能彈出這個菜單,可以將托盤控件的ContextMenuStrip屬性設置為該菜單即可。在這裡因為我需要監聽鼠標事件,讓左鍵點擊時顯示主窗口,我就在事件處理函數中順便處理右鍵點擊了。如果是右鍵點擊,則調用該菜單的Show方法就可以了。
然後是菜單的內容。新建若干ToolStripMenuItem對象,並用ContextMenuStrip.Items.Add(…)方法將這些Item添加進菜單即可。每個Item可以監聽鼠標點擊事件,同時也可以通過設置它的Checked屬性來顯示item文本前的小鉤鉤。需要分割線的話添加ToolStripSeparator對象就可以了。
動態的托盤圖標:為了少寫點什麼讀取文件之類的代碼,就直接把托盤圖標添加進程序的資源文件裡了。方法是在項目的屬性裡選擇資源,然後就可以添加想要的資源了。需要訪問這些資源時,在myProject.Properties.Resources裡就可以訪問了。如:System.Drawing.Bitmap bitmap1 = myProject.Properties.Resources.Image01(參考MSDN)。最後再根據選項的狀態選擇相應的圖標即可。
托盤消失:直接執行Application.Exit()的話,托盤不會自動消失,得鼠標從托盤上面滑過才可以。為了讓托盤顯示,執行NotifyIcon對象的Dispose( )方法就好了。
讓程序開始運行時只顯示托盤,而不顯示主窗體。放狗搜索的時候發現這個問題讓很多新手喝了一壺。我的解決方法是:讓程序開始是不運行主窗體的代碼,只運行托盤控件的代碼。轉到Main函數,發現Main函數最後執行的是 Application.Run(…) 這個方法。最開始嘗試在這個方法的參數裡填入一個NotifyIcon對象,但是不行。然後試著直接用new新建一個NotifyIcon對象,這個時候托盤是會顯示出來,但是程序馬上就會退出了。最後發現這個方法有個無參重載版本,執行後程序就不會退出了……
:在項目的屬性裡,選擇應用程序選項卡,就可以設置圖標了。
睡眠終結者: http://files.cnblogs.com/h46incon/SleepPreventer.zip