.NET Forum / .NET Framework / .NET SDK / August 2003
WindowsService: active user
|
|
Thread rating:  |
Johannes - 21 Aug 2003 23:20 GMT Hi! I have WinXPro on my Computer and wanted to write a Service with .net. This service shoud save the time a user is logged on in a database. And I am able to create and install a service, but if I tried to get the CurrentUser (with e.g. SystemInformation.Username) it of course sayd "LocalService" or "System". Because this is the User the Thread runs in. But I want the user that is logged on and the problem is, that in XP many users can be logged on, but just one can actually be active. And I found out that the Task-Manager has access to this information, it can tell which users are logged on and if they are active or "not connected". And I thought is has to be anywhere in the registry (sam or security\policy or so). So my question: where can i find the user state? Thanks Johannes
Willy Denoyette [MVP] - 22 Aug 2003 13:12 GMT || Hi! || I have WinXPro on my Computer and wanted to write a [quoted text clipped - 14 lines] || Thanks || Johannes Easiest is to use the Management namespace classes (WMI wrappers) for this, following is a small sample:
using System; using System.Management; class tester {
private static ManagementObjectSearcher query; public static void Main() {
ManagementScope msc = new ManagementScope("root\\cimv2"); string queryString = "select LogonId from win32_logonsession where logontype = 2";
query = new ManagementObjectSearcher(msc, new SelectQuery(queryString));
foreach( ManagementObject mo in query.Get()) { Console.WriteLine( "ID '{0}'", mo["LogonId"].ToString()); RelatedObjectQuery relatedQuery = new RelatedObjectQuery ("associators of {Win32_LogonSession.LogonId='" + mo["LogonId"]+ "'}"); relatedQuery.RelationshipClass = "win32_LoggedonUser"; ManagementObjectSearcher searcher = new ManagementObjectSearcher(msc,relatedQuery); foreach (ManagementObject mob in searcher.Get()) { Console.WriteLine(mob["Caption"]); Console.WriteLine("Domain {0}, Name {1}", mob["Domain"], mob["Name"]);
} }
} }
Johannes - 23 Aug 2003 06:20 GMT the problem is that in winxp every local user can be logged on. And you can get this information with your programm,but i want to know who's dektop is on the top or if no user is active (maybe logged on) and you can just see the logon screen! And i think windows has to know it, so how can i get this information? Johannes
Willy Denoyette [MVP] - 23 Aug 2003 11:30 GMT || the problem is that in winxp every local user can be || logged on. And you can get this information with your [quoted text clipped - 3 lines] || so how can i get this information? || Johannes Ok I see, you are talking about Terminal Server info (Fast user switching on XP).
Nothing built-in in the FCL, so Pinvoke is the message (note the same can be acomplished using WMI and the Management classes). Here is a console sample using the WTS API's (and PInvoke): //Begin source using System; using System.Text; using System.Runtime.InteropServices; using System.Security; namespace WTSsessions { // Using Wtsapi32 (only available on Windows Server 2003 and XP) // Get Session information using Terminal server API's // Requirements: see SDK docs using HANDLE = System.IntPtr; class Class1 { static void Main(string[] args) { TerminalServer WTSinfo = new TerminalServer(); WTSinfo.GetSessionInfo(); } }
class TerminalServer { [DllImport("wtsapi32", CharSet=CharSet.Auto, SetLastError=true), SuppressUnmanagedCodeSecurityAttribute] static extern bool WTSEnumerateSessions ( HANDLE hServer, // Handle to a terminal server (from WTSOpenServer) int Reserved, // dmust be 0 uint Version, // must be 1 ref IntPtr ppSessionInfo, // pointer to pointer to Processinfo ref int pCount // no. of processes ); [DllImport("wtsapi32", CharSet=CharSet.Auto, SetLastError=true), SuppressUnmanagedCodeSecurityAttribute] static extern bool WTSQuerySessionInformation ( HANDLE hServer, // Handle to a terminal server (from WTSOpenServer) uint sessionId, // int WTSInfoClass, // ref IntPtr ppBuffer, // pointer to pointer to returned info ref int bCount // no. of bytes returned );
[DllImport("wtsapi32", SetLastError=true), SuppressUnmanagedCodeSecurityAttribute] static extern IntPtr WTSOpenServer ( string ServerName // Server name (NETBIOS) );
[DllImport("wtsapi32", SetLastError=true), SuppressUnmanagedCodeSecurityAttribute] static extern void WTSCloseServer ( HANDLE hServer // Handle obtained by WTSOpenServer );
[DllImport("wtsapi32", SetLastError=true), SuppressUnmanagedCodeSecurityAttribute] static extern void WTSFreeMemory ( IntPtr pMemory );
[StructLayout(LayoutKind.Sequential)] struct WTSSessionInfo { internal uint SessionId; [MarshalAs(UnmanagedType.LPTStr)] internal string pWinStationName; internal uint State; } enum WTSConnectState { Active, Connected, ConnectQuery, Shadow, Disconnected, Idle, Listen, Reset, Down, Init } enum WTSInfoClass { InitialProgram, ApplicationName, WorkingDirectory, OEMId, SessionId, UserName, WinStationName, DomainName, ConnectState, ClientBuildNumber, ClientName, ClientDirectory, ClientProductId, ClientHardwareId, ClientAddress, ClientDisplay, ClientProtocolType }
public void GetSessionInfo() { HANDLE hServer = IntPtr.Zero; IntPtr pInfo = IntPtr.Zero; IntPtr pInfoSave = IntPtr.Zero; WTSSessionInfo WTSsi; // Reference to ProcessInfo struct IntPtr ppBuffer = IntPtr.Zero; int bCount = 0; int count = 0; int iPtr = 0; try { hServer = WTSOpenServer("scenic"); if(hServer == IntPtr.Zero) Console.WriteLine(Marshal.GetLastWin32Error()); if (WTSEnumerateSessions(hServer, 0, 1, ref pInfo, ref count)) { pInfoSave = pInfo; Console.WriteLine("Number of sessions :{0}", count); for(int n = 0; n < count; n++) { WTSsi = (WTSSessionInfo) Marshal.PtrToStructure(pInfo, typeof(WTSSessionInfo) ); iPtr = (int)(pInfo) + Marshal.SizeOf(WTSsi); pInfo = (IntPtr)(iPtr); Console.WriteLine(WTSsi.SessionId + "\t" + WTSsi.pWinStationName + "\t" + (WTSConnectState)WTSsi.State ); if(WTSQuerySessionInformation(hServer, WTSsi.SessionId, (int)WTSInfoClass.UserName, ref ppBuffer, ref bCount)) Console.WriteLine("User: {0}", Marshal.PtrToStringAuto(ppBuffer)); if(WTSQuerySessionInformation(hServer, WTSsi.SessionId, (int)WTSInfoClass.DomainName, ref ppBuffer, ref bCount)) Console.WriteLine("Domain: {0}", Marshal.PtrToStringAuto(ppBuffer)); if(WTSQuerySessionInformation(hServer, WTSsi.SessionId, (int)WTSInfoClass.WinStationName, ref ppBuffer, ref bCount)) Console.WriteLine("Windowstation: {0}",Marshal.PtrToStringAuto(ppBuffer)); } } } catch(Exception e) { Console.WriteLine(e.Message); } finally { // Free memory used WTSFreeMemory(pInfoSave); // Close server handle WTSCloseServer(hServer); } } } } // End source
Willy.
Willy Denoyette [MVP] - 23 Aug 2003 12:05 GMT Note WTSOpenServer takes the server name as argument (here "scenic"),
|| hServer = WTSOpenServer("scenic"); || if(hServer == IntPtr.Zero) if you run this on a local machine you don't have to call this API, instead call WTSEnumerateSessions passing a null handle , like this.
if (WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref pInfo, ref count)) {
Willy.
Johannes - 23 Aug 2003 21:45 GMT Thanks you so much! Thanks for spending your time without getting something! But let me ask you one thing: Where did you find this? How do you know this? Thanks Johannes
Willy Denoyette [MVP] - 23 Aug 2003 22:08 GMT || Thanks you so much! || Thanks for spending your time without getting something! || But let me ask you one thing: Where did you find this? || How do you know this? || Thanks || Johannes Well, I know Taskmgr.exe use the WTS API's when running on a "fast task switching" enabled Windows XP box. For detailed info about this API set, refer to the Platform SDK documentation or the MSDN Library (Platform SDK: Terminal Services). Once you have the API's it's easy to define the PInvoke declarations, and use them from any managed language.
Willy.
Johannes - 24 Aug 2003 22:53 GMT I have another question: When on user is active and i have a timer running that gives me every second the username of the active user, it doesn't change when i change to the loggon screen. It is still the same user name, but if i select another user it changes of course, so how can i get the information wether the logon screen is active or not? Thanks
Johannes - 25 Aug 2003 08:12 GMT I found a function that can be a solution:
BOOL WINAPI WTSRegisterSessionNotification( HWND hWnd, // Window handle DWORD dwFlags // Flags );
I tried to include it with:
[DllImport ("wtsapi32",CharSet=CharSet.Auto,SetLastError=true), SuppressUnmanagedCodeSecurityAttribute] static extern bool WTSRegisterSessionNotification( HWND hWnd, DWORD dwFlags );
But i don't know how to recieve these messages with c# and a service. I don't have a HWnd and he doesn't even know the HWND handle. I tought maybe it works with:
using HWND =System.IntPtr; using DWORD=System.IntPtr;
And the value for the dwFlags should be: NOTIFY_FOR_ALL_SESSIONS But he doesn't know it either.
Here my question: 1.How and where can I learn that stuff, because in th msdn is not much about getting it work there are just function and articles 2. Could you please help me? Thanks Johannes
Willy Denoyette [MVP] - 25 Aug 2003 10:50 GMT || I found a function that can be a solution: || [quoted text clipped - 21 lines] || using HWND =System.IntPtr; || using DWORD=System.IntPtr; Ok for a HWND you can use System.IntPtr, but a DWORD is simply a System.Int32 (or int in C#).
|| And the value for the dwFlags should be: || NOTIFY_FOR_ALL_SESSIONS [quoted text clipped - 4 lines] || msdn is not much about getting it work there are just || function and articles Check the API descriptions on MSDN, and install (if you didn't already) the latest Platform SDK (downloadable from Microsoft), if looking for samples or problem descriptions, check the Knowledge base. When looking for PInvoke stuff, check the .NET SDK docs in MSDN However, take care when using these functions from managed code, because: - If a large number of Win32 are used within a small application, you probably have chosen the wrong language/platform for the job, here I mean that you should use C++ (or ME C++). The Platform SDK and Win32 API set is written with C (C++) as a target, Pinvoke is only a bridge between the managed and unmanaged worlds, but it requires you to learn both sides to be successful. - They can be covered directly or indirectly by the framework classes, especially most of the 'management' style API's are covered by the System.Management namespace classes (WMI wrappers).
|| 2. Could you please help me? || Thanks || Johannes
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|