To read/set a user screensaver on Windows, do I need to use system registry or SystemParametersInfo API? - c++

There seems to be two methods of setting and getting a user screensaver parameters on a Windows platform:
1: Via the SystemParametersInfo() API:
//To read
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &bScreensaverAcrtive, NULL);
SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &nScreensaverTimeout, NULL);
//No API to get the screensaver file used
//To set
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, bScreensaverAcrtive, NULL);
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, nScreensaverTimeout, NULL);
//No API to change the screensaver file
2: Through the system registry keys:
HKCU\Control Panel\Desktop - "ScreenSaveActive"
HKCU\Control Panel\Desktop - "ScreenSaveTimeOut"
HKCU\Control Panel\Desktop - "SCRNSAVE.EXE"
But since there're two competing methods that seem to do the same, what is the recommended way to use?
PS. I highly favor method #2 (or writing directly into registry) due to the following reasons:
A. If you read the explanation of a bug in the SPI_GETSCREENSAVEACTIVE flag, you'll see that MS themselves recommend to use registry.
B. If you read the documentation for the SPI_SETSCREENSAVEACTIVE and SPI_SETSCREENSAVETIMEOUT flags, there's this mystical line that says, "*If the machine has entered power saving mode or system lock state, an ERROR_OPERATION_IN_PROGRESS exception occurs.*" I first ignored this situation until it actually started happening on my test installation of Windows 8. This is the most asinine error, I should tell you. There's absolutely no graceful way of interpreting what it means or do any workaround (except, writing directly into the registry.)

Use the API. Asking that is like asking if you should wait for the traffic light to turn green before crossing the road. I won't call the cops if I see you crossing at red, but if you ask me, I'll tell you you have to wait. And you are the one taking the risk of bad things happening.
The API is documented, the registry locations are not. Microsoft is in no obligation to preserve the registry locations or their functionality.
The SPI_GETSCREENSAVEACTIVE flag affects Windows 2000. If you support Windows 2000 as a target platform, I would apply the registry read to that version only (OSVERSIONINFO.dwMajor=5, .dwMinor=0)
ERROR_OPERATION_IN_PROGRESS I'd try to figure out under what circumstances this happens (e.g. screensaver already active, or system about to enter a power saving state).
Generally, I'd find it questionable if activating / deactivating the screensaver is not at least related to a user action, in which case the system should be ready to accept a change.
What are you trying to achieve? Why do you need to modify screensaver activity? Maybe there's some better method to achieve your goal

Use the API. The registry format changes often.
As for the power state changes, screen savers are really a 20th century feature. Laptops turn off the screen entirely, for obvious reasons. In that power saving state SPI_SETSCREENSAVEACTIVE obviously should fail. Not a lot of interpreting to do.
So, check for GUID_VIDEO_POWERDOWN_TIMEOUT first.
edit
I just realized that Group Policy screensavers are also unlikely to be in the registry, and certainly would override HKCU. Not a real issue for Windows 2000, of course, but today the API method would be even more advisable. Of course, do realize that this is just another reason why SPI_SETSCREENSAVEACTIVE may return an error. Still an improvement over the registry approach, which fails silently in the presence of Group Policy.

"To set" above is incorrect. It should be:
//To set
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, bScreensaverAcrtive, NULL, NULL);
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, nScreensaverTimeout, NULL, NULL);

Related

Is there a way in Qt to prohibit the computer from going to sleep?

I am writing a Qt application that does some heavy computations, but on a Mac (potentially also on Windows but I currently have no way of checking this), the execution ceases as soon as the computer goes into sleeping mode.
I would like a way to continue the execution even when the screen goes to screensaver or on blank. Obviously you can ask the user to change his/her energy settings, but that's far from an ideal solution. Is there a proper way of doing this?
After a thorough search through the Qt 5.2 API, it seems that Qt doesn't offer any functionality to change the energy settings (so neither for Mac, nor any other operating system). I haven't found any indication that it's on their road map either.
A possible solution for Mac OSX using Apple's Objective-C API can be found here (thanks, #Kuba).
On Windows, power settings can be dealt with using the SetThreadExecutionState function (see this question, C#).
There are two aspects of this:
Forced Sleep If the user intends the system to sleep, and you prevent it, your users may well curse you. Forced sleep is also part of energy and thermal management, and is vital to prevent data loss and avoid destruction of hardware and mitigate possible fire risk.
When I close the lid of my laptop, it better go to sleep and if I find an app that tries to circumvent it, it better be free or else I'm calling my credit card company for a chargeback. It's that simple, and I hope it's easy to understand why it would be so.
Idle Sleep What you want to do is not to prevent the system from going to sleep at all, but to only disable the idle sleep.
Disabling of idle sleep is covered in this answer.
If you want to avoid the Objective-C API, there's a C-based API underlying it. You can call IOPMAssertionCreateWithDescription() with an assertion type of kIOPMAssertionTypePreventUserIdleSystemSleep. That gives you an assertion ID reference. You cancel the assertion using IOPMAssertionRelease() to match the create call and any IOPMAssertionRetain() calls you may have made.
CFURLRef bundleURL = CFBundleCopyBundleURL(CFBundleGetMainBundle());
CFStringRef bundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
CFRelease(bundleURL);
IOPMAssertionID assertion;
IOReturn result = IOPMAssertionCreateWithDescription(kIOPMAssertionTypePreventUserIdleSystemSleep,
CFSTR("A name which makes sense for your app"),
CFSTR("Some details"), CFSTR("A human-readable reason"),
bundlePath, 0, NULL, &assertion);
CFRelease(bundlePath);
if (result != kIOReturnSuccess)
/* handle error */;
// ... do computation ...
IOPMAssertionRelease(assertion);
There seems to be a command line utility "caffeinate" that prevents system from going to sleep. Here is an example of using this utility within QT framework:
https://github.com/githublucas420/KDE/blob/4436536a6a2beb1631f89968dfab566963dae073/plugins/screensaver-inhibit/screensaverinhibitplugin-macos.cpp

Trying to hook to MessageBeep system API

I've been asked by a client to solve the following pesky issue. They have a custom software that has a tendency of displaying message boxes "left and right" without any apparent reason. For instance, the software itself is an accounting program, and when they take a customer's payment, the message box may be displayed about 3 or 4 times in a row. Each message box plays Windows default sound. Unfortunately the way this software was programmed, the type of sounds it plays is completely wrong. For instance, it may display a warning message box and play the warning system sound when the message itself is just an information. All this is quite annoying for the staff who uses the software.
I tried to contact the vendor who distributes the software, but I hit a deadend with them. So now I am looking for ways to mitigate this issue.
My easiest solution was to suggest to mute the speakers, but unfortunately, they require sound to be present to be able to hear incoming emails, and most importantly, be able to play voice mail from them later. So my solution was to somehow mute message box sounds just for a single process.
From my experience, I know that there're two APIs that may be producing these sounds: MessageBeep and an older Beep.
I also found this article that explains how to use AppInit_DLLs to hook to system APIs. It works great, except that both of the APIs that I need to hook to come from User32.dll and not from kernel32.dll like the author suggests.
There's also this post in the questions section that kinda gives approximate steps to hooking to an API from User32.dll, but when I tried to implement them, there's not enough information (for my knowledge to do it.)
So my questions is, does anyone know how to hook to an API in the User32.dll module?
EDIT: PS. Forgot to mention. This software is installed on Windows 7 Professional, with UAC disabled -- because it is not compatible with UAC :)
As an alternative you can patch you application. Find calls to MessageBeep and overwrite them with nop.
This is the hard way of doing it: if your app is supposed to be running as Administrator on a pre-Vista Windows, you could get the address of the API via ::GetProcAddress(), give yourself privileges to write to its memory page, and overwrite the beginning of the API's code with a "jmp" assembly instruction jumping into the address of your override function. Make sure your overwrite function takes the same arguments and is declared as __cdecl.
Expanded answer follows.
The "standard" technique for API hooking involves the following steps:
1: Inject your DLL into the target process
This is usually accomplished by first allocating memory in the target process for a string containing the name/path of your DLL (e.g. "MyHook.dll"), and then creating a remote thread in the target process whose entry point is kernel32::LoadLibraryA() passing the name of your DLL as argument. This page has an implementation of this technique. You'll have to wrestle a bit with privileges, but it's guaranteed to work 100% on Windows XP and earlier OSes. I'm not sure about Vista and post-Vista, Address Space Layout Randomization might make this tricky.
2. Hook the API
Once your DLL is loaded into the target process, its DllMain() will be executed automatically, giving you a chance to run anything you want in the target process. From within your DllMain, use ::LoadLibraryA() to get the HMODULE of the library containing the API you want to hook (e.g. "user32.dll") and pass it to ::GetProcAddress() together with the name of the API you want to hook (e.g. "MessageBeep") to get the address of the API itself. Eventaully give yourself privileges to write to that address' page, and overwrite the beginning of the API with a jmp instruction jumping into your detour (i.e. into your "version" of the API to hook). Note that your detour needs to have the same signature and calling convention (usually _cdecl) as the API you want to hook, or else monsters will be awakened.
As described here, this technique is somewhat destructive: you can't call back into the original API from the detour, as the original API has been modified to jump into yours and you'll end up with a very tight and nice infinite loop. There are many different techniques that would allow you to preserve and/or call back into the original API, one of which is hooking the ...A() versions of the API and then calling into the ...W() versions (most if not all of the ...A() Windows API's convert ASCII strings into UNICODE strings and end up calling into their ...W() counterparts).
No need to spend time on a custom program to do this.
You can mute a particular application when it's running, and that setting will be remembered the next time you open the application. See https://superuser.com/questions/37281/how-to-disable-sound-of-certain-applications.
There's also the Windows Sound Sentry that will turn off most system sounds, although I'm not aware of any per-application settings for Sound Sentry.
You can use Deviare API hook and solve the hook in a couple of C# lines. Or you can use EasyHook that is a bit more difficult and less stable.

Installation of power management API hooks on Windows OS using C++

Let me preface this by saying that my original goal was to determine the power state that a Windows OS is entering into before the actual power state kicks in. I asked a similar question on another thread for which I received a bunch of smirks regarding why I need to know this. So without going into lengthy explanation regarding why I need this, let me briefly say that the hardware I have connected to a PC will need this information for its own power management.
At this point I am also trying to avoid writing a device driver so instead I want to try to find a solution from a user mode/local service code.
OK, now back to the matter at hand. Since the Windows OS provides just the basic power notification that, for instance, won't let me differentiate between rebooting vs. shut-down, or sleep vs. hibernation, I thought to implement a global hook on Windows APIs that initiate these power states (which are SetSuspendState for sleep/hibernation and InitiateSystemShutdown for rebooting/shut-down.) I also found this article that explains how to implement the global API hook with C++/WinAPIs.
So being able to intercept a command for a power event before it happens the idea is to write into the system registry the type of the power event (see POWER_ACTION and SYSTEM_POWER_STATE below) and read it from the user-mode/local service code after it receives the WM_POWERBROADCAST notification.
I've never done global API hooking so before I jump into coding it, I'm asking for advice of professionals on this site -- what do you think, can this work?
Also a couple of technical questions about APIs themselves:
1: I did some research and it seems like most higher level power APIs on a kernel level boil down to either NtInitiatePowerAction or ZwInitiatePowerAction exported from Ntdll.dll. Both seem to do the same, but the question is, which one should I hook to?
2: There's a lack of documentation from Microsoft on those kernel level APIs. The only stuff I was able to find is this. Does anyone have any info to add to it?
NTSYSAPI
NTSTATUS
NTAPI
NtInitiatePowerAction(
IN POWER_ACTION SystemAction,
IN SYSTEM_POWER_STATE MinSystemState,
IN ULONG Flags,
IN BOOLEAN Asynchronous
);
typedef enum _POWER_ACTION {
PowerActionNone,
PowerActionReserved,
PowerActionSleep,
PowerActionHibernate,
PowerActionShutdown,
PowerActionShutdownReset,
PowerActionShutdownOff
} POWER_ACTION, *PPOWER_ACTION;
typedef enum _SYSTEM_POWER_STATE {
PowerSystemUnspecified = 0,
PowerSystemWorking,
PowerSystemSleeping1,
PowerSystemSleeping2,
PowerSystemSleeping3,
PowerSystemHibernate,
PowerSystemShutdown
} SYSTEM_POWER_STATE, *PSYSTEM_POWER_STATE;
//Flags seem to be the these ones
POWER_ACTION_QUERY_ALLOWED
POWER_ACTION_UI_ALLOWED
POWER_ACTION_OVERRIDE_APPS
POWER_ACTION_LOCK_CONSOLE
POWER_ACTION_DISABLE_WAKES
POWER_ACTION_CRITICAL
Actual values for flags above can be these here.
3: I need this to work under Windows XP SP3 and later OS. It seems like all this stuff is supported since XP, but my concern is those kernel level APIs that don't seem to be mentioned in the official MSDN documentation.
So anyway, I'd appreciate to hear any insight on this?

How to find out if hibernation is available for a Windows user (with C++)

I know that one can call the following API to hibernate the system:
SetSuspendState(TRUE, FALSE, FALSE);
But is there any way to find out if "real" hibernation is available for the current Windows user?
Here's what I mean:
If an admin calls:
powercfg.exe /hibernate off
the API above will put system into a Sleep mode. So how do you know (from a C++ program) that this will happen instead of hibernation?
I'm not sure if there's a group policy that can prohibit a user from hibernating a computer connected to an Active Directory?
Edit I am aware of the (dated) IsPwrHibernateAllowed API. I find that it doesn't work: it still returns the same result even if powercfg.exe /hibernate off was called. Am I doing something wrong there? Can someone explain why IsPwrHibernateAllowed doesn't work for me?
Take a look at SYSTEM_POWER_CAPABILITIES structure that can be obtained with CallNtPowerInformation. Specifically, look at HiberFilePresent field.

Grabbing events on specific keys with X11 on Linux

I'm writing a program in C++ to implement the keyboard backlight feature from OS X on MacBook Pro's running a Linux distro. So far, it turns the backlight on, on boot and if no keyboard and mouse events are registered for 20 seconds, it will turn it back off, and of course turn it on yet again when an event is registered. Next thing I need the program to do, is to capture keypresses on the keyboard-backlight-up/down keys, but I'm not sure how to approach this.
I am currently using XScreenSaverQueryInfo to get the idle time of keyboard and mouse events, so a method using X11 API would be okay. I have done a lot of googling but havent found a way that I felt sure about going with. The problem I'm seeing with lots of the methods I found, is that they use keycode to identify the key, but I dont think that would be a viable solution since the program should work for any keyboard-layout available.
Any idea of a method and API I should go with? What would work the best?
Regards,
The normal way to do this is with XGrabKey(). It uses keycodes, but you wouldn't hardcode the keycode, you'd get it with XKeysymToKeycode(). To be more correct you'd also want to redo the grab when you get a MappingNotify (XMappingEvent). (Note, MappingNotify, not MapNotify.) If there isn't a keysym for these keys - there probably isn't on old X versions, but hopefully newer X.org versions have one - then you just have to hardwire the keycode. Which won't be very robust or portable but probably works for everyone on Linux with the same hardware model.
Be prepared that key grabs are global, so if you try to XGrabKey() and something else has already grabbed that key, you'll get an X error - by default that exits the program. Another quirk of XGrabKey() is that it grabs the key with a precise modifier set. For example, to handle both with and without NumLock, you need to grab twice. See Global Hotkey with X11/Xlib
In a normal Linux setup (if you wanted to get a feature like this into upstream projects), the desktop environments don't want lots of separate apps fighting over the key grabs and getting errors. So there will be some central coordination points, such as the window manager or a special daemon might do all the keybindings and forward commands to other processes as needed. So you would probably want to look at patching the same upstream code that handles other special keys like this, if you were trying to get your feature integrated into distributions by default.
Another thing to be aware of is the Xkb API, which is a lot more complicated. There is some brain-bending way to grab keys with Xkb but I don't know of any advantage to going that route.
If you haven't done that yet, familiarize yourself with xev. Start it, give it the focus, and press the keys, to see what's happening.