Log Off User from Win Xp Programmatically in C#

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



Leave a reply



Submit