Log off user from Win XP programmatically in C#
You could P/Invoke ExitWindowsEx:
http://www.pinvoke.net/default.aspx/user32/ExitWindowsEx.html
Pulling it all together:
using System.Runtime.InteropServices;
class Class1
{
[DllImport("user32.dll")]
static extern bool ExitWindowsEx(uint uFlags, uint dwReason);
[STAThread]
static void Main(string[] args)
{
ExitWindowsEx(ExitWindows.LogOff, ShutdownReason.MajorOther | ShutdownReason.MinorOther);
}
}
[Flags]
public enum ExitWindows : uint
{
// ONE of the following five:
LogOff = 0x00,
ShutDown = 0x01,
Reboot = 0x02,
PowerOff = 0x08,
RestartApps = 0x40,
// plus AT MOST ONE of the following two:
Force = 0x04,
ForceIfHung = 0x10,
}
[Flags]
enum ShutdownReason : uint
{
MajorApplication = 0x00040000,
MajorHardware = 0x00010000,
MajorLegacyApi = 0x00070000,
MajorOperatingSystem = 0x00020000,
MajorOther = 0x00000000,
MajorPower = 0x00060000,
MajorSoftware = 0x00030000,
MajorSystem = 0x00050000,
MinorBlueScreen = 0x0000000F,
MinorCordUnplugged = 0x0000000b,
MinorDisk = 0x00000007,
MinorEnvironment = 0x0000000c,
MinorHardwareDriver = 0x0000000d,
MinorHotfix = 0x00000011,
MinorHung = 0x00000005,
MinorInstallation = 0x00000002,
MinorMaintenance = 0x00000001,
MinorMMC = 0x00000019,
MinorNetworkConnectivity = 0x00000014,
MinorNetworkCard = 0x00000009,
MinorOther = 0x00000000,
MinorOtherDriver = 0x0000000e,
MinorPowerSupply = 0x0000000a,
MinorProcessor = 0x00000008,
MinorReconfig = 0x00000004,
MinorSecurity = 0x00000013,
MinorSecurityFix = 0x00000012,
MinorSecurityFixUninstall = 0x00000018,
MinorServicePack = 0x00000010,
MinorServicePackUninstall = 0x00000016,
MinorTermSrv = 0x00000020,
MinorUnstable = 0x00000006,
MinorUpgrade = 0x00000003,
MinorWMI = 0x00000015,
FlagUserDefined = 0x40000000,
FlagPlanned = 0x80000000
}
Log off a Windows user locally using c#
Use the WTSDisconnectSession()
Windows API. See article here.
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
class Program
{
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
[DllImport("Kernel32.dll", SetLastError = true)]
static extern int WTSGetActiveConsoleSessionId();
const int WTS_CURRENT_SESSION = -1;
static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
static void Main(string[] args)
{
if (!WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,
WTS_CURRENT_SESSION, false))
throw new Win32Exception();
}
}
Even without remote desktop, it will disconnect the current user and go to the login screen. The processes will still run in the background. After manually login in again, the running programs will appear as they were before the disconnect.
Delay windows logoff (XP, Vista & 7)
When a logout is about to occur, the Windows message WM_QUERYENDSESSION
is sent to all applicaitons. An application can reply to this message with a negative answer, asking for the logoff to be cancelled.
From the MDSN doc:
Applications should respect the user's intentions and return TRUE. By
default, the DefWindowProc function returns TRUE for this message.If shutting down would corrupt the system or media that is being
burned, the application can return FALSE. However, it is good practice
to respect the user's actions.
In .NET this functionality is exposed by the SystemEvents.SessionEnding
event. If you set the Cancel
property of SessionEndingEventArgs
to true
requests the logoff being cancelled.
The logoff part has been asked before in Log off user from Win XP programmatically in C#.
How do I programatically log off the current user and log on as another?
Microsoft has this solution in c++, which you can use to hack a c# solution, or put in a DLL and call it using COM interop.
http://support.microsoft.com/kb/196070
Get notified from logon and logoff
I use ServiceBase.OnSessionChange to catch the different user events and load the necessary information afterwards.
protected override void OnSessionChange(SessionChangeDescription desc)
{
var user = Session.Get(desc.SessionId);
}
To load the session information I use the WTS_INFO_CLASS. See my example below:
internal static class NativeMethods
{
public enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}
[DllImport("Kernel32.dll")]
public static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQuerySessionInformation(IntPtr hServer, Int32 sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out Int32 pBytesReturned);
[DllImport("Wtsapi32.dll")]
public static extern void WTSFreeMemory(IntPtr pointer);
}
public static class Status
{
public static Byte Online
{
get { return 0x0; }
}
public static Byte Offline
{
get { return 0x1; }
}
public static Byte SignedIn
{
get { return 0x2; }
}
public static Byte SignedOff
{
get { return 0x3; }
}
}
public static class Session
{
private static readonly Dictionary<Int32, User> User = new Dictionary<Int32, User>();
public static bool Add(Int32 sessionId)
{
IntPtr buffer;
int length;
var name = String.Empty;
var domain = String.Empty;
if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTS_INFO_CLASS.WTSUserName, out buffer, out length) && length > 1)
{
name = Marshal.PtrToStringAnsi(buffer);
NativeMethods.WTSFreeMemory(buffer);
if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTS_INFO_CLASS.WTSDomainName, out buffer, out length) && length > 1)
{
domain = Marshal.PtrToStringAnsi(buffer);
NativeMethods.WTSFreeMemory(buffer);
}
}
if (name == null || name.Length <= 0)
{
return false;
}
User.Add(sessionId, new User(name, domain));
return true;
}
public static bool Remove(Int32 sessionId)
{
return User.Remove(sessionId);
}
public static User Get(Int32 sessionId)
{
if (User.ContainsKey(sessionId))
{
return User[sessionId];
}
return Add(sessionId) ? Get(sessionId) : null;
}
public static UInt32 GetActiveConsoleSessionId()
{
return NativeMethods.WTSGetActiveConsoleSessionId();
}
}
public class AvailabilityChangedEventArgs : EventArgs
{
public bool Available { get; set; }
public AvailabilityChangedEventArgs(bool isAvailable)
{
Available = isAvailable;
}
}
public class User
{
private readonly String _name;
private readonly String _domain;
private readonly bool _isDomainUser;
private bool _signedIn;
public static EventHandler<AvailabilityChangedEventArgs> AvailabilityChanged;
public User(String name, String domain)
{
_name = name;
_domain = domain;
if (domain.Equals("EXAMPLE.COM"))
{
_isDomainUser = true;
}
else
{
_isDomainUser = false;
}
}
public String Name
{
get { return _name; }
}
public String Domain
{
get { return _domain; }
}
public bool IsDomainUser
{
get { return _isDomainUser; }
}
public bool IsSignedIn
{
get { return _signedIn; }
set
{
if (_signedIn == value) return;
_signedIn = value;
OnAvailabilityChanged(this, new AvailabilityChangedEventArgs(IsSignedIn));
}
}
protected void OnAvailabilityChanged(object sender, AvailabilityChangedEventArgs e)
{
if (AvailabilityChanged != null)
{
AvailabilityChanged(this, e);
}
}
}
The following code use the static AvailabilityChanged
event from User
, which gets fired as soon as the session state changes. The arg e
contains the specific user.
public Main()
{
User.AvailabilityChanged += UserAvailabilityChanged;
}
private static void UserAvailabilityChanged(object sender, AvailabilityChangedEventArgs e)
{
var user = sender as User;
if (user == null) return;
System.Diagnostics.Debug.WriteLine(user.IsSignedIn);
}
How can I detect that users lock Windows and then log them off
You don't need bat or c# for that, just adjusting CNS, Corporate Nazi Settings. Also known as "Group Policies".
You can also find all the different options if (e.g.) you start up gpedit.msc. A good starting point is Administrative Templates --> System --> Ctrl+Alt+Del Options.
Here you can remove lock. One also can adjust lock so instead of locking it'll log the user off.
Login to Windows xp programmatically
Have a look at this: Gina.dll MSDN
Gina is the system that fingerprint readers etc. use to customise the login screen. You may be able to use this to achieve your purpose?
To future proof your app (Vista and Windows 7) you may wish to look into these: MSDN Mag Vista Credential Providers
Related Topics
Getting the Index of a Particular Item in Array
C# Linq Where Date Between 2 Dates
Can Someone Explain How Bcrypt Verifies a Hash
How Do Events Cause Memory Leaks in C# and How Do Weak References Help Mitigate That
How to Recognize If a String Contains Unicode Chars
How to Determine If an Event Is Already Subscribed
How to Detect If MAChine Is Joined to Domain
How to Copy Value from Class X to Class Y with the Same Property Name in C#
How to Cast Expression<Func<T, Datetime>> to Expression<Func<T, Object>>
How to Create an Instance from a String in C#
Sqlexception:String or Binary Data Would Be Truncated
Sorting an Array of Folder Names Like Windows Explorer (Numerically and Alphabetically) - Vb.Net
How to Implement a Navigation Button in Shared Application Resources