I have an application with some sort of media playing and I do not want the computer to sleep when my application runs. I searched around and came to know that this can be done by P/Invoke.
Neither should the display be turned off and neither should the computer go to sleep. So, I did the following to test this:
b.Click += (x, y) =>
{
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_AWAYMODE_REQUIRED);
Debug.WriteLine("Power line executed");
};
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
[FlagsAttribute]
public enum EXECUTION_STATE : uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
}
However, the computer still went to sleep after some time. What's missing here?
Away mode is not supported on XP. Use Continuous | Display | System instead.
SetThreadExecutionState
To enable away mode, an application uses both ES_AWAYMODE_REQUIRED and ES_CONTINUOUS; to disable away mode, an application calls SetThreadExecutionState with ES_CONTINUOUS and clears ES_AWAYMODE_REQUIRED. When away mode is enabled, any operation that would put the computer to sleep puts it in away mode instead. The computer appears to be sleeping while the system continues to perform tasks that do not require user input. Away mode does not affect the sleep idle timer; to prevent the system from entering sleep when the timer expires, an application must also set the ES_SYSTEM_REQUIRED value.
Related
I am trying to unschedule my computer shutdown/reboot/lock on C# by calling the following API function but when I call this function nothing happens. Can anyone help me fix it.
Shutdown or restart command
internal const int EWX_POWEROFF = 0x00000008;
[DllImport("advapi32.dll", SetLastError = true)]
static extern UInt32 InitiateShutdownA(string lpMachineName, string lpMessage, UInt32 dwGracePeriod, UInt32 dwShutdownFlags, UInt32 dwReason);
InitiateShutdownA(System.Environment.MachineName, "SHUTDOWN", 50, EWX_FORCE, 0);
And this is the command I used to cancel the shutdown/reboot command but it always returns false
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool AbortSystemShutdownA(String lpMachineName);
AbortSystemShutdownA(System.Environment.MachineName);
According to AbortSystemShutdown,
The InitiateSystemShutdown and InitiateSystemShutdownEx functions
display a dialog box that notifies the user that the system is
shutting down. During the shutdown time-out period, the
AbortSystemShutdown function can prevent the system from shutting
down.
InitiateSystemShutdown also shows
[in] dwTimeout
The length of time that the shutdown dialog box should be displayed,
in seconds. While this dialog box is displayed, the shutdown can be
stopped by the AbortSystemShutdown function.
If dwTimeout is not zero, InitiateSystemShutdown displays a dialog box
on the specified computer. The dialog box displays the name of the
user who called the function, displays the message specified by the
lpMessage parameter, and prompts the user to log off. The dialog box
beeps when it is created and remains on top of other windows in the
system. The dialog box can be moved but not closed. A timer counts
down the remaining time before a forced shutdown.
If dwTimeout is zero, the computer shuts down without displaying the
dialog box, and the shutdown cannot be stopped by AbortSystemShutdown.
There is a Displaying the Shutdown Dialog Box sample which explains these functions.
What's the best way to programmatically cause a Windows XP (or above) machine to wake up at a specific time. (Ideally a lot like how Media Center can start up automatically to record a particular TV program)
I've got a Windows service (written in C#) and I'd like this service to be able to cause the machine it is hosted on to start up at predetermined times.
Are there any BIOS settings or prerequisites (eg. ACPI) that need to be configured for this to work correctly?
This machine would be using dialup or 3G wireless modem, so unfortunately it can't rely on Wake on LAN.
You can use waitable timers to wake from a suspend or hibernate state. From what I can find, it is not possible to programmatically wake from normal shut down mode (soft off/S5), in that case, you need to specify a WakeOnRTC alarm in BIOS. To use waitable timers from C#, you need pInvoke. The import declarations are:
public delegate void TimerCompleteDelegate();
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetWaitableTimer(IntPtr hTimer, [In] ref long pDueTime, int lPeriod, TimerCompleteDelegate pfnCompletionRoutine, IntPtr pArgToCompletionRoutine, bool fResume);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CancelWaitableTimer(IntPtr hTimer);
You can use those functions in the following way:
public static IntPtr SetWakeAt(DateTime dt)
{
TimerCompleteDelegate timerComplete = null;
// read the manual for SetWaitableTimer to understand how this number is interpreted.
long interval = dt.ToFileTimeUtc();
IntPtr handle = CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer");
SetWaitableTimer(handle, ref interval, 0, timerComplete, IntPtr.Zero, true);
return handle;
}
You can then cancel the waitable timer with CancelWaitableTimer, using the returned handle as an argument.
Your program can hibernate and sleep using pInvoke:
[DllImport("powrprof.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
public static bool Hibernate()
{
return SetSuspendState(true, false, false);
}
public static bool Sleep()
{
return SetSuspendState(false, false, false);
}
Your system may not allow programs to let the computer enter hibernation. You can call the following method to allow hibernation:
public static bool EnableHibernate()
{
Process p = new Process();
p.StartInfo.FileName = "powercfg.exe";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.Arguments = "/hibernate on"; // this might be different in other locales
return p.Start();
}
The task scheduler program in Win7, taskschd.msc (and I beleive XP as well) can be set to wake the system on different triggers. Those triggers can be schedule, time, event, etc.
In at least Win7, you need to set "Allow Wake Timers" to 'Enabled' for this to work. This setting is found under...
--> Control Panel\Hardware and Sound\Power Options
click - "Edit Plan Settings"
click - "Change advanced power setting"
expand - "Sleep"
Expand - "Allow Wake timers"
Your best bet is using Wake on LAN capability. This will require another machine to send a packet of a special kind to wake your machine up.
This will not be helpful if your machine is not connected to the network or you for some reason don't wasnt to move this logic onto another machine. But it's useful for some configurations where you have multiple machines and want to wake them up programmatically.
Some machines have a BIOS alarm clock that can be set to wake up the computer at a certain hour. It should be possible to program this clock, but I don't know the specific details.
Edit: I found this program that should let you set the time. It's in C, under Linux, but maybe it can give you some hints.
A warning though: before trying anything that changes the BIOS settings directly be sure to write down every setting from BIOS screens, because in case of an error the BIOS might revert to factory default and you might need to set it up again as it was.
Project:
I currently devellop an application to warn the user if he leaves (lockscreen or shutdown) his workplace and has left his smartcard in the reader.
I was able to detect through the use of the WinAPI (WinSCard.dll) if the smarcard is currently in the reader.
Problem:
I read (correct me if this is wrong) it is not possible for an application to delay the lockscreen so I currently focus on delaying the shutdown.
The problem I am having now is that I need to delay the ongoing shutdown to warn the user that he left his smartcard.
I try to use ShutdownBlockReasonCreate to delay the shutdown for at least the 5 seconds Windows so generously lets me. The idea was that if the user removes his smartcard my application calls ShutdownBlockReasonDestroy to continue the shutdown.
I implemented the two methods like so:
[DllImport("User32.dll", EntryPoint = "ShutdownBlockReasonCreate",
CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool ShutdownBlockReasonCreate(
[In()]IntPtr wndHandle,
[In()]string reason);
[DllImport("User32.dll", EntryPoint = "ShutdownBlockReasonDestroy",
CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool ShutdownBlockReasonDestroy(
[In()]IntPtr wndHandle);
furthermore I use GetLastError to check for errors which I implemented this way:
[DllImport("Kernel32.dll", EntryPoint = "GetLastError",
CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int GetLastError();
Now the strange thing is that if I create the reason
WinAPIMethoden.ShutdownBlockReasonCreate(
new WindowInteropHelper(Application.Current.MainWindow).Handle,
"Smartcard still in reader!");
and then display the error
MessageBox.Show(WinAPIMethoden.GetLastError().ToString("X"));
it shows 0 which stands for ERROR_SUCCESS.
So far everything seems great.
Now if I try to shut the PC down there is no sign whatsoever that my application has requested that the PC should not be shut down right now.
Question:
What am I doing wrong so that ShutdownBlockReasonCreate does not work as intended?
Or is there maybe a better way to prevent the user from shutting the PC down if his smartcard is still in like preventing him from initiating the shutdown while his card is in or something like that?
tl;dr:
I try to prevent shutdown while user has his smartcard in the reader.
I use ShutdownBlockReasonCreate but it doesnt seem to work although there is no error.
Solution:
The accepted answer lead me to the solution of the problem.
You have to create the cancle reason AND subscribe a handler to SystemEvents.SessionEnding.
This handler then has to set e.Cancel to true
void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
if (mgr.state == SmartcardState.Inserted)
{
e.Cancel = true;
}
}
To execute the programm on shutdown I addet it to the shutdown scripts using gpendit.msc.
The programm then gets executed AFTER all programs have been terminated. Looks really weird but does the job.
Please take a look at these posts that could help you with your situation:
How to abort shutdown in Windows (XP|Vista) programatically?
Aborting computer shutdown from windows service
Prevent windows Shutdown with CANCEL option C#
Is there a way in c# to detect a Windows shutdown/logoff and cancel that action (after asking the user)
I am working on a C# application which runs in the background without any Windows control.
I want to notify Windows that my application is still alive to prevent Windows from going into the idle state.
Are there any APIs available to call from my application which notify the Windows OS that my application is still alive?
Thanks in advance.
You've to use SetThreadExecutionState function. Something like this:
public partial class MyWinForm: Window
{
private uint fPreviousExecutionState;
public Window1()
{
InitializeComponent();
// Set new state to prevent system sleep
fPreviousExecutionState = NativeMethods.SetThreadExecutionState(
NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED);
if (fPreviousExecutionState == 0)
{
Console.WriteLine("SetThreadExecutionState failed. Do something here...");
Close();
}
}
protected override void OnClosed(System.EventArgs e)
{
base.OnClosed(e);
// Restore previous state
if (NativeMethods.SetThreadExecutionState(fPreviousExecutionState) == 0)
{
// No way to recover; already exiting
}
}
}
internal static class NativeMethods
{
// Import SetThreadExecutionState Win32 API and necessary flags
[DllImport("kernel32.dll")]
public static extern uint SetThreadExecutionState(uint esFlags);
public const uint ES_CONTINUOUS = 0x80000000;
public const uint ES_SYSTEM_REQUIRED = 0x00000001;
}
You have a couple of options:
Use SetThreadExecutionState, which:
Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running.
Where you could use the ES_SYSTEM_REQUIRED flag to
Forces the system to be in the working state by resetting the system idle timer.
Use SendInput to fake keystroke, mouse motion/clicks
Another alternative would be to change your app to be a Windows service.
SetThreadExecutionState example
// Television recording is beginning. Enable away mode and prevent
// the sleep idle time-out.
SetThreadExecutionState(
ES_CONTINUOUS |
ES_SYSTEM_REQUIRED |
ES_AWAYMODE_REQUIRED);
// Wait until recording is complete...
// Clear EXECUTION_STATE flags to disable away mode and allow the system
// to idle to sleep normally.
SetThreadExecutionState(ES_CONTINUOUS);
You can use SetThreadExecutionState described here:
SetThreadExecutionState Function
Since it is a Win32 API function, to use it from C# you'll need to PInvoke it. The steps are described here, including a sample method PreventSleep to temporarily disable sleep mode:
PInvoke.net: setthreadexecutionstate (kernel32)
I don't think there's any way to do this directly in managed code.
A quick search reveals this post from 2 years ago. Basically you'd need to do some interop to call a raw windows API.
Here is SetThreadExecutionState C# implementation
I have a desktop application in which I would like to know two things:
Is the user currently on the PC (more specifically, is he giving any input to the PC), so I can change his state to "away" if needed; and
Is the screensaver running right now, so I can perform more CPU intensive work during that time.
I'm using C#/.NET. How would you suggest to tackle these two tasks?
NOTE: WIN32 invocation will be just as good, as well as any unmanaged code solution.
http://dataerror.blogspot.com/2005/02/detect-windows-idle-time.html
^ Detect Windows Idle Time. :)
The enabler for this feature is the GetLastInputInfo() Win32 API and the LASTINPUTINFO Win32 structure.
Here is the code to detect if a screen saver is running. See this for more details
const int SPI_GETSCREENSAVERRUNNING = 114;
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
private static extern bool SystemParametersInfo(
int uAction, int uParam, ref bool lpvParam,
int flags );
// Returns TRUE if the screen saver is actually running
public static bool GetScreenSaverRunning( )
{
bool isRunning = false;
SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0,
ref isRunning, 0 );
return isRunning;
}
Rather than figuring out when to run more intensive work... Consider doing your "intensive work" as early as you can, but at a lower thread priority.
I don't think your questions have an answer in pure C#, unless you poll the mouse position and observe movements... Or something like that.
You could use a global keyboard/mouse hook and just reset your "counter" to 0 when you receive an event from either. When your counter reaches the idle time that you're looking for, perform your background actions.
There is some code here that allows you to easily do the hooking in .NET: http://www.codeproject.com/KB/cs/globalhook.aspx