Tuesday, February 1, 2011

Laptop specific functions

First I would like to thank each and every one of the developers from stackoverflow who helped me out in detecting if application is running on laptop by answering my question.
I have pushed the envelop further by defining some helper functions which retrieves laptop specific information and some other as well, so without further introduction here's the unit that I've wrote, feel free to use it in commercial and/or personal applications AT YOUR OWN RISK of course, also if you find some flaws(high probability -- haven't tested enough) please feel free to drop a comment.
unit uDGMobileUtils;

interface

(*******************************************************************************

  Author:
    Dorin Duminica

  Note:
    That Parts of the code are Copyright© of Microsoft Corporation.
    All Rights Reserved.

  Disclaimer:
    Using the following code represents your acknowledgement that YOU TAKE
    FULL RESPONSABILITY of any damage it can and/or might cause to your
    system, country, pets, etc.

  Requirements:
    According to Microsoft the following code should work starting from
    Windows 2000 Professional and Server

*******************************************************************************)

uses
  Windows;

{$Z4} // required in order to have 4 byte enumerated type

type
  SYSTEM_POWER_STATE =(
    PowerSystemUnspecified,
    PowerSystemWorking,
    PowerSystemSleeping1,
    PowerSystemSleeping2,
    PowerSystemSleeping3,
    PowerSystemHibernate,
    PowerSystemShutdown,
    PowerSystemMaximum);

{$Z1} // restore enumerated type to 1 byte

const
  SYSTEM_POWER_STATE_NAMES: array[SYSTEM_POWER_STATE] of string = (
    'Unspecified',
    'Working',
    'Sleeping 1',
    'Sleeping 2',
    'Sleeping 3',
    'Hibernate',
    'Shutdown',
    'Maximum');

type
  BATTERY_REPORTING_SCALE = record
    Granularity: ULONG;
    Capacity: ULONG;
  end;

  PBATTERY_REPORTING_SCALE = ^BATTERY_REPORTING_SCALE;

type
  SYSTEM_POWER_CAPABILITIES = record
    // If this member is TRUE, there is a system power button.
    PowerButtonPresent: Boolean;
    // If this member is TRUE, there is a system sleep button.
    SleepButtonPresent: Boolean;
    // If this member is TRUE, there is a lid switch.
    LidPresent: Boolean;
    // for S1 —> S5 check microsoft site
    SystemS1: Boolean;
    SystemS2: Boolean;
    SystemS3: Boolean;
    SystemS4: Boolean;
    SystemS5: Boolean;
    // If this member is TRUE, the operating system supports power off state S5 (soft off).
    HiberFilePresent: Boolean;
    // If this member is TRUE, the system supports wake capabilities.
    FullWake: Boolean;
    // If this member is TRUE, the system supports video display dimming capabilities.
    VideoDimPresent: Boolean;
    // If this member is TRUE, the system supports APM BIOS power management features.
    ApmPresent: Boolean;
    // If this member is TRUE, there is an uninterruptible power supply (UPS).
    UpsPresent: Boolean;
    // If this member is TRUE, the system supports thermal zones.
    ThermalControl: Boolean;
    // If this member is TRUE, the system supports processor throttling.
    ProcessorThrottle: Boolean;
    // The minimum level of system processor throttling supported,
    // expressed as a percentage.
    ProcessorMinThrottle: UCHAR;
    // The maximum level of system processor throttling supported,
    // expressed as a percentage.
    ProcessorMaxThrottle: UCHAR;
    // If this member is TRUE, the system supports the hybrid sleep state.
    // Windows Server 2003 and Windows XP:  Hybrid sleep is not supported.
    // Windows 2000:  This member is not supported.
    FastSystemS4: Boolean;
    // reserved
    spare2: array [0 .. 3] of UCHAR;
    // If this member is TRUE, the system supports allowing the removal of power
    // to fixed disk devices.
    DiskSpinDown: Boolean;
    // reserved
    spare3: array [0 .. 7] of UCHAR;
    // If this member is TRUE, there are one or more batteries in the system.
    SystemBatteriesPresent: Boolean;
    // If this member is TRUE, the system batteries are short-term.
    // Short-term batteries are used in uninterruptible power supplies (UPS).
    BatteriesAreShortTerm: Boolean;
    // A BATTERY_REPORTING_SCALE structure that contains information about
    // how system battery metrics are reported.
    BatteryScale: array [0 .. 2] of BATTERY_REPORTING_SCALE;
    // The lowest system sleep state (Sx) that will generate a wake event when
    // the system is on AC power. This member must be one of the
    // SYSTEM_POWER_STATE enumeration type values.
    AcOnLineWake: SYSTEM_POWER_STATE;
    // The lowest system sleep state (Sx) that will generate a wake event via
    // the lid switch. This member must be one of the SYSTEM_POWER_STATE
    // enumeration type values.
    SoftLidWake: SYSTEM_POWER_STATE;
    // To wake the computer using the RTC, the operating system must also
    // support waking from the sleep state the computer is in when the RTC
    // generates the wake event. Therefore, the effective lowest sleep state
    // from which an RTC wake event can wake the computer is the lowest sleep
    // state supported by the operating system that is equal to or higher than
    // the value of RtcWake. To determine the sleep states that the operating
    // system supports, check the SystemS1, SystemS2, SystemS3, and SystemS4 members.
    RtcWake: SYSTEM_POWER_STATE;
    // The minimum allowable system power state supporting wake events.
    // This member must be one of the SYSTEM_POWER_STATE enumeration type values.
    // Note that this state may change as different device drivers are
    // installed on the system.
    MinDeviceWakeState: SYSTEM_POWER_STATE;
    // The default system power state used if an application calls
    // RequestWakeupLatency with LT_LOWEST_LATENCY. This member must be one of
    // the SYSTEM_POWER_STATE enumeration type values.
    DefaultLowLatencyWake: SYSTEM_POWER_STATE;
  end;

  PSYSTEM_POWER_CAPABILITIES = ^SYSTEM_POWER_CAPABILITIES;

type
  TACLineStatus = (
    // battery
    acsOffline = 0,
    // plugged in
    acsOnline = 1,
    acsUnknown = 255);

type
  TBatteryState = (
    // High—the battery capacity is at more than 66 percent
    bsHigh = 1,
    // Low—the battery capacity is at less than 33 percent
    bsLow = 2,
    // Critical—the battery capacity is at less than five percent
    bsCritical = 4,
    bsCharging = 8,
    bsNoSystemBattery = 128,
    // Unknown status—unable to read the battery flag information
    bsUnknown = 255);

  TBatteryStatus = set of TBatteryState;

  function GetPwrCapabilities(lpSystemPowerCapabilities: PSYSTEM_POWER_CAPABILITIES): Boolean; stdcall;
  function IsAdminOverrideActive: Boolean; stdcall;
  function IsPwrHibernateAllowed: Boolean; stdcall;
  function IsPwrShutdownAllowed: Boolean; stdcall;
  function IsPwrSuspendAllowed: Boolean; stdcall;

  // utility
  function IsLidPresent: Boolean;
  function IsRunningMobile: Boolean;
  function IsRunningOnBattery: Boolean;
  function IsPowerBtnPresent: Boolean;
  function IsApmPresent: Boolean;
  function IsUpsPresent: Boolean;
  function IsThermalControl: Boolean;
  function GetACLineStatus: TACLineStatus;
  function GetACLineStatusName(const AACLineStatus: TACLineStatus): string;
  function GetBatteryStatus: TBatteryStatus;
  function GetBatteryStateName(const ABatteryState: TBatteryState): string;
  function GetBatteryStatusStr(const ABatteryState: TBatteryStatus;
    const ADelimiter: Char = ','): string;
  function GetBatteryLifePercent: Byte;
  function GetBatteryLifeTime: DWORD;
  function GetBatteryLifeTimeFull: DWORD;
  function GetNumberOfProcessors: DWORD;
  function GetSystemPowerStateName(const ASystemPowerState: SYSTEM_POWER_STATE): string;

implementation

uses
  SysUtils,
  Classes;

const
  powrproflib = 'powrprof.dll';

function GetPwrCapabilities(lpSystemPowerCapabilities: PSYSTEM_POWER_CAPABILITIES): Boolean; external powrproflib name 'GetPwrCapabilities';
function IsAdminOverrideActive: Boolean; external powrproflib name 'IsAdminOverrideActive';
function IsPwrHibernateAllowed: Boolean; external powrproflib name 'IsPwrHibernateAllowed';
function IsPwrShutdownAllowed: Boolean; external powrproflib name 'IsPwrShutdownAllowed';
function IsPwrSuspendAllowed: Boolean; external powrproflib name 'IsPwrSuspendAllowed';

function IsLidPresent: Boolean;
var
  LSYSTEM_POWER_CAPABILITIES: SYSTEM_POWER_CAPABILITIES;
begin
  Result := GetPwrCapabilities(@LSYSTEM_POWER_CAPABILITIES);
  if Result then
    Result := LSYSTEM_POWER_CAPABILITIES.LidPresent;
end;

function IsRunningMobile: Boolean;
begin
  Result := IsLidPresent or IsRunningOnBattery;
end;

function IsRunningOnBattery: Boolean;
begin
  Result := (GetACLineStatus = acsOffline);
end;

function IsPowerBtnPresent: Boolean;
var
  LSYSTEM_POWER_CAPABILITIES: SYSTEM_POWER_CAPABILITIES;
begin
  Result := GetPwrCapabilities(@LSYSTEM_POWER_CAPABILITIES);
  if Result then
    Result := LSYSTEM_POWER_CAPABILITIES.PowerButtonPresent;
end;

function IsApmPresent: Boolean;
var
  LSYSTEM_POWER_CAPABILITIES: SYSTEM_POWER_CAPABILITIES;
begin
  Result := GetPwrCapabilities(@LSYSTEM_POWER_CAPABILITIES);
  if Result then
    Result := LSYSTEM_POWER_CAPABILITIES.ApmPresent;
end;

function IsUpsPresent: Boolean;
var
  LSYSTEM_POWER_CAPABILITIES: SYSTEM_POWER_CAPABILITIES;
begin
  Result := GetPwrCapabilities(@LSYSTEM_POWER_CAPABILITIES);
  if Result then
    Result := LSYSTEM_POWER_CAPABILITIES.UpsPresent;
end;

function IsThermalControl: Boolean;
var
  LSYSTEM_POWER_CAPABILITIES: SYSTEM_POWER_CAPABILITIES;
begin
  Result := GetPwrCapabilities(@LSYSTEM_POWER_CAPABILITIES);
  if Result then
    Result := LSYSTEM_POWER_CAPABILITIES.ThermalControl;
end;

function GetACLineStatus: TACLineStatus;
var
  LSystemPowerStatus: TSystemPowerStatus;
begin
  Result := acsUnknown;
  if GetSystemPowerStatus(LSystemPowerStatus) then
    Result := TACLineStatus(LSystemPowerStatus.ACLineStatus);
end;

function GetACLineStatusName(const AACLineStatus: TACLineStatus): string;
begin
  Result := 'Unknown';
  case AACLineStatus of
    acsOffline: Result := 'Offline';
    acsOnline: Result := 'Online';
  end; // case AACLineStatus of
end;

function GetBatteryStatus: TBatteryStatus;
var
  LSystemPowerStatus: TSystemPowerStatus;

    procedure CheckState(const ABatteryState: TBatteryState);
    begin
      if (LSystemPowerStatus.BatteryFlag and Ord(ABatteryState)) = Ord(ABatteryState) then
        Include(Result, ABatteryState);
    end; // procedure CheckState(const ABatteryState: TBatteryState);

begin
  Result := [];
  if GetSystemPowerStatus(LSystemPowerStatus) then begin
    CheckState(bsHigh);
    CheckState(bsLow);
    CheckState(bsCritical);
    CheckState(bsCharging);
    CheckState(bsNoSystemBattery);
    CheckState(bsUnknown);
  end else
    Result := [bsUnknown];
end;

function GetBatteryStateName(const ABatteryState: TBatteryState): string;
begin
  case ABatteryState of
    bsHigh: Result := 'High';
    bsLow: Result := 'Low';
    bsCritical: Result := 'Critical';
    bsCharging: Result := 'Charging';
    bsNoSystemBattery: Result := 'No system battery';
    bsUnknown: Result := 'Unknown';
  end; // case ABatteryState of
end;

function GetBatteryStatusStr(const ABatteryState: TBatteryStatus;
  const ADelimiter: Char): string;
var
  LBatteryState: TBatteryState;
  LNames: TStringList;
begin
  Result := EmptyStr;
  LNames := TStringList.Create;
  try
    LNames.Delimiter := ADelimiter;
    for LBatteryState in ABatteryState do
      LNames.Add(GetBatteryStateName(LBatteryState));
    Result := LNames.DelimitedText;
  finally
    FreeAndNil(LNames);
  end; // tryf
end;

function GetBatteryLifePercent: Byte;
var
  LSystemPowerStatus: TSystemPowerStatus;
begin
  Result := 0;
  if GetSystemPowerStatus(LSystemPowerStatus) then
    // The percentage of full battery charge remaining.
    // This value in the range 0 to 100 or 255 if status is unknown.
    Result := LSystemPowerStatus.BatteryLifePercent;
end;

function GetBatteryLifeTime: DWORD;
var
  LSystemPowerStatus: TSystemPowerStatus;
begin
  Result := DWORD(-1);
  if GetSystemPowerStatus(LSystemPowerStatus) then
    // The number of seconds of battery life remaining,
    // or –1 if remaining seconds are unknown.
    Result := LSystemPowerStatus.BatteryLifeTime;
end;

function GetBatteryLifeTimeFull: DWORD;
var
  LSystemPowerStatus: TSystemPowerStatus;
begin
  Result := DWORD(-1);
  if GetSystemPowerStatus(LSystemPowerStatus) then
    // The number of seconds of battery life when at full charge,
    // or –1 if full battery lifetime is unknown.
    Result := LSystemPowerStatus.BatteryFullLifeTime;
end;

function GetNumberOfProcessors: DWORD;
var
  LSystemInfo: TSystemInfo;
begin
  GetSystemInfo(LSystemInfo);
  // number of processor means number of threads
  // i.e. a processor with 4 cores can have 8 threads
  Result := LSystemInfo.dwNumberOfProcessors;
end;

function GetSystemPowerStateName(const ASystemPowerState: SYSTEM_POWER_STATE): string;
begin
  Result := SYSTEM_POWER_STATE_NAMES[ASystemPowerState];
end;

end.
How to use it:
a) drop a memo and a button on the form, rename the memo to "edInfo"
b) double-click the button and copy-paste the following code
procedure TForm1.Button1Click(Sender: TObject);

  procedure AddBool(const s: string; const Value: Boolean);
  begin
    edInfo.Lines.Add(Format('%s = %s', [s, BoolToStr(Value, True)]));
  end; // procedure AddBool(const s: string; const Value: Boolean);

  procedure AddString(const s, Value: string);
  begin
     edInfo.Lines.Add(Format('%s = %s', [s, Value]));
  end; // procedure AddString(const s, Value: string);

  procedure AddPercent(const s: string; const Value: Byte);
  begin
    edInfo.Lines.Add(Format('%s = %d%%', [s, Value]));
  end; // procedure AddPercent(const s: string; const Value: Byte);

  procedure AddSeconds(const s: string; const Value: DWORD);
  begin
    edInfo.Lines.Add(Format('%s = %d sec.', [s, Value]));
  end; // procedure AddSeconds(const s: string; const Value: DWORD);

  procedure AddDWord(const s: string; const Value: DWORD);
  begin
    edInfo.Lines.Add(Format('%s = %d', [s, Value]));
  end; // procedure AddDWord(const s: string; const Value: DWORD);

begin
  edInfo.Clear;
  AddBool('IsLidPresent', IsLidPresent);
  AddBool('IsRunningMobile', IsRunningMobile);
  AddBool('IsRunningOnBattery', IsRunningOnBattery);
  AddBool('IsPowerBtnPresent', IsPowerBtnPresent);
  AddBool('IsApmPresent', IsApmPresent);
  AddBool('IsUpsPresent', IsUpsPresent);
  AddBool('IsThermalControl', IsThermalControl);
  AddString('GetACLineStatus', GetACLineStatusName(GetACLineStatus));
  AddString('GetBatteryStatusStr', GetBatteryStatusStr(GetBatteryStatus));
  AddPercent('GetBatteryLifePercent', GetBatteryLifePercent);
  // if GetBatteryLifeTime = -1 it means that laptop is either plugged in OR
  // it is running on battery for a few seconds -- Windows did NOT detect
  // yet or it can't tell for certain how many seconds left
  // also the value might increase in a couple of seconds
  AddSeconds('GetBatteryLifeTime', GetBatteryLifeTime);
  // in my tests GetBatteryLifeTimeFull retrieves only -1 it might have something
  // to do with the fact that my laptop is only a couple of days old
  // or something fails -- I'm NOT 100% sure on this, please feel free to comment
  AddSeconds('GetBatteryLifeTimeFull', GetBatteryLifeTimeFull);
  AddDWord('GetNumberOfProcessors', GetNumberOfProcessors);
end;
c) and last but not least HAVE FUN!!

No comments:

Post a Comment

Blogroll(General programming and Delphi feeds)