RegisterPowerSettingNotification
The following example monitors the system for power state changes.
With the RegisterPowerSettingNotification function we register a window handle which will receive notifications when the power state of the system changes.
Then we hook the window procedure of the window with the BindEventsEx function.
The POWERBROADCAST_SETTING structure has a varying length, a pointer to this structure is passed to the registered callback function PowerBroadCastEvent.
The Translation options for this structure are Memory management - not responsible since the structure is passed to us from the OS and we don't need to allocate or free any memory.
The DataDword and DataGuid members are added manually to access the varying data in the structure.
#DEFINE WM_POWERBROADCAST 0x0218 #DEFINE PBT_POWERSETTINGCHANGE 0x8013 #DEFINE GUID_POWERSCHEME_PERSONALITY 0h41855D2443392244B02513A784F679B7 && {245D8541-3943-4422-B025-13A784F679B7} #DEFINE GUID_MIN_POWER_SAVINGS 0hDA7F5E8CBFE8964A9A85A6E23A8C635C && {8C5E7FDA-E8BF-4A96-9A85-A6E23A8C635C} #DEFINE GUID_MAX_POWER_SAVINGS 0h081384A14135AB4FBC81F71556F20B4A && {A1841308-3541-4FAB-BC81-F71556F20B4A} #DEFINE GUID_TYPICAL_POWER_SAVINGS 0h22421B3894F6F0419685FF5BB260DF2E && {381B4222-F694-41F0-9685-FF5BB260DF2E} #DEFINE GUID_ACDC_POWER_SOURCE 0h599A3E5DD5E9004BA6BDFF34FF516548 && {5D3E9A59-E9D5-4B00-A6BD-FF34FF516548} #DEFINE GUID_BATTERY_PERCENTAGE_REMAINING 0h4180ADA75AB4AE4C87A3EECBB468A9E1 && {A7AD8041-B45A-4CAE-87A3-EECBB468A9E1} #DEFINE GUID_IDLE_BACKGROUND_TASK 0hD8315C5134F73D16A0FD11A08C91E8F1 && {515C31D8-F734-163D-A0FD-11A08C91E8F1} #DEFINE GUID_SYSTEM_AWAYMODE 0h80F5A798F701AA489C0F44352C29E5C0 && {98A7F580-01F7-48AA-9C0F-44352C29E5C0} #DEFINE GUID_MONITOR_POWER_ON 0h151073021045264599E6E5A17EBD1AEA && {02731015-4510-4526-99E6-E5A17EBD1AEA} PUBLIC goPowerEvents m.goPowerEvents = CREATEOBJECT('cPowerEvents') m.goPowerEvents.RegisterEvent(GUID_POWERSCHEME_PERSONALITY) m.goPowerEvents.RegisterEvent(GUID_ACDC_POWER_SOURCE) m.goPowerEvents.RegisterEvent(GUID_BATTERY_PERCENTAGE_REMAINING) m.goPowerEvents.RegisterEvent(GUID_MONITOR_POWER_ON) DEFINE CLASS cPowerEvents AS Custom PROTECTED oRegisteredEvents oRegisteredEvents = .NULL. FUNCTION Init THIS.oRegisteredEvents = CREATEOBJECT('Collection') BINDEVENTSEX(_VFP.hWnd, WM_POWERBROADCAST, THIS, 'PowerBroadCastEvent', 'wParam, lParam') ENDFUNC FUNCTION Destroy THIS.UnregisterEvent() UNBINDEVENTSEX(_VFP.hWnd, WM_POWERBROADCAST) ENDFUNC FUNCTION RegisterEvent(lcEvent) LOCAL lnIndex, lnHandle m.lnIndex = THIS.oRegisteredEvents.GetKey(m.lcEvent) IF m.lnIndex = 0 m.lnHandle = RegisterPowerSettingNotification(_VFP.hWnd, m.lcEvent, 0) THIS.oRegisteredEvents.Add(m.lnHandle, m.lcEvent) ENDIF ENDFUNC FUNCTION UnregisterEvent(lcEvent) LOCAL lnIndex, lnHandle IF VARTYPE(m.lcEvent) = 'C' m.lnIndex = THIS.oRegisteredEvents.GetKey(m.lcEvent) IF m.lnIndex != 0 m.lnHandle = THIS.oRegisteredEvents.Item(m.lnIndex) UnregisterPowerSettingNotification(m.lnHandle) THIS.oRegisteredEvents.Remove(m.lnIndex) ENDIF ELSE && remove all events FOR EACH m.lnHandle IN THIS.oRegisteredEvents UnregisterPowerSettingNotification(m.lnHandle) ENDFOR THIS.oRegisteredEvents.Remove(-1) ENDIF ENDFUNC FUNCTION PowerBroadCastEvent LPARAMETERS dwEvent, lnData DO CASE CASE m.dwEvent = PBT_POWERSETTINGCHANGE LOCAL loPBS, lcPowerSetting m.loPBS = CREATEOBJECT('POWERBROADCAST_SETTING', m.lnData) && pass pointer to structure! m.lcPowerSetting = m.loPBS.PowerSetting.Guid DO CASE CASE m.lcPowerSetting == GUID_POWERSCHEME_PERSONALITY LOCAL lcPSGuid, lcPSName m.lcPSGuid = m.loPBS.DataGuid.Guid m.lcPSName = ICASE(m.lcPSGuid == GUID_MIN_POWER_SAVINGS, 'High Performance', ; m.lcPSGuid == GUID_MAX_POWER_SAVINGS, 'Power Saver', 'Automatic') ? 'Active power scheme changed to: ' + m.lcPSName CASE m.lcPowerSetting == GUID_ACDC_POWER_SOURCE LOCAL lnPowerSource m.lnPowerSource = m.loPBS.DataDword DO CASE CASE m.lnPowerSource = 0 ? 'The computer is powered by an AC power source.' CASE m.lnPowerSource = 1 ? 'The computer is powered by an onboard battery power source.' CASE m.lnPowerSource = 2 ? 'The computer is powered by a short-term power source such as a UPS device.' ENDCASE CASE m.lcPowerSetting == GUID_BATTERY_PERCENTAGE_REMAINING ? 'Current battery capacity: ' + ALLTRIM(STR(m.loPBS.DataDword)) + '%' CASE m.lcPowerSetting == GUID_MONITOR_POWER_ON ? 'Monitor state changed to: ' + IIF(m.loPBS.DataDword = 0, 'Off', 'On') ENDCASE ENDCASE ENDFUNC ENDDEFINE FUNCTION RegisterPowerSettingNotification(hRecipient, PowerSettingGuid, Flags) DECLARE INTEGER RegisterPowerSettingNotification IN WIN32API INTEGER hRecipient, STRING PowerSettingGuid, INTEGER Flags RETURN RegisterPowerSettingNotification(m.hRecipient, m.PowerSettingGuid, m.Flags) ENDFUNC FUNCTION UnregisterPowerSettingNotification(Handle) DECLARE INTEGER UnregisterPowerSettingNotification IN WIN32API INTEGER Handle RETURN UnregisterPowerSettingNotification(m.Handle) ENDFUNC DEFINE CLASS POWERBROADCAST_SETTING AS Exception Address = 0 Name = "POWERBROADCAST_SETTING" && structure fields PowerSetting = .NULL. DataLength = .F. DataGuid = .F. && added manually to access GUID at offset of Data member DataDword = .F. && added manually to access DWORD at offset of Data member PROCEDURE Init(lnAddress) ASSERT TYPE('lnAddress') = 'N' AND lnAddress != 0 MESSAGE 'Invalid structure address!' THIS.Address = lnAddress THIS.PowerSetting = CREATEOBJECT('GUID', THIS.Address) THIS.DataGuid = CREATEOBJECT('GUID', THIS.Address+20) && added manually ENDPROC PROCEDURE Address_Assign(lnAddress) DO CASE CASE THIS.Address = 0 THIS.Address = lnAddress CASE THIS.Address = lnAddress OTHERWISE THIS.Address = lnAddress THIS.PowerSetting.Address = lnAddress THIS.DataGuid.Address = lnAddress + 20 && added manually ENDCASE ENDPROC PROCEDURE DataLength_Access() RETURN ReadUInt(THIS.Address+16) ENDPROC PROCEDURE DataDword_Access() RETURN ReadUInt(THIS.Address+20) ENDPROC ENDDEFINE DEFINE CLASS GUID AS Exception Address = 0 SizeOf = 16 PROTECTED Embedded Embedded = .F. Name = "GUID" && structure fields Data1 = .F. Data2 = .F. Data3 = .F. Data4 = .F. Guid = .F. && custom member to assign and access GUID as a binary string GuidString = .F. && custom member to assign and access GUID as a readable string PROCEDURE Init(lnAddress) IF PCOUNT() = 0 THIS.Address = AllocMem(THIS.SizeOf) ELSE THIS.Address = lnAddress THIS.Embedded = .T. ENDIF ENDPROC PROCEDURE Destroy() IF !THIS.Embedded FreeMem(THIS.Address) ENDIF ENDPROC PROCEDURE Data1_Access() RETURN ReadUInt(THIS.Address) ENDPROC PROCEDURE Data1_Assign(lnNewVal) WriteUInt(THIS.Address,lnNewVal) ENDPROC PROCEDURE Data2_Access() RETURN ReadUShort(THIS.Address+4) ENDPROC PROCEDURE Data2_Assign(lnNewVal) WriteUShort(THIS.Address+4,lnNewVal) ENDPROC PROCEDURE Data3_Access() RETURN ReadUShort(THIS.Address+6) ENDPROC PROCEDURE Data3_Assign(lnNewVal) WriteUShort(THIS.Address+6,lnNewVal) ENDPROC PROCEDURE Data4_Access() RETURN ReadCharArray(THIS.Address+8,8) ENDPROC PROCEDURE Data4_Assign(lnNewVal) WriteCharArray(THIS.Address+8,lnNewVal,8) ENDPROC PROCEDURE Guid_Access() RETURN ReadBytes(THIS.Address, 16) ENDPROC PROCEDURE Guid_Assign(lnNewVal) WriteBytes(THIS.Address, m.lnNewVal, 16) ENDPROC PROCEDURE GuidString_Access() RETURN STRINGFROMCLSID(THIS.Address) ENDPROC PROCEDURE GuidString_Assign(lnNewVal) LOCAL lcGuid m.lcGuid = CLSIDFROMSTRING(m.lnNewVal) WriteBytes(THIS.Address, m.lcGuid) ENDPROC ENDDEFINE