CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 2 FirstFirst 12
Results 16 to 20 of 20
  1. #16
    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
    Thanks. It's a nice article. But unfortunately like one of the commenters noted there:
    See this post for a practical sample.
    Best regards,
    Igor

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

    Re: How to refresh logon screensaver parameter changes?

    @VictorN: LocalSystemSID is indeed S-1-5-18, which is the user SID that my local service is running under. I need to run my test process in a user account with SID S-1-5-19.

    @Igor Vartanov: It's an interesting idea. But you see, in your example you had notepad.exe already running in one user session, so you could reuse it's token. In my case I don't have a process to use for that approach...

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

    Re: How to refresh logon screensaver parameter changes?

    Quote Originally Posted by Igor Vartanov View Post
    See this post for a practical sample.
    Igor, you gave me an idea. I logged off all users and checked all running processes. As it shows here:

    Name:  1.jpg
Views: 2283
Size:  75.4 KB

    Windows Logon is the only interactive process, that is LogonUI.exe:

    Name:  2.jpg
Views: 2256
Size:  96.8 KB

    Shall I try to get its token & run my process with it using your approach?

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

    Re: How to refresh logon screensaver parameter changes?

    I think the best candidate for the case of real interactive user is explorer.exe, or whatever exe is registered as a shell. Or you can adopt the method from the article (afraid it's Vista/7/8 only).

    In case there is no interactive session at all, the suggested SystemParametersInfo API won't work I guess. Besides, I'm not sure whether screensaver timeout matters in this case.
    Best regards,
    Igor

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

    Re: How to refresh logon screensaver parameter changes?

    Quote Originally Posted by Igor Vartanov View Post
    See this post for a practical sample.
    Igor Vartanov, I'd like to thank you for suggesting your solution. Using it I was able to resolve this issue!

    Here's how:

    1. Use Igor's code from here and the following method to obtain the user token for the "LogonUI.exe" process:

    Code:
    HANDLE hToken = NULL;
    DWORD pid = GetProcessTokenByName(_T("LogonUI.exe"), &hToken);
    His GetProcessTokenByName is a bit an overkill for my needs, so you can strip out anything past the 'hToken' part. Or, you can use WTSEnumerateProcesses API to retrieve process names in a faster fashion and use hProc=OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_ID); and OpenProcessToken(hProc, TOKEN_ALL_ACCESS, &hToken) to obtain the desired token for a matched process (by its name.)

    One correction I want to point out for the Igor's method. Do not use CString().CompareNoCase() and stick with CompareString() API instead. It handles international case-insensitive comparison in a correct way, which CString does not.

    Also you may want to consider checking that there's no interactive users logged on to the console. For that use WTSEnumerateSessions() API and then call WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session_ID, WTSUserName, , ); for each session returned and check that the obtained user name has length 0. This will mean that the user session is not interactive. Otherwise, stop and don't continue.

    2. Once you have a token use it in a call to CreateProcessAsUser() to run a small console exe process (see item 3.) You can use Igor's ExecThread method, or something similar to this:

    Code:
    //INFO: Error handling is omitted
    // hToken = obtained from the 'LogonUI.exe' process using the method described above
    
    HANDLE hToken2;
    ::DuplicateHandle(::GetCurrentProcess(), hUserToken, ::GetCurrentProcess(), &hToken2, 0, FALSE, DUPLICATE_SAME_ACCESS);
    
    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' to be 1000 for success, otherwise an error
    }
    
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    
    DestroyEnvironmentBlock(pEnvBlock);
    
    //Close both tokens
    CloseHandle(hToken2);
    CloseHandle(hToken);
    3. The console exe process should simply read the value from the 'HKEY_USERS\.DEFAULT\Control Panel\Desktop\ScreenSaveTimeOut' registry and apply it as such:

    Code:
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
    	int nExitCode = 0;
    
    	int nValueForTimeout = readIntFromRegistry_I_will_let_you_do_it(HKEY_USERS, L".DEFAULT\\Control Panel\\Desktop", L"ScreenSaveTimeOut");
    
    	if(SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, nValueForTimeout, 0, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE))
    	{
    		//Success
    		nExitCode = 1000;
    	}
    	else
    	{
    		//Error
    		nExitCode = 0xdead;
    	}
    
    	return nExitCode;
    }
    Important thing is to create this console exe as a simple Win32 process, and statically link it to the CRT (with /MT switch.) This will make it depend on as few dlls as possible!

    4. And the last step is to check the return code 'dwExitCode' from the method in item 2 to be equal to '1000'. If it is, then we're in luck.

    And voila, it works! I tested it on Windows XP SP3, Vista, 7, 8. (I don't have Windows 8.1, but I'm assuming it'd work as well.)

    So thanks everyone who pitched it!

Page 2 of 2 FirstFirst 12

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