Using SetWaitableTimer in WPF - c#

I am creating a WPF app where I have to make device to sleep and awake at particular time. I tried to used SetWaitableTimer to do the same but due some mistakes my device is going into sleep but not able to do the awake part
For testing purpose I have set the time of 1 minute to awake
Code
DateTime dateTime = DateTime.Now;
var dt = dateTime.AddMinutes(1);
Log.Info("WakeUp after " + dt.ToString());
Utilities.TaskScheduler.SetWakeAt(dt);
Utilities.TaskScheduler.Sleep();
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);
[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);
}
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;
}

I tried the same code and it worked for me. You have to understand when SetWaitableTimer will support for the system, if your bios support Awake sleep timer option then you are all good with this code.
option 1 :
To check the awake sleep timer option , Go to control panel -> power option -> change current power plan -> click on advance setting and check the sleep dropdown
Option 2 :
Open an elevated command prompt.
Type the command below you want to use into the elevated command prompt, and press Enter.
(Add - default)
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\238C9FA8-0AAD-41ED-83F4-97BE242C8F20\BD3B718A-0680-4D9D-8AB2-E1D2B4AC806D /v Attributes /t REG_DWORD /d 2 /f
OR
(Remove)
powercfg -attributes SUB_SLEEP BD3B718A-0680-4D9D-8AB2-E1D2B4AC806D +ATTRIB_HIDE

Related

C# How to import ntdll.dll to use NtDelayExecution and ZwSetTimerResolution?

I am new to C# and I am trying to use the NtDelayExecution and ZwSetTimerResolution functions from ntdll.dll in order to create a custom sleep timer. (Thread.sleep is not precise enough for my application). I have tried many different ways, but i'm not sure how to import ntdll.dll in order to use these two functions. The two static NTSTATUS lines are partial c++ that I am trying to convert to C#. What I have tried so far:
public unsafe static void GoSleep(float ms, float resolution = 0.5f)
{
if (resolution < 0.5) resolution = 0.5f;
if (ms < resolution) ms = resolution;
nuint res = (nuint)(resolution * 10000);
nuint actualRes = 0;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] in string lpModuleName);
static NTSTATUS(__stdcall* NtDelayExecution)(bool Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(bool, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle(X("ntdll.dll")), X("NtDelayExecution"));
static NTSTATUS(__stdcall* ZwSetTimerResolution)(IN nuint RequestedResolution, IN bool Set, OUT pnuint ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle(X("ntdll.dll")), X("ZwSetTimerResolution"));
ZwSetTimerResolution(res, true, &actualRes);
long LargeInteger = -1 * (long)(ms * 10000.0f);
NtDelayExecution(false, &LargeInteger);
ZwSetTimerResolution(res, false, &actualRes);
}
The easiest way to import it is to use nuget.
Right click on nuget manager
Enter ntdll.dll, then select install

How to change setWaitableTimer accuracy on Windows 10 20H1 and later

There seems to have been a change to timer resolution in Windows 10 20H1 (https://randomascii.wordpress.com/2020/10/04/windows-timer-resolution-the-great-rule-change/).
If you want to use sleep() then reasonable accuracy can still be obtained by using the timeBeginPeriod() function. This approach doesn't seem to work with the waitable timers. Does anyone know of a way of improving the accuracy of these timers?
This is an extract from the test program I am using
// class Results omitted for clarity - it sums the duration calls to timerCallback() and divides it by the number of times it was called.
class Program
{
static Results m_Results = new Results();
// Windows API function imports
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
[DllImport("kernel32.dll")]
public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, CallBack pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
// callback definition
public delegate bool CallBack(IntPtr lpArg, int dwTimerLowValue, int dwTimerHighValue);
// Main method, run when the application is run
static void Main(string[] args)
{
SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, false, "MyWaitabletimer");
CallBack myCallBack = new CallBack(Program.timerCallback); // This function records the time its executed in a global list
const int period = 40; // Fire the timer every 40 mS
long duetime = period * -10000; // Keep firing the timer for 4 seconds
TimeBeginPeriod(1); // *** This call appears to make no difference.
SetWaitableTimer(handle, ref duetime, period, myCallBack, IntPtr.Zero, false);
TimeEndPeriod(1); // *** This call appears to make no difference.
Thread.Sleep(4000);
Console.WriteLine("count = {0}", m_Results.getCount());
Console.WriteLine("total duration = {0}", m_Results.getTotalDuration());
Console.WriteLine("average = {0}", m_Results.getResults());
Console.WriteLine("Tests complete");
Console.ReadKey();
}
public static bool timerCallback(IntPtr lpArg, int dwTimerLowValue, int dwTimerHighValue)
{
m_Results.addDifference(DateTime.Now.Millisecond);
return true;
}
When I run the code I get a count of 84, 85 or 86, a total duration <4000 and an average between 46 and 47 mS.
Is my testing method incorrect?
I appreciate it won't always be exactly 40mS but I can get the Sleep call accurate to within .1 of a mS. Is there some command to enable better accuracy?
BTW - I tried the code in C++, but I can't get the timerFunc() to trigger, event when waiting objects.

.NET Core on Linux: Is stdout redirected?

On Windows, I use this code to determine whether the stdout stream is redirected for the currently running process:
private static bool? isOutputRedirected;
public static bool IsOutputRedirected
{
get
{
if (isOutputRedirected == null)
{
isOutputRedirected =
GetFileType(GetStdHandle(StdHandle.Output)) != FileType.FileTypeChar ||
!GetConsoleMode(GetStdHandle(StdHandle.Output), out _);
// Additional GetConsoleMode check required to detect redirection to "nul"
}
return isOutputRedirected == true;
}
}
private enum StdHandle : int
{
Input = -10,
Output = -11,
Error = -12,
}
private enum FileType : uint
{
FileTypeChar = 0x0002,
FileTypeDisk = 0x0001,
FileTypePipe = 0x0003,
FileTypeRemote = 0x8000,
FileTypeUnknown = 0x0000,
}
[DllImport("kernel32.dll")]
private static extern FileType GetFileType(IntPtr hFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(StdHandle nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
I have similar properties for the other two standard streams.
This is required to handle situations when displaying progress info or trying to update the current line with new content. This isn't useful when the output is being redirected, so the output should be reduced to more simple content.
But this fails as expected when running on Linux (dotnet publish -r linux-arm).
How can I determine the same situation on Linux? The web doesn't seem to know anything about it (yet).
For .NET Framework 4.5 and beyond, you might want to look at Console.IsOutputRedirected and Console.IsErrorRedirected
source: https://learn.microsoft.com/en-us/dotnet/api/system.console?view=netcore-3.1

WindowsAccessBridge for Java Automation using C#

I try to automate an java application using WindowsAccessBridge.dll.
I can get the window handle but calling the function isJavaWindow(System.IntPtr hWnd) always return false
Please find my code below:
static void Main()
{
System.Int32 vmID = 0;
System.Int64 _acParent = 0;
string WndName = "GLOBUS EDU";
string ClassName = "SunAwtFrame";
Windows_run();
System.IntPtr hWnd = System.IntPtr.Zero;
hWnd = (System.IntPtr)FindWindow(ClassName, WndName);
bool Found = isJavaWindow(hWnd);
if (!Found) { throw new System.Exception("ERROR: Unable to find window by classname " + ClassName + " and " + WndName + "!"); }
System.Console.WriteLine("Application is finished. Press ENTER to exit...");
System.Console.ReadKey();
}
Interop:
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
[System.Runtime.InteropServices.DllImport("WindowsAccessBridge-64.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
private extern static bool getAccessibleContextFromHWNDFct(System.IntPtr hwnd, out System.Int32 vmID, out System.Int32 _acParent);
private static bool getAccesibleContextFromHWND(System.IntPtr hWnd, out System.Int32 vmID, out System.Int64 acParent)
{
System.Int32 ac = -1;
bool retVal = false;
getAccessibleContextFromHWNDFct(hWnd, out vmID, out ac);
acParent = ac;
return retVal;
}
[System.Runtime.InteropServices.DllImport("WindowsAccessBridge-64.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
private extern static bool getAccessibleContextInfo(int vmID, System.IntPtr ac, out AccessibleContextInfo textInfo);
[System.Runtime.InteropServices.DllImport("WindowsAccessBridge-64.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, ThrowOnUnmappableChar = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
private extern static void Windows_run();
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern System.IntPtr FindWindowByCaptionFct(System.IntPtr ZeroOnly, string lpWindowName);
private static System.IntPtr FindWindowByCaption(string WindowTitle) { return FindWindowByCaptionFct(System.IntPtr.Zero, WindowTitle); }
[System.Runtime.InteropServices.DllImport("WindowsAccessBridge-64.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, ThrowOnUnmappableChar = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
private extern static System.Boolean isJavaWindow(System.IntPtr hwnd);
The function FindWindowis working perfect and I'm getting the window handle also Spy++ shows me. The classname is SunAwtFrameas Spy++ says.
My Java applications runs in 64 bit but I tried all the Libraries (-32, -64) and also switched in the VS Configuration Manager from x86 to x64 and back.
The AccessBridge itself is working well - Java-Monkey-64.exe can spy my running java application.
Does anybody has an idea, why this is not working?
Regards,
Jan
I have been fighting with your problem in few days.
i created a program that enumerate window that is java application(of course write on console application), and catch same problem like yours.
then, i rewrite it on WPF application,enumerate all window, then recognize that: besides the normal window, i see a strange window named: "java access bridge", and the problem is clearly:
the Windows_run function need to have an active windows message pump.
another way, you must putting it on the constructor of a WPF application or something same that.
if (result != FALSE) {
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
shutdownAccessBridge();
}
code in Java Monkey application.
After create a hidden window, it performs a PostMessage with a registered message. The JVM side of the access bridge responds to this message, and posts back another message to the window that was created. As such, they communicate by that way.
and more, you only can call JAB functions after the message pump can process messages.
that is reason why the java monkey need to use call back for it's business.
Pass null for class name as in the below code:
IntPtr hWnd = FindWindow(null, "GLOBUS EDU"); //cast to IntPtr is redundant
bool Found = isJavaWindow(hWnd);
Reference is here on Pinvoke documentation, and it works for me!

C# console application lose focus

I have about 15 different console apps on my local PC and they are running with different time periods as scheduled tasks.
Since I am using this computer as personal usage (such as surfing on YouTube or Watching Movies)
They are jumping on my screen but I have to always minimize them manually.
My goal is, I want them to first appear (which is already doing) and lose automatically focus after a couple of seconds.
Is it possible with console apps on Windows?
If you want to minimize console window, you can use WinApi
const Int32 SW_MINIMIZE = 6;
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern IntPtr GetConsoleWindow();
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow([In] IntPtr hWnd, [In] Int32 nCmdShow);
private static void MinimizeConsoleWindow()
{
IntPtr hWndConsole = GetConsoleWindow();
ShowWindow(hWndConsole, SW_MINIMIZE);
}
Usage:
static void Main(string[] args)
{
Console.WriteLine("Starting foo...");
Thread.Sleep(1000); // hold console for a second on the screen
MinimizeConsoleWindow();
Console.ReadKey();
}

Categories