.Net CF 2.0 - Prevent device from sleeping

Hello,

I've been looking for a way to (optionally) prevent a pocketpc 2k3 device from going into sleep mode while my app is running, but could not find anything. Any suggestions

--John

(update)

Also, Is there a way to keep the screen light from going out without user interaction And something more extreme, can one change the way devices behave during sleep mode (e.g. keep WiFi in a running state like GSM phone device)



Answer this question

.Net CF 2.0 - Prevent device from sleeping

  • jattali

    correction to the above: in my last reply, I was referring to keeping the backlight on. Preventing the PocketPC from sleeping wasn't necessary in my case because I open a bluetooth connection with a device, which prevents the PocketPC from sleeping anyway. Using the SystemIdleTimerReset function works fine when needed though. Thanks a bunch

    --John


  • Shalini

    Welcome to read the series of articles I post in my blog (http://windowsmobilepro.blogspot.com/) on Pocket PC Power Management :) All together there are 8 of them. I plan to write another one or two on how to write battery-friendly application, and another for wrap up.

    The articles might worthy a read, as I wrote them based on my past 1.5 years' struggling with Pocket PC's unique power management, when documentations were scarce:

    - Pocket PC Power Management Series 1: the Challenge to Developers
    - Pocket PC Power Management Series 2: Problem Domain
    - Pocket PC Power Management Series 3: When is My Device Sleeping, and when is it Running
    - Pocket PC Power Management Series 4: A Better Way to Catch when the Device Wakes Up
    - Pocket PC Power Management Series 5: Force the Device not to Sleep: a Brutal Way
    - Pocket PC Power Management Series 6: Request the Device to Run: a Gentle Way
    - Pocket PC Power Management Series 7: Trap of GetTickCount() and Sleep()
    - Pocket PC Power Management Series 8: Why Pocket PC's Battery Life so Notorious

    As Michael pointed out, SystemIdleTimerReset might not work in some cases. CeSetUserNotificationEx is more reliable. Please read Series 5 and Series 6 for details.

    ---
    Lao K
    Visit my blog for Windows Mobile Pocket PC Smartphone Programming Hints and Tips





  • sunnair

    I am having a problem with a device sleeping while I have a Bluetooth link established. The remote device is performing a routine than can take anywhere from 3 to 10 minutes to complete and when its done, the user presses a button to continue.

    I can't change the fact that data is not sent back to the PDA due to the fact that I originally wrote the app using palm and the hardware is already out in the field so I'm stuck emulating what I did with the palm. Do you have info on how you wrote the wrapper for your project

    thanks,

    ~Tony


  • Deadlock

    Hi Lao,

    Thanks for the links, I'm going to check them out as soon as I post this. I ended up using SetPowerRequirement for device bkl1: to D0 and it works fine.

    --John


  • terceslil

    Hi Michael,

    Better late than never, thanks for your answer (I actually forgot about this question and saw it 2 days ago). I used the power api, made a nice wrapper component, all work fine and do the job perfectly. I even handled power notifications to stop and restart bluetooth connections after suspend. Thanks a lot!

    --John


  • wullien

    Hi John

    I'm not aware of any Managed APIs to get this job done.

    There is a native API called SystemIdleTimerReset that can be used to prevent the device from going into sleep. The documentation for this API can be found here: http://msdn.microsoft.com/library/default.asp url=/library/en-us/wceui40/html/cerefSystemIdleTimerReset.asp
    It might be a bit tricky to figure out how often you have to call this API (see doc remark section)

    An other option is to simulate keyboard (or stylus) input using SendInput API. (See http://msdn.microsoft.com/library/default.asp url=/library/en-us/wceui40/html/cerefSendInput.asp)

    Concerning the backlight/WiFi questions: you may want to play with some APIs the Power Manager exposes like SetPowerRequirement and ReleasePowerRequirement.
    See here: http://msdn.microsoft.com/library/default.asp url=/library/en-us/wceddk40/html/cxcondevicepowerrequirements.asp

    Backlight sample: http://blog.opennetcf.org/pfoot/PermaLink,guid,d130e903-ffea-44d0-b909-9e8009e75954.aspx

    Just be aware that power management is highly device specific. Some stuff might not work the same way on all devices.

    Please let me know if this works for you.

    Michael

  • hoho

    Interestingly enough, my device does not go to sleep while any bluetooth link is established. I suppose that should be happening with your device too.

    Here's the code for the class I made, nevertheless. It's not complete yet (but then again, there is not such thing as final code, is there ;)) Also, it's not heavily commented (in fact there are no comments at all :) ).

    Btw including this class to a managed project creates lots of problems with VS UI designers. I compile it in a separate assembly.

    using System;
    using System.ComponentModel;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Threading;
    
    namespace Microbase.Whereami.Controls
    {
    	public enum PowerState
    	{
    		On = 0x00010000,
    		Off = 0x00020000,
    		Critical = 0x00040000,
    		Boot = 0x00080000,
    		Idle = 0x00100000,
    		Suspend = 0x00200000,
    		Reset = 0x00800000
    	}
    
    	public enum ACLineStatus
    	{
    		Offline = 0,
    		Online = 1,
    		Unknown = 255
    	}
    
    	public enum BatteryStatus
    	{
    		High = 1,
    		Low = 2,
    		Critical = 4,
    		Charging = 8,
    		NoSystemBattery = 128,
    		Unknown = 255
    	}
    
    	public enum CEDevicePowerState
    	{
    		PwrDeviceUnspecified = -1,
    		D0 = 0,
    		D1 = 1,
    		D2 = 2,
    		D3 = 3,
    		D4 = 4,
    		PwrDeviceMaximum = 5
    	}
    
    	public partial class PowerManager : Component
      {
        #region Power Management API Declarations
    
    		[Flags]
    		private enum PowerEventType
    		{
    			PBT_TRANSITION = 0x00000001,
    			PBT_RESUME = 0x00000002,
    			PBT_POWERSTATUSCHANGE = 0x00000004,
    			PBT_POWERINFOCHANGE = 0x00000008,
    			PBT_OEMBASE = 0x00010000,
    			POWER_NOTIFY_ALL = -1
    		}
    
    		private const UInt32 INFINITE = UInt32.MaxValue;
    
    		private class POWER_BROADCAST
    		{
    			byte[] buffer;
    
    			public POWER_BROADCAST(int size)
    			{
    				buffer = new byte[size];
    			}
    
    			public byte[] Data
    			{
    				get
    				{ 
    					return buffer; 
    				}
    			}
    
    			public PowerEventType Message
    			{
    				get
    				{
    					return (PowerEventType)BitConverter.ToInt32(buffer, 0);
    				}
    			}
    
    			public PowerState Flags
    			{
    				get
    				{
    					return (PowerState)BitConverter.ToInt32(buffer, 4);
    				}
    			}
    
    			public int Length
    			{
    				get
    				{
    					return BitConverter.ToInt32(buffer, 8);
    				}
    			}
    
    			public byte[] SystemPowerState
    			{
    				get
    				{
    					byte[] data = new byte[Length]; 
    					Buffer.BlockCopy(buffer, 12, data, 0, Length); 
    					return data;
    				}
    			}
    		}
    
    		[StructLayout(LayoutKind.Sequential)]
    		private struct MSGQUEUEOPTIONS
    		{
    			public UInt32 dwSize;
    			public UInt32 dwFlags;
    			public UInt32 dwMaxMessages;
    			public UInt32 cbMaxMessage;
    			public Int32 bReadAccess;
    		};
    
    		[StructLayout(LayoutKind.Sequential)]
    		private struct MSGQUEUEINFO
    		{
    			public UInt32 dwSize;
    			public UInt32 dwFlags;
    			public UInt32 dwMaxMessages;
    			public UInt32 cbMaxMessage;
    			public UInt32 dwCurrentMessages;
    			public UInt32 dwMaxQueueMessages;
    			public UInt16 wNumReaders;
    			public UInt16 wNumWriters;
    		};
    
    		private enum PowerOptions
    		{
    			None = 0,
    			Force = 0x00001000
    		}
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static int GetSystemPowerState(string psState, UInt32 dwLength, out PowerState flags);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static int SetSystemPowerState(string psState, PowerState flags, PowerOptions options);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static IntPtr RequestPowerNotifications(IntPtr messageQueueHandle, int flags);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static bool StopPowerNotifications(IntPtr requestHandle);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static IntPtr SetPowerRequirement(string pvDevice, CEDevicePowerState DeviceState,
    			UInt32 DeviceFlags, string pvSystemState, UInt32 StateFlags);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static int ReleasePowerRequirement(IntPtr powerRequirementHandle);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static void SystemIdleTimerReset();
    		//HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power
    
    		#endregion
    
    		#region MsgQueue API Declarations
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static IntPtr CreateMsgQueue(string lpName, ref MSGQUEUEOPTIONS lpOptions);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static IntPtr OpenMsgQueue(IntPtr hSrcProc, IntPtr hMsgQ, ref MSGQUEUEOPTIONS lpOptions);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static Int32 ReadMsgQueue(IntPtr hMsgQ, byte[] lpBuffer, UInt32 cbBufferSize,
    			out UInt32 lpNumberOfBytesRead, UInt32 dwTimeout, out UInt32 pdwFlags);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static Int32 WriteMsgQueue(IntPtr hMsgQ, byte[] lpBuffer, UInt32 cbDataSize,
    			UInt32 dwTimeout, UInt32 dwFlags);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static Int32 GetMsgQueueInfo(IntPtr hMsgQ, MSGQUEUEINFO lpInfo);
    
    		[DllImport("coredll.dll", SetLastError = true)]
    		extern private static Int32 CloseMsgQueue(IntPtr hMsgQ);
    
    		#endregion
    
    		#region Synchronization API Declarations
    
    		private enum EventModification
    		{
    			EventPulse = 1,
    			EventReset = 2,
    			EventSet = 3
    		}
    
    		private const int WAIT_OBJECT_0 = 0;
    		private const int EVENT_SET = 3;
    
    		[DllImport("coredll.dll")]
    		static extern IntPtr CreateEvent(int dwReserved1, bool bManualReset, bool bInitialState, string Name);
    
    		[DllImport("coredll.dll")]
    		static extern Int32 EventModify(IntPtr hEvent, EventModification modification);
    
    		[DllImport("coredll.dll", EntryPoint = "CloseHandle", SetLastError = true)]
    		static extern Int32 CloseHandle(IntPtr h);
    
    		[DllImport("coredll.dll")]
    		static extern int WaitForMultipleObjects(UInt32 nCount, IntPtr[] hHandles, Int32 fWaitAll, UInt32 dwMilliseconds);
    				
    		#endregion
    
    		public class PowerStatusInfo
    		{
    			// levels available in battery flag fields, see BatteryDrvrGetLevels()
    			private int NumLevels;
    
    			// see GetSystemPowerStatusEx2()
    			public readonly TimeSpan MainBatteryLifeTime;
    			public readonly TimeSpan MainBatteryFullLifeTime;
    			public readonly TimeSpan BackupBatteryLifeTime;
    			public readonly TimeSpan BackupBatteryFullLifeTime;
    			public readonly ACLineStatus ACLineStatus;
    			public readonly BatteryStatus MainBatteryStatus;
    			public readonly int MainBatteryLifePercent;
    			public readonly BatteryStatus BackupBatteryStatus;
    			public readonly int BackupBatteryLifePercent;
    
    			internal PowerStatusInfo(byte[] data)
    			{
    				NumLevels = BitConverter.ToInt32(data, 0);
    				MainBatteryLifeTime = TimeSpan.FromSeconds(BitConverter.ToInt32(data, 4));
    				MainBatteryFullLifeTime = TimeSpan.FromSeconds(BitConverter.ToInt32(data, 8));
    				BackupBatteryLifeTime = TimeSpan.FromSeconds(BitConverter.ToInt32(data, 12));
    				BackupBatteryFullLifeTime = TimeSpan.FromSeconds(BitConverter.ToInt32(data, 16));
    				ACLineStatus = (ACLineStatus)data[20];
    				MainBatteryStatus = (BatteryStatus)data[21];
    				MainBatteryLifePercent = data[22];
    				BackupBatteryStatus = (BatteryStatus)data[23];
    				BackupBatteryLifePercent = data[24];
    			}
    		};
    
    		public event EventHandler PowerStateTransition;
    		public event EventHandler PowerStateResume;
    		public event EventHandler PowerStatusChanged;
    		public event EventHandler PowerStatusInfoChanged;
    
    		private IntPtr queueHandle;
    		private IntPtr notificationHandle;
    		private IntPtr closeEventHandle;
    
        private bool notificationsEnabled;
        public bool NotificationsEnabled
        {
          get
          {
            return notificationsEnabled;
          }
        }
    
        private int mainBatteryPercentage;
        public int MainBatteryPercentage
        {
          get
          {
            return mainBatteryPercentage;
          }
        }
    
        private BatteryStatus mainBatteryStatus;
        public BatteryStatus MainBatteryStatus
        {
          get
          {
            return mainBatteryStatus;
          }
        }
    
        private int backupBatteryPercentage;
        public int BackupBatteryPercentage
        {
          get
          {
            return backupBatteryPercentage;
          }
        }
    
        private BatteryStatus backupBatteryStatus;
        public BatteryStatus BackupBatteryStatus
        {
          get
          {
            return backupBatteryStatus;
          }
        }
    
        private ACLineStatus aCLineStatus;
        public ACLineStatus ACLineStatus
        {
          get
          {
            return aCLineStatus;
          }
        }
    
    		private Thread workerThread;
    
    		private IntPtr backlightPowerRequirement = (IntPtr)0;
    		public bool ScreenBacklightAlwaysOn
    		{
    			get
    			{
    				return backlightPowerRequirement != (IntPtr)0;
    			}
    			set
    			{
    				if (value)
    					backlightPowerRequirement = SetPowerRequirement("BKL1:",
    						CEDevicePowerState.D0, 1, null, 0);
    				else
    				{
    					if (backlightPowerRequirement != (IntPtr)0)
    					{
    						ReleasePowerRequirement(backlightPowerRequirement);
    						backlightPowerRequirement = (IntPtr)0;
    					}
    				}
    			}
    		}
    
    		public PowerState PowerState
    		{
    			set
    			{
    				SetSystemPowerState(null, value, PowerOptions.Force);
    			}
    		}
    
        public PowerManager()
        {
          EnableEvents();
        }
    
        public PowerManager(IContainer container)
        {
          container.Add(this);
    
    			EnableEvents();
        }
    
        private AutoResetEvent sync;
    
    		public void EnableEvents()
        {
          if (!notificationsEnabled)
          {
            MSGQUEUEOPTIONS options = new MSGQUEUEOPTIONS();
    
            options.dwSize = (UInt32)Marshal.SizeOf(options);
            options.cbMaxMessage = 1024;
            options.bReadAccess = 0;
    
            queueHandle = CreateMsgQueue("PowerEventQueue", ref options);
    
            closeEventHandle = CreateEvent(0, false, false, null);
    
            workerThread = new Thread(new ThreadStart(WorkerThreadProc));
    
            sync = new AutoResetEvent(false);
    
            if (Site == null || !Site.DesignMode)
              workerThread.Start();
    
            sync.WaitOne();
    
            notificationHandle = RequestPowerNotifications(queueHandle, (int)PowerEventType.POWER_NOTIFY_ALL);
    
            notificationsEnabled = true;
          }
    		}
    
        private void WorkerThreadProc()
        {
    			MSGQUEUEOPTIONS options = new MSGQUEUEOPTIONS();
    
    			options.dwSize = (UInt32)Marshal.SizeOf(options);
    			options.cbMaxMessage = 1024;
    			options.bReadAccess = 1;
    			
    			IntPtr readHandle = CreateMsgQueue("PowerEventQueue", ref options);
    
          sync.Set();
    
    			IntPtr[] handles = new IntPtr[] { closeEventHandle, readHandle };
    			
    			for (; WaitForMultipleObjects(2, handles, 0, INFINITE) != WAIT_OBJECT_0; )
    			{
    				UInt32 bytesRead;
    				UInt32 flags;
    
    				POWER_BROADCAST pbr = new POWER_BROADCAST(1024);
    
    				if (ReadMsgQueue(readHandle, pbr.Data, 1024, out bytesRead, 0, out flags) == 0)
    				{
    					int r = Marshal.GetLastWin32Error();
    					continue;
    				}
    
    				ProcessPowerBroadcast(pbr);
    			}
    
    			CloseMsgQueue(readHandle);
        }
    
    		private void ProcessPowerBroadcast(POWER_BROADCAST pbr)
    		{
    			switch (pbr.Message)
    			{
    				case PowerEventType.PBT_POWERSTATUSCHANGE:
    					OnPowerStatusChanged(new PowerStatusChangedEventArgs());
    					break;
    				case PowerEventType.PBT_RESUME:
    					OnPowerStateResume(new PowerStateResumeEventArgs(pbr.Flags));
    					break;
    				case PowerEventType.PBT_POWERINFOCHANGE:
    					OnPowerStatusInfoChanged(new PowerStatusInfoChangedEventArgs(
    						new PowerStatusInfo(pbr.SystemPowerState)));
    					break;
    				case PowerEventType.PBT_TRANSITION:
    					OnPowerStateTransition(new PowerStateTransitionEventArgs(pbr.Flags));
    					break;
    			}
    		}
    
    		protected virtual void OnPowerStateTransition(PowerStateTransitionEventArgs e)
    		{
    			if (PowerStateTransition != null)
    				PowerStateTransition(this, e);
    		}
    
    		protected virtual void OnPowerStateResume(PowerStateResumeEventArgs e)
    		{
    			if (PowerStateResume != null)
    				PowerStateResume(this, e);
    		}
    
    		protected virtual void OnPowerStatusChanged(PowerStatusChangedEventArgs e)
    		{
    			if (PowerStatusChanged != null)
    				PowerStatusChanged(this, e);
    		}
    
    		protected virtual void OnPowerStatusInfoChanged(PowerStatusInfoChangedEventArgs e)
    		{
          mainBatteryPercentage = e.PowerStatusInfo.MainBatteryLifePercent;
          mainBatteryStatus = e.PowerStatusInfo.MainBatteryStatus;
          backupBatteryPercentage = e.PowerStatusInfo.BackupBatteryLifePercent;
          backupBatteryStatus = e.PowerStatusInfo.BackupBatteryStatus;
          aCLineStatus = e.PowerStatusInfo.ACLineStatus;
    
    			if (PowerStatusInfoChanged != null)
    				PowerStatusInfoChanged(this, e);
    		}
    
    		public void DisableEvents()
    		{
          if (notificationsEnabled)
          {
            StopPowerNotifications(notificationHandle);
    
            if (Site == null || !Site.DesignMode)
            {
              EventModify(closeEventHandle, EventModification.EventSet);
              workerThread.Join();
            }
    
            CloseMsgQueue(queueHandle);
            CloseHandle(closeEventHandle);
    
            notificationsEnabled = false;
          }
    		}
    
    		#region Event handlers
    
    		void Parent_Closed(object sender, EventArgs e)
    		{
    			DisableEvents();
    		}
    
    		#endregion
    
    		protected override void Dispose(bool disposing)
        {
    			DisableEvents();
    
    			if (backlightPowerRequirement != (IntPtr)0)
    			{
    				ReleasePowerRequirement(backlightPowerRequirement);
    				backlightPowerRequirement = (IntPtr)0;
    			}
    
          base.Dispose(disposing);
        }
    
    		~PowerManager()
    		{
    			Dispose(true);
    		}
      }
    
      public class PowerStateTransitionEventArgs : EventArgs
      {
        public readonly PowerState PowerState;
    
        internal PowerStateTransitionEventArgs(PowerState state)
        {
          PowerState = state;
        }
      }
    
      public class PowerStateResumeEventArgs : EventArgs
      {
        public readonly PowerState PowerState;
    
        internal PowerStateResumeEventArgs(PowerState state)
        {
          PowerState = state;
        }
      }
    
      public class PowerStatusChangedEventArgs : EventArgs
      {
        internal PowerStatusChangedEventArgs()
        {
          //Might be useful to keep track of status an report it
        }
      }
    
      public class PowerStatusInfoChangedEventArgs : EventArgs
      {
        public readonly PowerManager.PowerStatusInfo PowerStatusInfo;
    
        internal PowerStatusInfoChangedEventArgs(PowerManager.PowerStatusInfo info)
        {
          PowerStatusInfo = info;
        }
      }
    
    }
    
    

  • rimysoft

    Wow, your approach looks pretty complex. I figured out an easier way (if you're interested). I simple create a timer and every 30 seconds, I call the native function void SystemIdleTimerReset() It's pretty simple and works very well!


  • TheDane

    hi john ,
    i too got struck with Power management . I want my application to support PalmTreo 700wx and PalmTreo 700w.what happens is when the call end button(red button) is pressed , the screen gets freezed , but the application is running in the back ground . when again the call end button is pressed the application resumes . this happens because power key is mapped . i want to know to how to handle Power suspend and resume usimg managed wrapper.

    thanks
    sadiq


  • .Net CF 2.0 - Prevent device from sleeping