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.
Related
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 currently working on some parental control software. This software is supposed to log out a user and then lock the account so that they cannot log back in unless the parent/admin has specified that they can.
I have tried several things so far such as setting flags on the user account saying that it is disabled. This completely removes it from the login screen. From what I have found out is that if the user account is logged in, it doesn't apply the ADS_Disable flag. I have also tried looking for resources on logging out another account but I can only seem to find information on logging out the account that is running the logout command. Such as Pinvoke, or directly calling the LOGOUT.EXE program.
I found a resource on LSAUser and found that there might be something there. I am doing this project for school and I am needing a little guidance. Since there is such a sparse amount of information on doing this, is there a better way of doing what I want to do? Or is there a reason why I shouldn't do this? Any alternatives?
Use the WTSDisconnectSession() Windows API. See article here.
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
class Program
{
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
[DllImport("Kernel32.dll", SetLastError = true)]
static extern int WTSGetActiveConsoleSessionId();
const int WTS_CURRENT_SESSION = -1;
static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
static void Main(string[] args)
{
if (!WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,
WTS_CURRENT_SESSION, false))
throw new Win32Exception();
}
}
Even without remote desktop, it will disconnect the current user and go to the login screen. The processes will still run in the background. After manually login in again, the running programs will appear as they were before the disconnect.
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
When you use WTSDisconnectSession in remote desktop is equivalent to 'Close' the remote desktop windows. It is disconnect your Windows session, but hold the connection.
The advantage is you can reconnect back the session later by remote log in again.
The disadvantage is the Windows may not be able log in by other user when the remote desktop connection is full.
To simulate Windows 'Log off' should use ExitWindowsEx under user32.dll
[DllImport("user32.dll", SetLastError = true)]
static extern bool ExitWindowsEx(uint uFlags, uint dwReason);
public static bool WindowsLogOff() {
return ExitWindowsEx(0, 0);
}
if you want to Force the user to log off you need to add the EWX_FORCE flag like this:
ExitWindowsEx(0 | 0x00000004, 0);
More details on the function here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376868(v=vs.85).aspx
piggybacking off Leng Weh Seng's answer (since I can't comment), if you want to Force the user to log off you need to add the EWX_FORCE flag like this:
ExitWindowsEx(0 | 0x00000004, 0);
More details on the function here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376868(v=vs.85).aspx
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.
In order to get the application name of the foreground Window (or the name of application file) I want to use GetActiveWindow with GetWindowModuleFileName.
I found a similar question relating to GetWindowText here
That implementation of GetWindowText works fine, but GetWindowModuleFileName only returns a value for visual studio (when I click inside the devenv) for all other applications it stays blank.
Any hint how I can find out what goes wrong? Might this have to do with permission/security of my application querying the applicationfilename of another process?
EDIT: http://support.microsoft.com/?id=228469 looks like this doesn't work under Win >=XP
Any alternatives how to get the application file name?
In order to get the application name of the foreground Window (or the name of application file) I want to use GetActiveWindow with GetWindowModuleFileName.
... querying the applicationfilename of another process ...
In my opinion your problem with use of GetActiveWindow() function. It is used for gathering information from the calling thread/process only. If calling thread is inactive GetActiveWindow return 0;
From MSDN:
GetActiveWindow Retrieves the window handle to the active window attached to the calling thread's message queue.
Try to use GetForegroundWindow() function instead of GetActiveWindow()
By chance do you have UAC turned off?
Starting with Vista, if your code touches an HWND in another process, your process needs to be run at the same privilege level.
In other words, if the window is hosted in a process running as administrator, your app must also run as administrator.
I found a workaround using this:
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
IntPtr handle = IntPtr.Zero;
handle = GetForegroundWindow();
uint processId;
if (GetWindowThreadProcessId(handle, out processId) > 0)
{
Console.WriteLine(Process.GetProcessById((int)processId).MainModule.FileName);
}
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