예제 #1
0
        void BatteryCheck(object state)
        {
            SYSTEM_POWER_STATUS_EX status = new SYSTEM_POWER_STATUS_EX();

            if (GetSystemPowerStatusEx(status, true))
            {
                if (status.ACLineStatus != oldStatus)
                {
                    OnPowerMessage("power source: " + status.ACLineStatus.ToString(), status.ACLineStatus == ACLineStatus.AC_LINE_ONLINE ? true : false);
                    oldStatus = status.ACLineStatus;
                }
            }
        }
예제 #2
0
        private void PowerEventArrive(object sender, EventArrivedEventArgs e)
        {
            // Credit: https://stackoverflow.com/questions/3948884/detect-power-state-change
            bool exitLoop = false;
            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" }
            };

            foreach (PropertyData pd in e.NewEvent.Properties)
            {
                if (pd != null && pd.Value != null && !exitLoop)
                {
                    if (pd.Value.ToString() == "10")
                    // Power Status Change event = 10
                    {
                        List <string> executeCommands    = null;
                        bool          cancellingPowerOff = false;
                        int           taskDelay          = 0;
                        var           powerStatus        = Win32PowerManager.GetSystemPowerStatus();
                        ACLineStatus  newACLineStatus    = powerStatus.ACLineStatus;

                        // We'll be done with the event after this
                        exitLoop = true;

                        if (newACLineStatus == ACLineStatus.Online)
                        {
                            // Power was off but came back on
                            executeCommands = _appSettings.PowerOnCommands;

                            // Cancel any running tasks and refresh cancellation token source

                            // TODO: Code below should only run if there is a currently running power off task
                            if (_powerOffDelayed)
                            {
                                _powerOffDelayed = false;
                                _runningTasksCancellationTokenSource.Cancel();
                                cancellingPowerOff = true;

                                _logger.LogInformation($"Power back on within ({_appSettings.SecondsBeforePowerOffExecution}) seconds of power off. Skipping execution of power on script(s).");
                            }
                            else
                            {
                                _logger.LogInformation($"Power back on. Power on script(s) execution beginning...");
                            }
                        }
                        else if (newACLineStatus == ACLineStatus.Offline)
                        {
                            // Power was on but then went off
                            executeCommands  = _appSettings.PowerOffCommands;
                            taskDelay        = _appSettings.SecondsBeforePowerOffExecution * 1000;
                            _powerOffDelayed = true;

                            _logger.LogInformation($"Power is off. Waiting ({_appSettings.SecondsBeforePowerOffExecution}) seconds to begin execution of script(s)...");
                        }

                        // Execute the relevant commands
                        if (!cancellingPowerOff)
                        {
                            Task.Run(() =>
                            {
                                // Only reference this copy of the token inside of here
                                var localCancelToken = _runningTasksCancellationTokenSource;

                                try
                                {
                                    _logger.LogDebug($"Task ID#{Task.CurrentId} started.");
                                    _logger.LogInformation($"Executing command(s): {String.Join(", ", executeCommands)}");

                                    if (taskDelay > 0)
                                    {
                                        var delayTask = Task.Delay(taskDelay, localCancelToken.Token);
                                        _logger.LogDebug($"Task ID#{delayTask.Id} (delay task) started. Waiting ({taskDelay / 1000}) seconds...");

                                        // If the task is cancelled here, it will throw an AggregateException and be caught below.
                                        try
                                        {
                                            delayTask.Wait(localCancelToken.Token);
                                        }
                                        catch (OperationCanceledException)
                                        {
                                            _logger.LogDebug($"Task ID#{delayTask.Id} (delay task) cancelled.");
                                        }

                                        _powerOffDelayed = false;

                                        // Cancel the outer task if the inner one was cancelled
                                        localCancelToken.Token.ThrowIfCancellationRequested();

                                        _logger.LogDebug($"Task ID#{delayTask.Id} (delay task) completed.");
                                    }

                                    for (int x = 0; x < executeCommands.Count && !localCancelToken.Token.IsCancellationRequested; x++)
                                    {
                                        string command = executeCommands[x];

                                        using (var process = new Process())
                                        {
                                            bool procKilled = false;

                                            // Create a new process for each command in the list
                                            process.StartInfo.FileName        = command;
                                            process.StartInfo.CreateNoWindow  = true;
                                            process.StartInfo.UseShellExecute = true;

                                            _logger.LogInformation($"Starting child process ({command})...");

                                            try
                                            {
                                                process.Start();

                                                // Check for task cancellation once a second. If task was cancelled, kill the process
                                                const int PROC_POLL_INTERVAL = 1000;

                                                while (!process.WaitForExit(PROC_POLL_INTERVAL))
                                                {
                                                    if (localCancelToken.Token.IsCancellationRequested)
                                                    {
                                                        procKilled = true;
                                                        process.Kill(true);
                                                    }
                                                }

                                                _logger.LogInformation($"Child process {(procKilled ? "killed" : "ended")} ({command}).");
                                            }
                                            catch (Exception ex)
                                            {
                                                _logger.LogError(ex, "Unable to start process.");
                                            }
                                        }
                                    }
                                }
                                catch (AggregateException ae)
                                {
                                    ae.Handle(ex =>
                                    {
                                        if (ex is TaskCanceledException)
                                        {
                                            _logger.LogDebug($"Task ID#{(ex as TaskCanceledException).Task.Id} cancelled.");
                                        }

                                        return(ex is TaskCanceledException);
                                    });
                                }
                                catch (OperationCanceledException ex)
                                {
                                    _logger.LogDebug($"Task ID#{Task.CurrentId} cancelled.");
                                }
                            }, _runningTasksCancellationTokenSource.Token)
                            .ContinueWith((t) =>
                            {
                                // If a cancellation is requested, it will most likely be caught in the power off delay wait and caught in the AE handler just above.
                                // Because the exception was handled, the outer task will complete successfully despite being cancelled. Thus we'll need to handle this situation here
                                // by reporting the task as being cancelled and resetting the cancellation token source
                                if (t.IsCanceled)
                                {
                                    _logger.LogDebug($"Task ID#{t.Id} cancelled.");
                                }
                                else
                                {
                                    _logger.LogDebug($"Task ID#{t.Id} completed with status ({t.Status})");
                                }
                            }, _runningTasksCancellationTokenSource.Token);
                        }
                        else
                        {
                            _runningTasksCancellationTokenSource = new CancellationTokenSource();
                        }
                    }
                }

                /*
                 * var name = powerValues.ContainsKey(pd.Value.ToString())
                 *             ? powerValues[pd.Value.ToString()]
                 *             : pd.Value.ToString();
                 * _logger.LogInformation($"POWER EVENT: {name}");
                 */
            }
        }