Using SetWaitableTimer in Universal Windows Platform - c#

I use SetWaitableTimer from "kernel32.dll" in my UWP app. I want the computer to wake from sleep because of my application. If I run the app in debug mode it works. If I run it in release mode then the computer doesn't wake up.
How can I do to make my application awakened the computer when it is running in realise mode?
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(SetWaitForWakeUpTime);
}
[DllImport("kernel32.dll")]
public static extern IntPtr CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll")]
public static extern bool SetWaitableTimer(IntPtr hTimer, [In] ref long pDueTime, int lPeriod,
IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern Int32 WaitForSingleObject(IntPtr handle, uint milliseconds);
static IntPtr handle;
static void SetWaitForWakeUpTime()
{
long duetime = -600000000;
handle = CreateWaitableTimer(IntPtr.Zero, true, "MyWaitabletimer");
SetWaitableTimer(handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true);
uint INFINITE = 0xFFFFFFFF;
int ret = WaitForSingleObject(handle, INFINITE);
}

Windows 10 Universal Windows Platform (UWP) apps can use a subset of the Win32 and COM APIs. This subset of APIs was chosen to support key scenarios for Windows Runtime apps that were not already covered by the Windows Runtime, HTML/CSS, or other supported languages or standards. The Windows App Certification Kit ensures that your app uses only this subset of the Win32 and COM API. For the Win32 APIs that can be used in UWP, please see Win32 and COM APIs for UWP apps.
Unfortunately, CreateWaitableTimer and SetWaitableTimer are not in the supported APIs. We can not use them in UWP apps. For a UWP app, it should not be able to wake the system from sleep. But we can prevent the system from sleep by using DisplayRequest class.
Apps that show video or run for extended periods without user input can request that the display remain on by calling DisplayRequest::RequestActive. When a display request is activated, the device's display remains on while the app is visible.
For more info, plesae see Remarks of DisplayRequest class.
But if you are developing apps for enterprise, you can try with Brokered Windows Runtime Components. With this, you have the ability to run existing desktop software assets in one process (desktop component) while interacting with this code in a UWP App. For more info, please check this blog.

Related

How to get WH_KEYBOARD_LL to work in a Universal Windows Platform Builds

Background: I have a library which requires keyboard scancodes (Not KeyCodes from the enum) which I am trying to get working with Unity for the HoloLens.
The only way to obtain scancodes from C# I have found so far is to use the Windows Hook system through PInvoke by registering a hook for WH_KEYBOARD_LL through SetWindowsHookEx
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
Documentation https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
The suggested way is to call it like this
IntPtr hHook;
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
IntPtr hModule = GetModuleHandle(module.ModuleName);
hHook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hook, hModule, 0);
}
see http://www.pinvoke.net/default.aspx/user32.setwindowshookex
This works well on PC builds, but the Remark for UWP in the documentation for SetWindowsHookEx is confusing me:
Windows Store app development If dwThreadId is zero, then window hook
DLLs are not loaded in-process for the Windows Store app processes and
the Windows Runtime broker process unless they are installed by either
UIAccess processes (accessibility tools). The notification is
delivered on the installer's thread for these hooks:
WH_JOURNALPLAYBACK WH_JOURNALRECORD WH_KEYBOARD WH_KEYBOARD_LL
WH_MOUSE WH_MOUSE_LL This behavior is similar to what happens when
there is an architecture mismatch between the hook DLL and the target
application process, for example, when the hook DLL is 32-bit and the
application process 64-bit.
As I understand I have to specify dwThreadId on UWP, otherwise it will not work. But if I do so using GetCurrentThreadId() (again through pinvoke), I get an error code:
ERROR_GLOBAL_ONLY_HOOK
1429 (0x595)
This hook procedure can only be set globally.
Setting hMod from GetModuleHandle(NULL) and dwThreadId to NULL creates a valid hookID but again no events arrive.
Since then I tried to search for ways to obtain a module handle, but did not find any way that works on UWP:
Process.GetCurrentProcess does not compile, missing
Marshal.GetHINSTANCE missing
GetType().Module.Name missing (for GetModuleHandle)
What else can I try?
The only way to obtain scancodes from C# I have found so far is to use the Windows Hook system through PInvoke by registering a hook for WH_KEYBOARD_LL through SetWindowsHookEx.
Unfortunately, the solution that you have mentioned is not applicable for UWP. For your requirement, you could use the AcceleratorKeyActivatedevent, and the AcceleratorKeyEventArgs provides the ScanCode value directly.
public MainPage()
{
this.InitializeComponent();
Window.Current.Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated;
}
private void Dispatcher_AcceleratorKeyActivated(Windows.UI.Core.CoreDispatcher sender, Windows.UI.Core.AcceleratorKeyEventArgs args)
{
var scanCode = args.KeyStatus.ScanCode;
}

SendKeys.SendWait doesn't work on Stella Emulator

Have tried a couple of days without any sucess.
I'm just trying to send keystrokes to a process, which is an Atari video game emulator (Stella).
My app is a Console Application in C# made with VS 2013, running in 64 bit Windows 7.
Method Sendkeys.Wait works fine with almost any app, e.g. calc, excel, notepad, etc.
Tried some approachs, such as:
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
static private void Teste(string key)
{
IntPtr stellaHandle = FindWindow("SDL_app", "Stella 4.6.7: \"River Raid (1982) (Activision)\"");
SetForegroundWindow(stellaHandle);
SendKeys.SendWait(key);
}
I compiled in Any CPU, x86 and x64, used 32 and 64 bit versions of Stella, tried also with an other emulator (Z26), even tried with a javascript emulator running in Firefox (http://www.virtualatari.org).
None of my approachs worked. Get the window is ok. Set the window as foreground also ok.
Any idea? Someone faced such a problem before?
Thanks in advance.

ShowWindow Function Doesn't Work When Target Application Is Run As Administrator

I am writing a program that shows/hides the window of some target application. I was testing it out earlier and noticed something strange. If I run the target application as Administrator (right-click->Properties, "Compatability" tab, "Run this program as administrator") it doesn't work.
To demonstrate I wrote a simple GUI app called "TargetApplication" and then I wrote the following code to test showing/hiding this application:
class Program
{
static void Main(string[] args)
{
IntPtr windowPtr = FindWindow(null, "TargetApplication");
ShowWindow(windowPtr, 0); // 0 = Hide
Console.WriteLine("The window is now hidden. Press Enter to restore");
Console.ReadLine();
ShowWindow(windowPtr, 9); // 9 = Restore
Console.WriteLine("The window is now restored. Press Enter to exit.");
Console.ReadLine();
}
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
If I start the windowed application without Administrator rights it doesn't work.
Would anyone mind testing this for me? I have uploaded the .exe's for both applications here:
TestShowWindow Download
All you have to do is download them and run TestApplication.exe then run TestShowWindow.exe. You will find that by changing TestApplication.exe to run as Administrator causes ShowWindow to no longer work.
Of course if you don't trust downloading my stuff you can always compile my code and test it on any target application in Windows that you are able to change compatability mode of.
P.S. I am not sure if it makes a difference but I am running Windows 8 Pro. 64-bit.
This is by design. It is the lesser known twin of UAC, called UIPI or User Interface Privilege Isolation. An un-elevated program cannot commandeer an elevated one. Given the capabilities of UI Automation, this is an obvious counter-measure to stop programs from hijacking the capabilities of an elevated process. A security violation called a shatter attack.
Workarounds are to provide a manifest with uiAccess = true for a program stored in c:\windows or c:\program files and provided with a certificate. And for the target program to call ChangeWindowMessageFilter to allow certain messages to be sent. In your case that ought to be WM_SHOWWINDOW.
If you don't mind the window acting like you minimized it to the taskbar; You can, generally, show and hide windows from elevated processes by posting WM_SYSCOMMAND with a wParam of SC_RESTORE or SC_MINIMIZE.

Finding the Child Window inside a Microsoft RemoteApp Programmatically

Background
I'm using SendKeys() to send keyboard commands to the active window, but I'm not having any luck finding the child window when the application is running through RemoteApp. It all works as expected when I run the application locally.
Microsoft RemoteApp allows users to connect to applications through the RDP protocol, but instead of showing the entire remote Virtual machine, it just shows the application window. To the end user, there is no difference between an application running under RemoteApp and it running on their desktop.
I've been using ManagedSpy to determine the class name of the .NET application window so that I can use the Win32 API function FindWindowEx to make one of the child windows active, and it works well. However, I'm having a problem when the application is running over RemoteApp.
I can still use the .NET Process.GetProcessesByName() to find the application, I just have to have it invoke mstsc.exe:
IntPtr hwndChild = IntPtr.Zero;
Process[] processess = Process.GetProcessesByName("mstsc");
IntPtr appHandle = IntPtr.Zero;
foreach (Process p in processess)
{
if ((p.MainWindowHandle != IntPtr.Zero))
{
appHandle = p.MainWindowHandle;
}
}
if (appHandle == IntPtr.Zero)
{
MessageBox.Show("Application is not Running.");
return;
}
However, I can't use FindWindowEx in the same way. This question revolves around that.
For the unmanaged code to tell me what windows mstsc.exe has active, I used Spy++, but for mstsc.exe it comes back with a different class name, called RAIL_WINDOW:
Here is the code I'm using to find the Child Window:
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
hwndChild = FindWindowEx(appHandle, IntPtr.Zero, "RAIL_WINDOW", "MyApplication (Remote)");
SetForegroundWindow(hwndChild);
Questions
I can use Spy++ to highlight the active child window in the RemoteApp version of the application, and I get RAIL_WINDOW, but I cannot seem to access this window programmatically. Given the code above, what am I missing to be able to do so?
Are there other ways of sending keyboard strokes to an application running over Remote App?
Knowing how Microsoft does things, I'll bet the "rail window" is nothing more than a dumb, local proxy that doesn't bother responding to what SendKeys is sending. I haven't looked, but I'll bet that ends up sending WM_CHAR messages, to which a dumb proxy probably wouldn't bother responding. Instead, try sending it WM_KEYUP and WM_KEYDOWN messages manually and see if that works, given that I expect it would transmit those and mouse clicks (and what not) rather than the translated versions.
What commands are you sending using SendKeys()?
It may be better to look for an alternative solution instead of using `SendKeys()'.
And you can probably take advantage of handling IMsTscAxEvents::OnRemoteWindowDisplayed event that gives you the proper window handle at the right time without calling FindWindowEx, etc.

Receive WM_COPYDATA struct in WPF or Console C# app

I am writing a C# application that needs to communicate with another application written in native C. So far I have figured out how to send messages from my C# app to the C app with the User32.dll SendMessage. However I am unable to figure out how to get the C# app to RECEIVE messages from the C app.
I have seen WinForms examples of overriding the WndProc method, but there is no WndProc method to override in a WPF or Console application. Surely it's possible to do in a Console application at least. Right?
You can do this in WPF using HwndSource.AddHook:
private HwndSource hwndSource;
void MyWindowClass_Loaded(object sender, RoutedEventArgs e)
{
hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Process your windows proc message here
}
Unfortunately, there is no real equivelent for a Console Application. Windows messages, by definition, are sent and received by a window handle (HWND), so they really are meant to be used with GUI applications.
There are many other, less odd, means of doing inter-process communication on Windows, however. I personally like using pipes - setting up named pipes works very well in both native and managed code, and is very efficient for communicating between the two programs.

Categories

Resources