How to logoff a user when the workstation is locked?
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10

Thread: How to logoff a user when the workstation is locked?

  1. #1
    Join Date
    Nov 2003
    Location
    Portland, OR
    Posts
    827

    How to logoff a user when the workstation is locked?

    I wrote a Windows application that comes with two modules: service and user-mode exes. The service implements its own scheduler and may log-off a user at a predefined time. For that I was using the following call that is triggered from my user-mode module exe in a logged-on user session that has to be logged off:

    Code:
    BOOL result = ExitWindowsEx(EWX_LOGOFF, reason);
    This works fine, except of the situation when a user's account is locked. In that case that API doesn't seem to do anything at all even through I get 1 returned from it.

    So I was curious, is there any other way to log off a user when their account is locked? (One condition I have in this case is that if that user had any unsaved documents then the log-off should not be forced.)

  2. #2
    Join Date
    Dec 2012
    Location
    England
    Posts
    2,308

    Re: How to logoff a user when the workstation is locked?

    As far as I am aware, there is no way for one program to know if other programs have unsaved open files (although you can find out which files are open). It is up to the individual programs what to do when they receive WM_CLOSE, WM_QUERYENDSESSION etc.

    Re forcing a logoff when a user's account is locked. See http://www.vistaheads.com/forums/mic...on-locked.html and others. They basically say you can't via a program.
    All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.

  3. #3
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    11,217

    Re: How to logoff a user when the workstation is locked?

    Years ago, I solved a similar problem within a distributed test framework. We automatically reimaged test machines and ran tests on 80 lab machines. Each machine had a test agent client that would check if errors appeared, restart the machine, reimage and so on. The approach that I took was to track initial processes on startup (and flag these as base processes) and then while running tests, I would update the process list every two seconds. What is applicable here is how I would close down these processes in the event of a failure. What I did was to attempt to 'politely' close the process using WM_QUERYENDSESSION (as 2kaud mentioned). In order to do this, you need to retrieve the top level window of each process and sendmessagetimeout the message to it. That will tell you if you the process can be shutdown (or if the user can be logged off, in your case). For shutting the system down, I preferred to use InitiateSystemShutdown over ExitWindowsEx, because back then, ExitWindowsEx wasn't as reliable.

    Here is the close process code for an individual process:

    Code:
    //+-----------------------------------------------------------------------
    //	Public Method:  RemoveProcess
    //
    //	Purpose:		Attempts to 'politely' tell the process to
    //                  terminate itself.  If process still exists
    //                  after gentle prodding, use TerminateProcess
    //                  to remove the process.  
    //
    //	Restrictions:	none
    //
    //	Parameters:		void
    //
    //	Return:			void
    //------------------------------------------------------------------------
    void CProcItem::RemoveProcess()
    {
        BOOL bDisplayError  = FALSE;
        HANDLE hProcess     = NULL;
        DWORD dwExitCode    = 0;
        DWORD dwResult      = 0;
    
        // Don't want to kill if base process
        if( m_bIsBaseProcess )
        {
            return;
        }
    
        if((hProcess = OpenProcess(PROCESS_ALL_ACCESS | SYNCHRONIZE,
                                    FALSE, 
                                    (DWORD)m_hPId)) != NULL)
        {
            // For processes with main level hWnds,
            // attempt to terminate nicely
            if(NULL != m_hWnd)
            {
                if(SendMessageTimeout(m_hWnd,
                                    WM_QUERYENDSESSION,
                                    0,
                                    ENDSESSION_LOGOFF,
                                    SMTO_ABORTIFHUNG,
                                    2000,       
                                    &dwResult))
                {
                    // Process will terminate nicely, so tell it to close
                    SendMessageTimeout(m_hWnd, 
                                        WM_CLOSE,
                                        TRUE,
                                        0,
                                        SMTO_ABORTIFHUNG,
                                        2000,   
                                        &dwResult);
                }
            }
            else
            {
                // TODO: Find a polite way to terminate 
                // processes without hWnds, i.e., console apps, etc.)
            }
    
            // Give time for the process to go away
            switch(WaitForSingleObject(hProcess, 2000)) // Wait 2 seconds
            {
            case WAIT_OBJECT_0:
                // Process terminated on its own
                break;
            default:
                //WAIT_ABANDONED, WAIT_FAILED, or WAIT_TIMEOUT
                // Process still exists, time to get rough
    
                if(GetProcessInfo()->IsNT())
                {
                    // Special-case killing WOW tasks: kill only ntvdm which in turn will
                    // will kill the child wow processes.
                    //This method helps to avoid the "can't terminate wow process 
                    //because wowexec is not letting it run" error dialogs
                    if (IsWowTask() && _wcsicmp(m_sImageName.c_str(), L"ntvdm.exe"))
                    {
                        ATLASSERT(GetProcessInfo()->m_pfn_VdmTerminateTaskWow);
                        GetProcessInfo()->m_pfn_VdmTerminateTaskWow(GetRealPID(), m_hTaskWow);
                    }
                }
                
                if(GetExitCodeProcess(hProcess, &dwExitCode))
                {
                    if(STILL_ACTIVE == dwExitCode)
                    {
    					USES_CONVERSION;
    					ATLTRACE( _T("IProcess::TerminateProcess(): %s\r\n"), W2T(m_sImageName.c_str()) );
    
                        if (!TerminateProcess(hProcess,0)) 
                        {
                            bDisplayError = TRUE;
                        }
                    }
                }
            }
           
            CloseHandle( hProcess );
        }
        // Invalidate so it's removed from the list
        Invalidate();
    
    }
    You can ignore the ntvdm code as it was a special case for handling 16-bit wow processes.
    Last edited by Arjay; December 1st, 2013 at 04:16 PM.

  4. #4
    Join Date
    Dec 2012
    Location
    England
    Posts
    2,308

    Re: How to logoff a user when the workstation is locked?

    Consoles handle logoff/shutdown queries via CTRL_SHUTDOWN_EVENT or CTRL_LOGOFF_EVENT notifications which should be processed in the console's handler routine (if the console program is well behaved!).

    The close process code will enable processes to be checked to see if they can be closed (assuming the programs process the WM_QUERYENDSESSION message - I found some that don't), and to forceibly close them. However, this doesn't seem to address the OP's question re logging off a user when the workstation is locked. The information I've found about this says you can't do it programatically.

    If ExitWindowsEx returns true, this doesn't mean that the operation has been carried out. All it means is that the command is valid and has been 'passed on' to the OS to perform. Whether the operation itself has been successful or not can't be determined from this function.
    All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.

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

    Re: How to logoff a user when the workstation is locked?

    Thank you, guys. I see Arjay's point, if I know that all processes don't have unsaved data I can use a forced log-off. Unfortunately as 2kaud pointed out this process is not conclusive. I've witnessed myself that WM_QUERYENDSESSION was not honored and in that case I can't risk logging off a user and lose their unsaved data.

    @Arjay I looked at alternative methods to log off a user and don't think InitiateSystemShutdown will work for me because it initiates shutdown/reboot, which I don't need. There's also WTSLogoffSession which unfortunately works as if I specified the EWX_FORCE flag.

    As an alternate method I was curious if there's a way to unlock the workstation, maybe even undocumented?

    Also since this LockWorkStation function seems to be of a relevance in case of a log-off, I'm not entirely clear how it works. Say, I have 3 interactive user accounts on the workstation with 3 of my user-mode processes running. Say, one calls LockWorkStation, then another one calls LockWorkStation and then after some time the 3rd process also calls LockWorkStation. Will this make each user account to be locked? Or will it toggle the lock between user 1, then user 2 and eventually user 3? If the latter case is true, maybe I can "juggle" this LockWorkStation call between user sessions and "trick" the ExitWindowsEx API this way. Just curious what you guys think on this?

  6. #6
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    11,217

    Re: How to logoff a user when the workstation is locked?

    Yeah, InitiateSystemShutdown won't work. I got off track after posting all the code.. Doing some research, I see that you can prevent a user from locking the workspace by changing a group policy (users only can logoff). Will that work for you?

    As far as the lock toggle question? Use the WTSRegisterSessionNotification to register for the session lock message and test for it in each of the scenarios.

    Btw, I haven't witnessed apps ignoring the WM_QUERYENDSESSION message, but have noticed that apps that are hung don't respond to it (like, duh?). SendMessageTimeout will return a 0 and GetLastError returns ERROR_TIMEOUT in this case.
    Last edited by Arjay; December 2nd, 2013 at 12:47 AM.

  7. #7
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    5,957

    Re: How to logoff a user when the workstation is locked?

    Quote Originally Posted by dc_2000 View Post
    Also since this LockWorkStation function seems to be of a relevance in case of a log-off, I'm not entirely clear how it works. Say, I have 3 interactive user accounts on the workstation with 3 of my user-mode processes running. Say, one calls LockWorkStation, then another one calls LockWorkStation and then after some time the 3rd process also calls LockWorkStation. Will this make each user account to be locked? Or will it toggle the lock between user 1, then user 2 and eventually user 3? If the latter case is true, maybe I can "juggle" this LockWorkStation call between user sessions and "trick" the ExitWindowsEx API this way. Just curious what you guys think on this?
    The API article states that the function is about locking interactive session's display. In terms of WTS it must be about locking WTS session's virtual display. So by no means it's about juggling sessions, but it's literally about locking session's input/output. (Not sure what did you mean by "locking user account" though)

    In case you really need to reliably log off users, you should find a way to disable the lock-workstation function and make your users to log off explicitly instead. Look in direction of system policies.


    As an alternate method I was curious if there's a way to unlock the workstation, maybe even undocumented?
    I'd like to warn you about going to enter an unsafe ground. Official security mechanisms is way too sensitive matter for being recklessly breached, or exploiting a breach, just for providing a questionable benefit/feature. And no doubt locking workstation is a part of Windows security.
    Best regards,
    Igor

  8. #8
    Join Date
    Dec 2012
    Location
    England
    Posts
    2,308

    Re: How to logoff a user when the workstation is locked?

    As an alternate method I was curious if there's a way to unlock the workstation, maybe even undocumented?
    No documented method - and as Ignor correctly points out in post #7, stay well clear of undocumented ways.

    If you find a workstation locked, rather than logoff what about reboot?

    Preventing users from locking the workstation when they temporarily leave the computer is not good security practice Yes, they can logoff - but then they have to save work etc first before they logoff and have to log back on again when they come back and reload the applications they had open etc etc. This amounts to a lot of time waste - especially if logon/logoff is slow if using roaming profiles. The users are unlikely to do it properly.

    Why do you want to logoff a user at a pre-defined time? Have you thought about using logon hours in the users profile to restrict usage?
    All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.

  9. #9
    Join Date
    Dec 2012
    Location
    England
    Posts
    2,308

    Re: How to logoff a user when the workstation is locked?

    Have a look at pshutdown command from SysInternanls
    http://technet.microsoft.com/en-us/s...rnals/bb897541
    particularly the -o option.

    Also have a look at
    http://www.intelliadmin.com/?p=4439
    All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.

  10. #10
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    11,217

    Re: How to logoff a user when the workstation is locked?

    Good idea 2kaud. Similarly you can try the built-in shutdown.exe utility (see the /l switch).

    C:\>shutdown /?
    Usage: shutdown [/i | /l | /s | /r | /g | /a | /p | /h | /e] [/f]
    [/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]

    No args Display help. This is the same as typing /?.
    /? Display help. This is the same as not typing any options.
    /i Display the graphical user interface (GUI).
    This must be the first option.
    /l Log off. This cannot be used with /m or /d options.
    /s Shutdown the computer.
    /r Shutdown and restart the computer.
    /g Shutdown and restart the computer. After the system is
    rebooted, restart any registered applications.
    /a Abort a system shutdown.
    This can only be used during the time-out period.
    /p Turn off the local computer with no time-out or warning.
    Can be used with /d and /f options.
    /h Hibernate the local computer.
    Can be used with the /f option.
    /e Document the reason for an unexpected shutdown of a computer.
    /m \\computer Specify the target computer.
    /t xxx Set the time-out period before shutdown to xxx seconds.
    The valid range is 0-315360000 (10 years), with a default of 30.
    If the timeout period is greater than 0, the /f parameter is
    implied.
    /c "comment" Comment on the reason for the restart or shutdown.
    Maximum of 512 characters allowed.
    /f Force running applications to close without forewarning users.
    The /f parameter is implied when a value greater than 0 is
    specified for the /t parameter.
    /d [p|u:]xx:yy Provide the reason for the restart or shutdown.
    p indicates that the restart or shutdown is planned.
    u indicates that the reason is user defined.
    If neither p nor u is specified the restart or shutdown is
    unplanned.
    xx is the major reason number (positive integer less than 256).
    yy is the minor reason number (positive integer less than 65536).

Posting Permissions

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


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center