在WM裝置中,大多數的電力來源都是電池,所以一些省電的動作也會產生,例如說多久沒有操作裝置的話,系統會關閉LCD的背光以節省電力,使用AC電源的時候,LCD的背光應該多亮,使用電池的時候背光應該多亮等等
- 我的程式要一直跑,無論如何我不想讓系統進入待機的狀態,可不可以?
- 一段時間沒有動作的話,系統會自動關閉背光,但是我在放電影啊,拜託不要關
- 能不能讓我的程式去控制關閉背光的時間?
- 能不能讓我控制背光的級距(Level)?
_
Public Sub SystemIdleTimerReset()
End Sub
使用的時候也是直接呼叫就可以了
這樣就可以讓系統不進入待機了;這個時候程式人的潔癖又來了,那我要多久呼叫一次SystemIdleTimerReset?每秒?每分鐘?
那麼就要知道多久會進入待機了,這個值也是放在登錄檔中,利用登錄編輯程式(remote tool),可以在這個位置找到
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Power\BattPowerOff
知道放置的位置之後,就可以利用程式把這個值給讀出來了,像是下面的方式
''' 取得系統進入待機前等待的秒數
''' reference http://support.microsoft.com/default.aspx/kb/180898
'''
'''
'''
Private Function GetSuspendTimeOutSetting() As Integer
Dim hHKLM As Microsoft.Win32.RegistryKey
hHKLM = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System\CurrentControlSet\Control\Power", False)
Dim intSuspendTimeout As Integer = CInt(hHKLM.GetValue("BattPowerOff", -1))
hHKLM.Close()
If intSuspendTimeout <> -1 Then
''成功取得reg內容
Return intSuspendTimeout
Else
Return -1
End If
End Function
於是乎我們就搞定了第一個需求了,而在上圖中有一個用粉紅色的設定值
PowerManager/SystemIdleTimerReset
這個也請先有個印像,後面會談到這個部分。
搞定了不讓系統進入待機了,但是第二個問題就接著來了;系統不會進入待機模式了,但是背光的Timeout時間一到還是會關掉耶,能不能一直亮著?關掉我就看不到東西了啊。
那麼要解決這個問題,也是需要呼API,這時候我們會用到SetPowerReuirement、ReleasePowerRequirement,宣告的方式向下面這樣
_
Public Function SetPowerRequirement(ByVal pvDevice As String, ByVal DeviceState As PowerState, _
ByVal DeviceFlags As Integer, ByVal pvSystemState As IntPtr, ByVal StateFlags As Integer) As IntPtr
End Function
''reference http://msdn.microsoft.com/en-us/library/ms919803.aspx
_
Public Function ReleasePowerRequirement(ByVal hPowerReq As IntPtr) As Integer
End Function
除了function的宣告之外,還有一些常數值必須要宣告
Public Const POWER_FORCE As Integer = &H1000
Public Enum PowerState
PwrDeviceUnspecified = -1
D0 = 0 'full on
D1 = 1 'low power
D2 = 2 'standby
D3 = 3 'sleep
D4 = 4 'off
PwrDeviceMaximum = 5
End Enum
使用的方式會像下面這樣,發出請求時
hResult = SetPowerRequirement("BKL1:", PowerState.D0, POWER_NAME Or POWER_FORCE, Nothing, Nothing)
這邊這個hResult要記起來,因為使用完之後我們要釋放掉我們的請求,而BKL1:這個指的就是LCD的部分了;釋放的部分會像下面這樣
在做SetPowerRequirement的時候有幾個部分要注意
- 利用這個API可以對系統發出請求,將power設定在normal或是sleep的狀態,也就是亮起或是關閉,亮一點或是暗一點是辦不到的
- SetPowerRequirement可以接受多重呼叫,也就是有可能很多隻成是都會呼叫SetPowerRequirement來請求系統將power設定成某一種狀態,那打架的時候怎麼辦?如果發生打架的情形,系統會將Power設定在比較亮的狀態,也是是說,A程式要求D4的狀態,B程式要求D0的狀態,那最後Power會是D0
那麼SetPowerReurirement可以接受多重呼叫,也就表示我的呼叫不一定會成功,那有沒有比較惡霸的方式,不管三七二十一,變成我要的狀態就對了?
是有的,但是在說明這個方法之前,要先知道一些事情
WM系統會自動維護電源狀態,還記得上面利用SetPowerRequirement時會傳回一個intptr嗎?最後不使用的時候會利用這個intptr來做release的動作,那萬一如果程式異常結束(中止)的話,會怎麼樣?WM系統也會自動幫我們做釋放,所以不會造成不良影響;而接下來要說明的方式是強制把power設定到某一狀態,所以如果沒做釋放動作,那這個時候WM系統的電源管理機制會錯亂,其他應用程式也就跟著不能對該設備(BKL1:)做操作了,所以切記,一定要做釋放的動作。
比較惡霸的方式就是呼叫SetDevicePower,宣告的方式是下面這樣
_
Public Function SetDevicePower(ByVal pvDevice As String, ByVal dwDeviceFlags As Integer, ByVal DeviceState As Integer) As Integer
End Function
呼叫的時候會像下面這樣
D0就是指定一直亮著的狀態,切記切記,使用完畢請記得要放回原位,記得用下面方式讓控制權回到WM系統
好啦,滿足了不睡覺、不熄大燈的需求之後,還有什麼呢?接下來就是來看看怎麼去控制系統關閉背光的時間;在WM系統中,一般會進到”設定”裡面去做修改,像是下圖
啥?最短只能設到1分鐘?當插上外部電源時,通常來說環境都是很明亮的,不能10秒後就關掉嗎?
這個時候,一樣先來這些相關的資料是存放再哪裡,先來看看登錄檔
在HKEY_CURRENT_USER\ControlPanel\BackLight裡面,就可以看到相關的設定值了,下面只列出會用到的名稱跟功能
- ACBrightness:當使用外部電源時,背光的亮度
- ACTimeout:當使用外部電源時,沒有對裝置進行操作,經過多久(秒)後,關閉背光
- Brightness:當使用電池電力時,背光的亮度
- BatteryTimeout:當使用電池電力時,沒有對裝置進行操作,經過多久(秒)後,關閉背光
這邊會用到Timeout相關的設定,如果你從系統去做變更,也會在登錄檔裡面看到對應的變化(要refresh一下);好,那麼怎麼從程式去做控制呢?當然首先要先變更登陸檔裡面的設定值,但是光改變設定值,系統不知道我改了啊,所以還要喊一下系統,讓他知道有這件事,也就是觸發一個變更的事件,那麼程式碼會像下面這樣
API宣告
Public Function CreateEvent(ByVal lpEventAttributes As IntPtr, ByVal bManualReset As Boolean, _
ByVal InitialState As Boolean, ByVal lpName As String) As IntPtr
End Function
_
Public Function EventModify(ByVal hEvent As IntPtr, ByVal func As Integer) As Boolean
End Function
_
Public Function CloseHandle(ByVal hObject As IntPtr) As Boolean
End Function
使用時會像下面這樣
If SetTimeout("ACTimeout", 5) Then
TextBox1.Text = "Set timeout success"
Else
TextBox1.Text = "Set timeout failed"
End If
End Sub
'''
''' 設定背光關閉時間
'''
''' 值名稱,ACTimeout / BatteryTimeout
''' Timeout秒數
'''
'''
Private Function SetTimeout(ByVal RegKeyName As String, ByVal Timeout As Integer) As Boolean
Dim hUSER As Microsoft.Win32.RegistryKey
hUSER = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("ControlPanel\BackLight", True)
hUSER.SetValue(RegKeyName, Timeout, Microsoft.Win32.RegistryValueKind.DWord)
hUSER.Flush()
hUSER.Close()
Return CreateChangeEvent("PowerManager/ReloadActivityTimeouts")
End Function
'''
''' 產生變更的事件
'''
''' 事件名稱
''' 成功與否
'''
Private Function CreateChangeEvent(ByVal EventName As String) As Boolean
Dim hEvent As IntPtr
Dim bolReturn As Boolean = False
hEvent = CreateEvent(IntPtr.Zero, False, True, EventName)
bolReturn = EventModify(hEvent, enumEvent.EVENT_SET)
CloseHandle(hEvent)
Return bolReturn
End Function
於是乎,我們就可以由程式裡面去控制多久之後去關閉背光了。
就在不久之前,從登錄檔裡面也可以看到調整背光亮度的設定值,那我是不是也可以如法炮製,利用同樣的方式去做調整呢?原則上是可以,為什麼說原則上呢?這又有一段故事要講..在背光的亮度調整部分,由於各家廠商硬體不同,所以會去修改到Driver,而當背光修改之後,一般需要去觸發BackLightChangeEvent,但是各家廠商實作之後這個Event名稱有可能就會不同了,目前在網路上查資料,有看到BackLightChangeEvent,也有看到SDKBackLightChangeEvent,而我的HTC Tytn2都不是這兩個..
所以這部分就沒有通用解了,下面說明一般的方式以及HTC變更的方式
一般方式
If SetBrightness("ACBrightness", 10) Then
TextBox1.Text = "Set Brightness success"
Else
TextBox1.Text = "Set Brightness failed"
End If
End Sub
Private Function SetBrightness(ByVal RegKeyName As String, ByVal Level As Integer) As Boolean
Dim hUSER As Microsoft.Win32.RegistryKey
hUSER = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("ControlPanel\BackLight", True)
hUSER.SetValue(RegKeyName, Level, Microsoft.Win32.RegistryValueKind.DWord)
hUSER.Flush()
hUSER.Close()
Return CreateChangeEvent("BacklightChangeEvent")
End Function
那麼HTC的部分怎麼辦呢?在不知道抓掉多少根頭髮之後,總算在xda上面找到這篇
http://forum.xda-developers.com/showthread.php?t=450318&page=31
直接呼叫dll來做調整的動作,所以在API的宣告上做了像下面這樣的Class
Imports System.Runtime.InteropServices
Public Class HTCPInvoke
'' battery backlight
_
Public Shared Function HTCUtilGetOnBatteryBrightnessLevel(ByRef pValue As Integer) As Integer
End Function
_
Public Shared Function HTCUtilSetOnBatteryBrightnessLevel(ByRef pValue As Integer) As Integer
End Function
'' AC backlight
_
Public Shared Function HTCUtilSetOnPowerBrightnessLevel(ByRef pValue As Integer) As Integer
End Function
_
Public Shared Function HTCUtilGetOnPowerBrightnessLevel(ByRef pValue As Integer) As Integer
End Function
'' minimum
_
Public Shared Function HTCUtilGetBacklightMinBrightness(ByRef pValue As Integer) As Integer
End Function
'' maximum
_
Public Shared Function HTCUtilGetBacklightMaxBrightness(ByRef pValue As Integer) As Integer
End Function
End Class
呼叫的範例像是下面這樣
Dim intIn As Integer = 0
intResult = HTCPInvoke.HTCUtilGetOnPowerBrightnessLevel(intIn)
For i As Integer = 0 To 10 Step 2
intIn = i
intResult = HTCPInvoke.HTCUtilSetOnPowerBrightnessLevel(intIn)
Threading.Thread.Sleep(2000)
Next
本來對於背光調整這部分已經放棄了,都是spb mobile shell害的,他的小工具居然可以調整我的Tytn2!! (好叉燒,為什麼要讓我吃到這麼好吃的叉燒..),讓我不知道抓了幾天的頭,看了多少google上面的相關討論..
回到正題,那麼就結束了嗎?還沒有,朋友,再聽我多費話兩句;再上面的程式碼中可以去改變亮度,但是都有分是使用外部電源還是電池電源,那麼,我現在是用哪一種電?總不能每次都暴力兩個值都改吧,我們可是程式人,有潔癖的..那要怎麼知道目前是什麼裝態?於是乎,又要辛苦coredll.dll大俠了,宣告方式會像下面這樣
_
Public Structure SYSTEM_POWER_STATUS_EX2
Public ACLineStatus As Byte
Public BatteryFlag As Byte
Public BatteryLifePercent As Byte
Public Reserved1 As Byte
Public BatteryLifeTime As Integer
Public BatteryFullLifeTime As Integer
Public Reserved2 As Byte
Public BackupBatteryFlag As Byte
Public BackupBatteryLifePercent As Byte
Public Reserved3 As Byte
Public BackupBatteryLifeTime As Integer
Public BackupBatteryFullLifeTime As Integer
Public BatteryVoltage As Integer
Public BatteryCurrent As Integer
Public BatteryAverageCurrent As Integer
Public BatteryAverageInterval As Integer
Public BatterymAHourConsumed As Integer
Public BatteryTemperature As Integer
Public BackupBatteryVoltage As Integer
Public BatteryChemistry As Byte
End Structure
Public AC_LINE_ONLINE As Integer = 1
Public AC_LINE_OFFLINE As Integer = 0
''reference http://msdn.microsoft.com/en-us/library/aa931066.aspx
_
Public Function GetSystemPowerStatusEx2(ByRef lpSystemPowerStatus As SYSTEM_POWER_STATUS_EX2, _
ByVal dwLen As Integer, ByVal fUpdate As Boolean) As Integer
End Function
使用方式會像下面這樣
Dim Result As New SYSTEM_POWER_STATUS_EX2
Dim intReturn As Integer = GetSystemPowerStatusEx2(Result, Marshal.SizeOf(Result), False)
If intReturn <> 0 Then
''呼叫成功
If Result.ACLineStatus = AC_LINE_ONLINE Then
''Using AC power
TextBox1.Text = "using AC power"
Else
TextBox1.Text = "using battery power"
End If
End If
End Sub
其實在GetSystemPowerStateEx2中,還有很多東西可以使用,這邊只抓出是否使用AC電源的部分,各位可以自行在觀察、研究一下。
呼 ~ 今天的介紹就到這邊了,快,別閒著,把手機掏出來試試看吧 !!