1

I am trying to create windows screensaver that turns monitor on and off depending on face detection. Here is the esential code (c++ and winapi):

#define TIMER 1010
unsigned int FREQUENCY_OF_CHECK = 5000;
LRESULT WINAPI ScreenSaverProc(
     HWND hwnd, 
     UINT message, 
     WPARAM wParam, 
     LPARAM lParam)
{
  if(!fChildPreview)
  {
    switch(message) 
    {
      case WM_CREATE:
        //start timer
        SetTimer(hwnd, TIMER, FREQUENCY_OF_CHECK, NULL);
        //create transparent see thru layer
        SetWindowLong(
               hwnd, 
               GWL_EXSTYLE, 
               GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED
               );
        break;

      case WM_DESTROY:
        SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1);
        KillTimer(hwnd, TIMER);
        break;

      case WM_TIMER:
        //separate process detects face and stores detection into registry
        if(!ProcessRunning("capture.exe")){
            ShellExecute(
               NULL,
               "open",
               "C:/camsaver/capture.exe",
               "",
               "", 
               SW_SHOWNOACTIVATE);
        }
        //load detection from registry and then turn monitor on/off
        bool face;
        readFaceFromRegistry(face);

        if (face){
            //turn monitor on
            SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1);
        }
        else {
            //turn monitor off
            SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
        }

        break;

      default:
        return DefScreenSaverProc(hwnd, message, wParam, lParam);
      }
    return 0;
  }
}

If the screensaver runs by itself when it doesnt detect face it just turns off the monitor and stops doing anything else.
I'd like it to continue running and turn the screen back on when there is a face detected. Like it does when run in preview mode.
My guess is that the line SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2); does something more than I am aware of.

luda
  • 11
  • 3
  • 1
    When a screen saver runs, it runs on a different desktop than the user. Perhaps your `ShellExecute` is failing? – Mark Ransom May 09 '14 at 22:22
  • That's not it. The `ShellExecute` doesn't even start to give any error code. It really seems like the whole Screensaver just pauses indefinitely. – luda May 09 '14 at 23:15
  • 1
    My guess is [you're experiencing a glitch(?) where `SC_MONITORPOWER` won't turn the monitor on](http://stackoverflow.com/questions/12572441/sendmessage-sc-monitorpower-wont-turn-monitor-on-when-running-windows-8). You should be able to prove/disprove this by running your screensaver code in isolation - in other words, just test the code that turns the screen off and back on again, and see if this issue still occurs. – cf- May 10 '14 at 03:54
  • also: your `WM_CREATE` code doesn't have a `break;` at the end – Edward Clements May 10 '14 at 07:28
  • @computerfreaker The glitch is not a issue, I am running W7, and as I pointed out the code works when run in preview mode, the problem occures when the screensaver runs automaticaly. I edited the `break;`, it slipped when copying code here. – luda May 10 '14 at 10:54
  • It is possible that your computer is overzealous in responding to the signal to turn off the monitor, and is actually going to sleep. You should be able to verify this using something like `MessageBeep`. Does it beep while the screen is dark, or only after the system is woken back up? – Cody Gray - on strike May 10 '14 at 11:18
  • It beeps all the time. @MarkRansom could you give me some hint on running on different user? I am not really sure what you mean. – luda May 10 '14 at 13:14
  • This may be one of those times when you're forced to run the program as a Windows Service rather than a regular program. I'm afraid I don't have much experience with that. – Mark Ransom May 10 '14 at 14:43
  • @MarkRansom I really dont have time to recreate the whole thing into service. Would you happen to know how to run the "capture.exe" from the screen saver so it is completly independent on it? This way it shouldnt get shut down with it and I might find some workaround... – luda May 12 '14 at 01:16

1 Answers1

0

So apparently in Win7 the SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2); not only turns off screen but also shuts down the screensaver (without even bothering sending it at least a destoy message first). There is no simple way to hack this.
Reference: I found this and it also leads to some other threads at msdn. (Which I cannot link right now due to my reputation...)

And while I am at it the above code won't work for Win8 either because SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1); doesn't turn on screen in Win8. However this should be easy to solve as in this C# workaround.

Community
  • 1
  • 1
luda
  • 11
  • 3
  • If I'm reading this right, `SC_MONITORPOWER` doesn't *change* the state of the monitor, it *notifies* you of a change. – Mark Ransom May 12 '14 at 04:17
  • Sure, but as far as I understand it, it may as well change the state of the screen because google tells me it is the only way to turn off screen thru WinAPI. There is no point of intercepting the message in the saver as it is where the message comes from in the first place. Also there are some ways to tell the system, that you want that one application running no matter what (`SetThreadExecutionState`) but it doesn't work for the saver... – luda May 12 '14 at 05:53