Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / .NET SDK / August 2003

Tip: Looking for answers? Try searching our database.

WindowsService: active user

Thread view: 
Enable EMail Alerts  Start New Thread
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

Rate this thread:







Free Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.