I'm working on a kiosk style application where I need to control the shutdown/restart of the PC when the power button is pressed. Thanks to this post, I'm about 90% of the way there.
In control panel set the acpi power button press action to shutdown.
Listen for the WndProc message WM_QUERYENDSESSION
When received issue the completely undocumented:
[DllImport("user32.dll", SetLastError = true)]
static extern int CancelShutdown();
Return from the WndProc and bring up my own message box asking the user to Shutdown / Restart or Cancel, and respond to their action.
Everything works well if I do a start / shutdown from the task bar (I can issue theses as fast as I want). Everything also works well the first time I press the power button. On subsequent power button presses though I see a minute or so delay before I receive the WM_QUERYENDSESSION message.
Is there a setting or registry entry about how often windows will issue an ACPI event? I know it's not the hardware because under linux the same machine will fire the ACPI event as fast as I can press the button.
Thanks.
Calling in some favors at work, I was able to take this question directly to Microsoft support. On my third support engineer, I was essentially told this is not possible at an application level. It was his belief that calling the undocumented CancelShutdown() "confuses" the power manager or acpi driver which leads to the WM_QUERYENDSESSION message delay. Since the CancelShutdown() is undocumented, MS is not willing investigate further.
So, how do you hook power button presses? You need to write a device driver, specifically an ACPI Filter Driver. We are investigating this now.
I don't think it is possible unless you speak with your hardware manufacturer or hardwire the start-button so that it doesn't send a signal to the hardware which handles this.
You can only delay it but even that would not give you 100% guarantee I guess.
Windows 8.1 will (maybe) bring a Kiosk Mode. Maybe that is what you are looking for ;-)
Related
I have a C# .NET 2.0 application running on client kiosk machine (Windows XP) that occasionally puts up a window for user input. The other kiosk software seems to be interfering with it somehow because while it is running our window will not receive Mouse or Keyboard events despite it being the top window. When the other software is not running all works as expected. Does anyone have any insight as to what might be going on here?
Thanks
If in doubt - use Spy++ provided with Visual Studio to see what messages your window receives from the system.
If the other application blocks all input, it's not conforming to the Win32 API. That's why the low level hooks timeout was introduced in Vista and newer Win OS. Meaning a process would be kicked out of the low level hook chain, if it held onto a hook too long before calling CallNextHookEx() and not receive any low level hook messages anymore.
On Windows XP, there is no such limitation. A process can take as much time as they want to process a hooking message. The other program is either buggy, or evil. If it's essential that your application has input, then just close the other one programmatically or contact the author of it and explain the situation.
Take a look here
http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
Using global keyboard hook should do just fine and some sources are included as well. Also, some user seem to solve similar problem by using ManagedSpyLib:
https://stackoverflow.com/a/8829286/1284902
After some digging, it is possible that the other windows forms program is utilizing a low level keyboard hook similar to one found here http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx. After following a link in that article, I came across a summary of that code snippet
For a concrete example of this, consider the (buggy) code in Figure 4. Using a low-level keyboard windows hook, the code intercepts all WM_KEYDOWN messages sent to any window and prints out the corresponding key.
Source: http://msdn.microsoft.com/en-us/magazine/cc163606.aspx
I'm working on writing an application that straddles the line between C# and C/++ on Windows Mobile 6.1/6.5. We currently have a kiosk application running on our devices, and would like to add the ability to switch back and forth to a second kiosk application.
Our goal is to establish a global hot key that switches process windows (similar to the way that alt+tab works) whenever it is pressed. We already have both applications and I've written some code that switches the processes, but am having a rough time getting the global hot key portion of the project working.
From all of the reading that I've done, my understanding is that the best way to monitor global key presses is to link into the system message pump with the SetWindowsHookEx function in coredll.dll. Unfortunately, I've also read that this function isn't technically supported on the platform.
I also found some tutorials that suggested using a message map with the ON_WM_KEYUP/ON_WM_KEYDOWN macros in the MFC framework, but couldn't find any documentation specific to Windows Mobile. When I tried to use the documentation here, my device kept crashing.
Is there an accepted best practice for setting some kind of global key hook on the platform? If not, is there something that's at least technically supported?
Thanks in advance.
ReplyQuote
Why not use a RegisterHotKey call and use that to swap applications? IIRC the hardware buttons typically map to key codes starting at 0xC1 (193).
We actually ended up polling the GetAsyncKeyState function in coredll.dll on a separate thread. The thread monitors a specific key, and throws an event whenever it is pressed.
Because the event is executed on the key polling thread, you have to be sure to use a delegate to invoke its handler on the GUI thread when the event is thrown.
I would go for a keyboard hook, but only if RegisterHotKey didn't work for your particular scenario.
From all of the reading that I've done, my understanding is that the best way to monitor global key presses is to link into the system message pump with the SetWindowsHookEx function in coredll.dll. Unfortunately, I've also read that this function isn't technically supported on the platform.
Not technically supported, is correct in theory, but I've not seen a WM 6.5.* device that hasn't supported it in reality. Keyboard hooking is such an important feature of vertical market custom rugged WM device apps that it I think it just cannot be removed, for backwards compatibilty.
The enterprise side of the WM space is too important.
My app has an option to disable aero by calling DwmEnableComposition(0) before capturing a screen image. As you know, disabling aero makes the screen go black then return to normal afterwards. On different PCs this might take 2 to 3 seconds depending on how fast the system is.
Is there a better way of determining if aero has fully disabled before screen capture instead of Thread.Sleep()?
You should be able to do this using the related API function DwmIsCompositionEnabled. The other option might be to listen for the WM_DWMCOMPOSITIONCHANGED event.
Your form's Paint event will run. That doesn't mean all windows will be fully painted, but you can sleep less. Listening for the notification message by overriding WndProc() may work, not sure when it is sent. WM_DWMCOMPOSITIONCHANGED is message 0x31e. I suspect it will be sent too soon, all windows probably have to repaint themselves next. The only way to be sure is to enumerate the windows with EnumWindows and call UpdateWindow. Visit pinvoke.net for the P/Invoke declarations you'll need. Sleep() will work too but there's no way to guess an amount that's guaranteed to work everywhere.
Have you looked into DwmIsCompositionEnabled? This page also says Applications can listen for composition state changes by handling the WM_DWMCOMPOSITIONCHANGED notification.
Is there an easy way to get notified when user presses Power Off button on it's Windows Mobile device? Using C# of course.
Thanks!
When the power button is pressed, the power manager will send out a notification of a state change. You can request that the PM send you a notification by calling RequestPowerNotifications You have to send in a handle to a point-to-point messgae queue (managed version here) that will get the notification.
For thos who don't want to write all of the glue to make this work, all of this is already pre-done for you in the SDF's PowerManagement class.
Also be forewarned that just becasue you request the notification does not mean that your app will get the notification before the state change occurs. For example on pwer down it's pretty common that an app won't see the notification, and almost certain that even if you do see it you won't have time to execute anything before suspend actually occurs. Typically your handler will run when the device resumes (followed by any handler for the resume state).
The power manager doesn't wait for you, it simply broadcasts a message. You cannot use this to run code before a shutdown.
I just place CreateMsgQueue() into the XIP RPM binaries, without need for source code or OEM help. you need to use a hex editor and a few tools from XDA forums.
<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function CreateMsgQueue(ByVal lpszName As String, ByVal lpOptions As MsgQueueOptions) As IntPtr
End Function
also you should just create a simple driver for blocking the power down event, your driver is allowed to hold up the power down process in the PowerDown device Event. that way you get a guaranteed event that you can set the flag and stop your background running process, and store any variables, and then restore them on ther PowerUp event, which is also a standard evc++ event for winCE device driver. Pretty simple really. there is 100s of demo source code on the internet for this, I've seen it on 100s of sites.
Unfortunately, on the Windows CE 6 device i am using, CreateMsgQueue does not exist in CoreDll. Any other suggestions?
The only thing i can think of is continually checking Environment.TickCount against the device's real time clock. If time has moved forward but not the tick count, then presumably the device was sleeping.
Dont like this solution because it will get tricked if the time jumps due to a failure in the device's real time clock
I want to send an Application Key Presses, To Automate some stuff that has to be done repeatedly and So I don't always have to cramp my fingers.
In C#, it's nice to use SendKeys.Send(), but this won't work because the Application doesn't take Windows Messages. SendKeys.SendWait() does nothing at all.
How would I STILL Simulate the Keyboard events?
Come To Think of It, I was going to use some P/Invoke to simulate Mouse Events too, but If it takes no messages, How Can I get around that?
EDIT - I can use mouse and keyboard to interact with the program, I just cannot manipulate it with Windows Messages sent from my own Code.
Have you tried AutoIt?
Is it a console app? If so, maybe you should be SendKeys'ing to the command shell instance it is running in.