Search code examples
delphiwindows-10delphi-7standby

How to put a Win10 PC into Standby mode from Delphi?


This code (compiled under Delphi 7) works nice under XP and Win7:

var
  _SetSuspendState: function (Hibernate, ForceCritical, DisableWakeEvent: BOOL): BOOL stdcall;
  // Hibernate: SetSuspendState(True , False, False);
  // Standby  : SetSuspendState(False, False, False);
  function SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent: Boolean): Boolean;
  function LinkAPI(const module, functionname: string): Pointer;
...

function LinkAPI(const module, functionname: string): Pointer;
var
  hLib: HMODULE;
begin
  hLib := GetModulehandle(PChar(module));
  if hLib = 0 then
    hLib := LoadLibrary(PChar(module));
  if hLib <> 0 then
    Result := getProcAddress(hLib, PChar(functionname))
  else
    Result := nil;
end;

function SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent: Boolean): Boolean;
begin
  if not Assigned(_SetSuspendState) then
    @_SetSuspendState := LinkAPI('POWRPROF.dll', 'SetSuspendState');
  if Assigned(_SetSuspendState) then
    Result := _SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent)
  else
    Result := False;
end;

But how do I make it work under Windows 10, too?

If I test it on a Win10 TabletPC (by calling: SetSuspendState(False, False, False); the device is shutting down completely.

Update2:

Tried to send a virtual "Sleep" button press too:

const
  VK_SLEEP = $5F;
begin
  keybd_event(VK_SLEEP, 0, 0, 0);
  Application.ProcessMessages;
  keybd_event(VK_SLEEP, 0, KEYEVENTF_KEYUP, 0);
  Application.ProcessMessages;

But the application's OnKeyDown event could not catch it, like it was never sent.

Update3:
After thorough investigation of the problem during last days I've realized following things:

  1. The first code I've wrote here: WORKS under Win10 too! But only on some machines. :-(
  2. On a (AMD) Desktop PC, it worked perfectly fine. It had an old (1709) Win10 installed, so I've updated to see if it's related to Win10 builds, but the code still worked. Also tested from User/Admin privileges: no difference! Works always.
  3. Tested 4 different Intel-Atom Tablets: 1 did nothing, 2 shut down, 1 hibernated.
  4. On the tablets even a simple ".BAT" file to put the device into standby did NOT work!
  5. Tested all versions of .BAT + script-files (`powercfg -h off', etc...) nothing helped.
  6. 6.

Summarized:
So my first code is basically affected by Power-configurations and problems of Win10 drivers and OS.

That's why I think the only solution would be to circumvent the whole problem by simply simulating a "Keyboard-SLEEP-KEY-PRESS" (as I've tried at 'Update2').


Solution

  • Found the same conclusions at this topic:
    programmatically-enter-connected-standby-in-c-sharp

    Solution is to send a monitor-turn-off signal:
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, 2);