-
January 13th, 2014, 01:59 AM
#1
[RESOLVED] How to refresh logon screensaver parameter changes?
I have a Windows service that may change the timeout of the logon screensaver in Windows (as described here.) To do that I change the following registry key to the timeout in seconds:
Code:
HKEY_USERS\.DEFAULT\Control Panel\Desktop\ScreenSaveTimeOut
The issue is that how do I make OS "read" or refresh the actual screensaver timeout after a change in the registry key above?
My practice shows that it is refreshed (for sure) only when I reboot the system, but in my case I need it to be applied without the reboot.
-
January 13th, 2014, 04:06 AM
#2
Re: How to refresh logon screensaver parameter changes?
I think you are doing it the wrong way. Instead use SystemParametersInfo with parameter SPI_SETSCREENSAVETIMEOUT (seconds).
Nobody cares how it works as long as it works
-
January 13th, 2014, 04:08 AM
#3
Re: How to refresh logon screensaver parameter changes?
Originally Posted by zerver
I think you are doing it the wrong way. Instead use SystemParametersInfo with parameter SPI_SETSCREENSAVETIMEOUT (seconds).
If I call SystemParametersInfo from a service it returns error 1459, or ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION.
-
January 13th, 2014, 05:27 AM
#4
Re: How to refresh logon screensaver parameter changes?
Nobody cares how it works as long as it works
-
January 13th, 2014, 05:39 AM
#5
Re: How to refresh logon screensaver parameter changes?
Note that UpdatePerUserSystemParameters is an undocumented function and therefore could change between OS releases and is not supported by Microsoft.
SystemParametersInfo() gets/sets the value for the current user and the OP is trying to change the value for the .default user (ie the user when no user is logged on).
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
January 13th, 2014, 05:47 AM
#6
Re: How to refresh logon screensaver parameter changes?
Thanks, fellas.
@zerver: I tried to call UpdatePerUserSystemParameters defined as such in User32.dll module:
Code:
BOOL (WINAPI *pfnUpdatePerUserSystemParameters)(DWORD, BOOL);
//Load it and then
if(pfnUpdatePerUserSystemParameters)
{
BOOL bResult = pfnUpdatePerUserSystemParameters(NULL, 1);
}
but it kept crashing my process, and I can't seem to find which parameters I'm supposed to call it with.
@2kaud: Yes, SystemParametersInfo API unfortunately is useless for my case. If I was calling it from the user-mode process, I'd definitely go with it.
The only solution that I was able to come across is to kill LogonUI.exe, which doesn't seem like the best way to go. Nonetheless, I tried it, but so far it didn't yield any results. The screensaver timeout remains unchanged until I reboot the system.
-
January 13th, 2014, 08:08 AM
#7
Re: How to refresh logon screensaver parameter changes?
If you look at the sample I sent, it appears you should call UpdatePerUserSystemParameters(NULL), or possibly without any parameters at all.
You could also try to call system("path to windows folder\\System32\\RUNDLL32.EXE user32.dll, UpdatePerUserSystemParameters");
I tried the RUNDLL thing on my w7 x64 system and it does not crash.
Nobody cares how it works as long as it works
-
January 13th, 2014, 08:53 AM
#8
Re: How to refresh logon screensaver parameter changes?
you need to change your service to be an interactive service (set the checkbox "Allow service to interact with desktop").
Doing so will however have consequences, so be sure to read up on what exactly this does.
Then use SystemParametersInfo().
Typically speaking, a noninteractive service is not allowed to make any direct changes to the user experience, which is why the screen saver delay change isn't doing anything for a non-interactive service until reboot.
-
January 13th, 2014, 09:18 AM
#9
Re: How to refresh logon screensaver parameter changes?
Originally Posted by OReubens
you need to change your service to be an interactive service (set the checkbox "Allow service to interact with desktop").
Doing so will however have consequences, so be sure to read up on what exactly this does.
Then use SystemParametersInfo().
Typically speaking, a noninteractive service is not allowed to make any direct changes to the user experience, which is why the screen saver delay change isn't doing anything for a non-interactive service until reboot.
I'm not convinced that using SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT) even if the service is changed to be interactive will accomplish what is required as this will change the parameter for the current user and it is the parameters for .DEFAULT user that are required to be changed.
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
January 14th, 2014, 01:58 AM
#10
Re: How to refresh logon screensaver parameter changes?
Originally Posted by dc_2000
Yes, SystemParametersInfo API unfortunately is useless for my case. If I was calling it from the user-mode process, I'd definitely go with it.
The only solution that I was able to come across is to kill LogonUI.exe, which doesn't seem like the best way to go.
So it seems that SystemParametersInfo called in user-mode is the very only solution you are to put up with.
What way you do it, thread injection, or specialized exe, or surrogate process running your dll, or whatever else, it's up to you.
Best regards,
Igor
-
January 14th, 2014, 04:36 AM
#11
Re: How to refresh logon screensaver parameter changes?
First off, thank you fellas for sticking with this issue!
@zerver: I'm not sure what to think about that UpdatePerUserSystemParameters() API. I tried calling it in a seemingly any possible combination and it failed in all. The only "promising" result was when I called it without any parameters, it returned control back to my function, although still did some "damage" to the stack (one of my variables had garbage in it afterwards and then the host function later crashed) but it also set GetLastError to ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION, which tells me that it probably acts analogous to SystemParametersInfo().
As for calling it via RUNDLL32.EXE... I'm not sure I want to go this route. I'd be ashamed to show this code to any fellow-C/C++ developer... It's like coding in JScript or Visual Basic, ya know.
@OReubens: I tried setting my service as an interactive (in despite of ample warnings not to do it if it's intended to run on the OS later than Windows XP.) Nonetheless it ran fine, and SystemParametersInfo() succeeded, but ... it didn't do any changes to my actual parameters. The logon screensaver timeout was not changed. My guess is that my service was running in a totally different desktop (or session.)
@2kaud: Good point! .DEFAULT is not the user account that any service will run in. So I did a small test. I put a logging function into my logon screensaver to see what user account and SID it was running under and I got this:
Code:
user=LOCAL SERVICE
domain=MyComputersDomain
sid=S-1-5-19
If you check the SID, it turns out that the logon screensaver is running under "LOCAL_SERVICE" account.
@Igor Vartanov: I thought your suggestion was my last-ditch attempt to make it work. Before doing any dll-injection (apart from not even knowing, what and where to inject), having the user account above I decided to simply run my test user process from my service under the LOCAL_SERVICE credentials and try to see if that may fix the issue.
So I came up with the following code to call my test user process from my service:
(Just a pseudo-code to eliminate the full-size clunker that it is)
Code:
//INFO: Error handling is omitted
HANDLE hToken;
LogonUser(L"LOCAL SERVICE", L"NT AUTHORITY", NULL, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &hToken);
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);
LPVOID pEnvBlock;
CreateEnvironmentBlock(&pEnvBlock, hToken2, FALSE);
STARTUPINFO si = {0};
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = _T("winsta0\\default");
PROCESS_INFORMATION pi = {0};
ImpersonateLoggedOnUser(hToken2);
bResult = CreateProcessAsUser(
hToken2, // client's access token
pStrExeFilePath, // file to execute
pBuffCmdLine[0] != 0 ? pBuffCmdLine : NULL, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, // creation flags
pEnvBlock, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
RevertToSelf();
DWORD dwResWait = ::WaitForSingleObject(pi.hProcess, 5 * 1000);
if(dwResWait == WAIT_OBJECT_0)
{
//Get return code with results from my test exe
DWORD dwExitCode;
GetExitCodeProcess(pi.hProcess, &dwExitCode);
//Analyze the 'dwExitCode'
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
DestroyEnvironmentBlock(pEnvBlock);
CloseHandle(hToken2);
CloseHandle(hToken);
And the test exe is simply a console application, statically linked to the CRT (/MT) to do this:
Code:
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
int nExitCode = 0;
if(SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 15, 0, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE))
{
//Success
nExitCode = 1000;
}
else
{
//Error
nExitCode = 0xdead;
}
return nExitCode;
}
So when the above construct runs, I get to the point when CreateProcessAsUser() succeeds, and returns the process handle but then GetExitCodeProcess() returns exit code `0xC0000142`, which is STATUS_DLL_INIT_FAILED, that means that my small test exe failed to initialize.
I ran it through Dependency Walker and all I have it linked to is: kernel32.dll and user32.dll.
From what I understand kernel32 is present all the time, and user32 is needed to actually run SystemParametersInfo.
So at this point I'm almost ready to throw in the towel. Unless you have any other ideas how to make it work???
-
January 14th, 2014, 10:45 AM
#12
Re: How to refresh logon screensaver parameter changes?
Hi dc2000,
I think if you read this you will find the soluition:
http://blogs.msdn.com/b/winsdk/archi...and-later.aspx
Nobody cares how it works as long as it works
-
January 14th, 2014, 12:57 PM
#13
Re: How to refresh logon screensaver parameter changes?
Originally Posted by zerver
Thanks. It's a nice article. But unfortunately like one of the commenters noted there:
This is a very good article.
But only theorie.
I'll play around with CreateProcessWithLogonW, CreateProcessWithTokenW, and ImpersonateLoggedOnUser to see if maybe they can fix the error I get from my small test exe.
-
January 15th, 2014, 12:06 AM
#14
Re: How to refresh logon screensaver parameter changes?
A short update. I can't seem to find a way how to run my test process in the following context from the LocalSystem service. Any idea how to do it, guys?
Code:
LOCAL SERVICE
sid=S-1-5-19
-
January 15th, 2014, 02:24 AM
#15
Re: How to refresh logon screensaver parameter changes?
Victor Nijegorodov
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|