如何确定从窗口服务当前Windows用户?窗口、用户、Windows

2023-09-03 11:48:49 作者:一脸美人痣

我正在写一个Windows服务使用C#.NET 2005如何确定谁是当前登录的用户(如果有的话)?也就是有没有办法得到通知,当用户登录?

I'm writing a Windows Service using C# .NET 2005. How can I determine who the currently logged-on user is (if any)? Also is there a way to be notified when a user logs on?

另外,有没有办法知道谁最近使用的机器?

Alternatively, is there a way to know who has recently used the machine?

我需要知道当前登录的用户,所以我可以缓存一些数据,这些用户。工作在企业环境中有成千上万的潜在用户,但它才有意义缓存数据的人谁使用计算机。

I need to know the currently logged on user so I can cache some data for that user. Operating in a corporate environment there are thousands of potential users but it only makes sense to cache data for someone who uses that machine.

更新:

This解决方案效果很好。另请参阅这个pinvoke.net例如它采用扩展的结构也检索域名。

This solution works well. Also see this pinvoke.net example which uses the extended structure to also retrieve domain name.

在这个组合我使用SystemEvents类,当用户登录到本机的通知。请参见例如2此处一个很好的例子 - 注意,需要,以便从服务使用一个隐藏的形式,以便能够使用SystemEvents从服务

In combination with this I'm using the SystemEvents class to be notified when a user logs on to the machine. See example 2 here for a good example - note that you need to use a hidden form from a service in order to be able to use SystemEvents from a service.

推荐答案

您可以使用P / Invoke来调用的 NetWkstaUserEnum ,这将枚举当前登录的用户。请记住,可能有一个以上的用户的情况下有终端服务器会话,而不是所有的用户返回是一个真实的用户。正如文件指出:

You can use P/Invoke to call NetWkstaUserEnum, which will enumerate the currently logged on users. Keep in mind that there might be more than one user in case there are terminal server sessions, and that not all users returned is a "real" user. As the documentation states:

这个列表包括互动,   服务和批处理登录。

"This list includes interactive, service and batch logons."

下面是一个完整的工作code在C#中如何调用NetWkstaUserEnum例如:

Here is a complete working code example in C# on how to call NetWkstaUserEnum:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace EnumerateUsers
{
    class Program
    {
        static void Main(string[] args)
        {
            var ue = new UserEnumerator();
            foreach(string userName in ue.GetLoggedOnUsers(null))
            {
                Console.WriteLine(userName);
            }
        }

    }

    class UserEnumerator
    {
        public IEnumerable<string> GetLoggedOnUsers(string host)
        {
            int entriesRead, totalEntries, resumeHandle = 0;
            IntPtr pBuffer = IntPtr.Zero;
            try
            {
                int result = NetWkstaUserEnum(host, 0, out pBuffer, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries, ref resumeHandle);
                if (result != NERR_Success)  
                    throw new ApplicationException(String.Format("Failed to enumerate users, error code {0}", result));

                return GetUsersFromStruct(pBuffer, entriesRead).ToList();
            }
            finally
            {
                if (pBuffer != IntPtr.Zero)
                    NetApiBufferFree(pBuffer);
                }

        }

        private IEnumerable<string> GetUsersFromStruct(IntPtr pBuffer, int count)
        {
            for (int i = 0; i < count; i++)
            {
                var user = (WKSTA_USER_INFO_0)Marshal.PtrToStructure(pBuffer, typeof(WKSTA_USER_INFO_0));
                yield return user.username;
                pBuffer = IntPtr.Add(pBuffer, user.username.Length * 2);                
            }
        }
        [DllImport("netapi32.dll")]
        private static extern int NetWkstaUserEnum(string host, int level, out IntPtr pBuffer, int prefMaxLength, out int entriesRead,
                                     out int totalEntries, ref int resumeHandle);

        [DllImport("netapi32.dll")]
        private static extern int NetApiBufferFree(IntPtr buffer);

        private const int MAX_PREFERRED_LENGTH = -1;

        private const int NERR_Success = 0;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct WKSTA_USER_INFO_0
    { 
        [MarshalAs(UnmanagedType.LPTStr)]
        internal string username;
    }
}