6

Background

My son likes to use his laptop when he's not supposed to and I just thought it would be handy if I could write an application that would email me whenever he opened / closed his laptop.

(I'd even settle for something that notified me when there was network traffic on the machine)

Question

How do you programmatically detect when an OS is waking up or going to sleep? I found this link from this related post. But that covers OS X. I'm looking for the same thing for Windows 7.

(I'd like to do this in Java, if possible, but I'd settle for C#/C++)

Community
  • 1
  • 1
gMale
  • 17,147
  • 17
  • 91
  • 116
  • You can't do this in Java as far as I know unless you somehow tie into the OS with JNI or JNA. – Hovercraft Full Of Eels Jan 14 '11 at 17:01
  • 1
    Did you check windows events log? I believe it contains enough info. – AlexR Jan 14 '11 at 17:02
  • 2
    http://windows.microsoft.com/en-US/windows7/Control-when-children-can-use-the-computer – Austin Salonen Jan 14 '11 at 17:09
  • Sounds like a good use for parental controls. I use this to prevent logins too learly or late in the day. – Peter Lawrey Jan 14 '11 at 17:16
  • If he's not responsible enough not to use it when he's not supposed to, he shouldn't have it. – Shawn D. Jan 14 '11 at 18:17
  • 1
    A potential alternate solution to your problem, spurred by a recent project I was working on is this. You could write a simple C# app that takes a screenshot every 10-15min and saves it to your Dropbox (or emails it to you). If installed as a service, it will not function when the computer is asleep, and when awoken, not only will you know so, you can also monitor what exactly he is doing. – Ayush Jan 14 '11 at 20:02

6 Answers6

7

Easiest way is not to write any code at all, even though this is stack overflow. Click Start, type Schedule and choose Scheduled Tasks. Set one up (click Create Task) and set a Trigger when the machine is unlocked. For the Action, have it send you an email.

new trigger new action

Repeat for startup and when a user logs in, if you want. Done.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
  • I think this will exactly (not to mention elegantly) solve my problem. I'll try it and report back! – gMale Feb 21 '11 at 15:23
6

You're going to want to create a window and watch for the WM_POWERBROADCAST message (http://msdn.microsoft.com/en-us/library/aa373248%28v=vs.85%29.aspx) and check the wParam for your desired action. For example, your window should receive a WM_POWERBROADCAST with PBT_APMSUSPEND as the wParam when the system is about to enter a suspended state (i.e. closing a laptop). Resuming seems to have a few different wParam values: PBT_APMRESUMESUSPEND, PBT_APMRESUMECRITICAL and PBT_APMRESUMEAUTOMATIC

Joe Jordan
  • 2,372
  • 2
  • 17
  • 20
5

I search for a long time and found that this was the best way, the 'Sleep'-event was never working before:

 private ManagementEventWatcher managementEventWatcher;
    private readonly Dictionary<string, string> powerValues = new Dictionary<string, string>
                         {
                             {"4", "Entering Suspend"},
                             {"7", "Resume from Suspend"},
                             {"10", "Power Status Change"},
                             {"11", "OEM Event"},
                             {"18", "Resume Automatic"}
                         };
    public void InitPowerEvents()
    {
        var q = new WqlEventQuery();
        var scope = new ManagementScope("root\\CIMV2");

        q.EventClassName = "Win32_PowerManagementEvent";
        managementEventWatcher = new ManagementEventWatcher(scope, q);
        managementEventWatcher.EventArrived += PowerEventArrive;
        managementEventWatcher.Start();
    }
    private void PowerEventArrive(object sender, EventArrivedEventArgs e)
    {
        foreach (PropertyData pd in e.NewEvent.Properties)
        {
            if (pd == null || pd.Value == null) continue;
            var name = powerValues.ContainsKey(pd.Value.ToString())
                           ? powerValues[pd.Value.ToString()]
                           : pd.Value.ToString();
            Console.WriteLine("PowerEvent:"+name);
        }
    }
    public void Stop()
    {
        managementEventWatcher.Stop();
    }
Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
Emmanuel
  • 7,574
  • 3
  • 24
  • 22
  • 1
    I think it's worth mentioning that you need to add the reference to System.Management in your project as well. - https://stackoverflow.com/questions/6218272/the-type-or-namespace-name-managementeventwatcher-not-found – Peet Jun 28 '18 at 14:35
1

A very simple, perhaps crude, but effective way may be to have a program with a timer firing every minute. If the timer fires and it's been, say, 5 minutes of real time since its last execution then you can likely assume that the computer was sleeping since it's unlikely that your thread was unable to be scheduled for so long.

The other reason for the difference may be a clock adjustment, like DST or a manual change, but that kind of "noise" should be very low, in your scenario.

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
0

You could write a simple app and register it as a Windows service, to be started automatically at system startup. This app could then do whatever you want when it starts. And if it's a proper Windows app, it can register to get notification about impending system shutdown too (I don't remember the details but I implemented this in a C++ MFC app many years ago).

If you prefer Java, you could register your app as a service via a suitable service wrapper like Tanuki (it seems they have a free Community License option). Although this might be overkill. And it may be possible to get notification about the JVM shutting down when the system is closing (but I have no concrete experience with this).

Péter Török
  • 114,404
  • 31
  • 268
  • 329
0

http://www.pinvoke.net/default.aspx/powrprof.CallNtPowerInformation - Check out the link. It has almost all win32api for all windows function. You can call power management feature directly in your windows 7 laptop. For that create a Windows Service , that will use these specific api to notify the machine state.