CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 20
  1. #1
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    894

    [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.

  2. #2
    Join Date
    Jun 2002
    Location
    Stockholm, Sweden
    Posts
    1,641

    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

  3. #3
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    894

    Re: How to refresh logon screensaver parameter changes?

    Quote Originally Posted by zerver View Post
    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.

  4. #4
    Join Date
    Jun 2002
    Location
    Stockholm, Sweden
    Posts
    1,641

    Re: How to refresh logon screensaver parameter changes?

    Did you try whether calling UpdatePerUserSystemParameters in user32.dll has any effect?

    http://www.codeproject.com/Questions...-not-Reflected
    http://www.cplusplus.com/forum/windows/77727/
    Nobody cares how it works as long as it works

  5. #5
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    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)

  6. #6
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    894

    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.

  7. #7
    Join Date
    Jun 2002
    Location
    Stockholm, Sweden
    Posts
    1,641

    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

  8. #8
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    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.

  9. #9
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: How to refresh logon screensaver parameter changes?

    Quote Originally Posted by OReubens View Post
    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)

  10. #10
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: How to refresh logon screensaver parameter changes?

    Quote Originally Posted by dc_2000 View Post
    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

  11. #11
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    894

    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???

  12. #12
    Join Date
    Jun 2002
    Location
    Stockholm, Sweden
    Posts
    1,641

    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

  13. #13
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    894

    Re: How to refresh logon screensaver parameter changes?

    Quote Originally Posted by zerver View Post
    Hi dc2000,

    I think if you read this you will find the soluition:
    http://blogs.msdn.com/b/winsdk/archi...and-later.aspx
    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.

  14. #14
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    894

    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

  15. #15
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,395

    Re: How to refresh logon screensaver parameter changes?

    The LocalSystemSID is S-1-5-18
    See http://msdn.microsoft.com/en-us/library/cc980032.aspx
    Victor Nijegorodov

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured