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
Related
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.
When using
InitiateSystemShutdown(null, null, 0, true, false);
some weird things happen. It all works well when I just call the function, also works fine build in my shut-down timer application but the thing is that it does not shut down pc when it's idle for 30+ min and my monitors turn off.
I used other functions to try and shut down the system but I come across the same problem whatever I use. The system does not go to sleep or hibernate or anything like that, it just turns off the displays.
is there a need to "wake" system up somehow prior to calling the function or anything like that.
Method declared as:
static extern bool InitiateSystemShutdown(
[MarshalAs(UnmanagedType.LPStr)] string lpMachinename,
[MarshalAs(UnmanagedType.LPStr)] string lpMessage,
Int32 dwTimeout,
bool bForceAppsClosed,
bool bRebootAfterShutdown);
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 WinForms application (I'm using VB) that can be minimized to the system tray. I used the "hackish" methods described in multiple posts utilizing a NotifyIcon and playing with the Form_Resize event.
This all works fine aesthetically, but the resources and memory used are unaffected. I want to be able to minimize resources when minimizing to system tray, just like Visual Studio does. If you are coding in Visual Studio, the memory usage can creep up (depending on project size) to above 500 MB, but when minimizing Visual Studio to the taskbar, the memory drastically decreases to (what I'm assuming) is the minimal amount.
Does anyone have any clue as to how to accomplish this?
Here's a short description of the application, if anyone finds it relevant: I have a windows form with a ListView that contains Work Orders for my IT department. The application has a "listener" that notifies when a new Work order is submitted. So, when the application is running in the system tray, all I really do is compare the count of items in the ListView to a count of rows in a SQL table every couple of minutes.
EDIT: To be more specific, a windows form intrinsically has threads and resources being used by means of the controls, when the form is invisible (in the system tray) these resources are still being used. What can I do to minimize these resources, short of killing all the controls and redrawing them when the form is restored.
Calling MiniMizeMemory() will do a garbage collection, trim the process working size, then compact the process' heap.
public static void MinimizeMemory()
{
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(
Process.GetCurrentProcess().Handle,
(UIntPtr)0xFFFFFFFF,
(UIntPtr)0xFFFFFFFF);
IntPtr heap = GetProcessHeap();
if (HeapLock(heap))
{
try
{
if (HeapCompact(heap, 0) == 0)
{
// error condition ignored
}
}
finally
{
HeapUnlock(heap);
}
}
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetProcessWorkingSetSize(
IntPtr process,
UIntPtr minimumWorkingSetSize,
UIntPtr maximumWorkingSetSize);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcessHeap();
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool HeapLock(IntPtr heap);
[DllImport("kernel32.dll")]
internal static extern uint HeapCompact(IntPtr heap, uint flags);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool HeapUnlock(IntPtr heap);
You're probably looking for this function call: SetProcessWorkingSetSize
If you execute the API call SetProcessWorkingSetSize with -1 as an argument, then Windows will trim the working set immediately.
However, if most of the memory is still being held by resources you haven't released minimizing the working set will do nothing. This combined with the suggestion of forcing Garbage Collection might be your best bet.
From your application description, you might want to also verify how much memory the ListView is consuming as well as the database access objects. I'm also not clear on how you're making those monitoring database calls. You might want to isolate that into a separate object and avoid touching any of the forms while minimized, otherwise the program will be forced to keep the controls loaded and accessible. You could start a separate thread for monitoring, and pass the ListView.Count as a parameter.
Some sources:
.NET Applications and the Working Set
How much memory does my .Net Application use?
To clean up unused memory, use GC.Collect()... though you should read up on why to do it and why its usually a bad idea to use it often.
If you mean other resources, you will need to be more specific.
While this is in C#, look at the source code, it will solve any issues you have:
http://www.codeproject.com/KB/cs/NotifyIconExample.aspx
How can I prevent the pocket PC device from shutting down from my application when the power button pressed? I am using C#.
You could use the Microsoft.WindowsCE.Form.MessageWindows class to intercept the Power Button event. This solution will not be portable, as the hardware key will be different in different machines.
I recommend however that you don't disable power down completely. Have a look at my answer in another question here. You could also use openetcf to easily create power down events handlers and register wake up events. You should implement the application logic based on what you are trying to achieve, for instance wake up every one minute to run a process.
You can try changing the power requirements for the device "BLK1:", which is the blacklight device. Be aware that the behavior may not be the same on all devices and version of the OS or Vendor specific Extensions.
To do this, you can write something like :
[DllImport("coredll")]
private extern static IntPtr SetPowerRequirement(string pvDevice, int deviceState,
int deviceFlags, IntPtr pvSystemState, int stateFlags);
[DllImport("coredll")]
private extern static int ReleasePowerRequirement(IntPtr handle);
and call it this way :
IntPtr handle = SetPowerRequirement("BLK1:", 0 /* D0, Full On */, 1, IntPtr.Zero, 0);
// Do something that requires the device to stay on ...
ReleasePowerRequirement(handle);
But this is generally not a good practice, leaving a device with the backlight on for extended periods might reduce dramatically its autonomy.