窗口标题/前景检测所有用户的运行应用程序

时间:2017-04-06 19:09:05

标签: c# windows powershell winapi

假设应用程序将由administrator用户在Windows上执行;有没有办法使用Windows API检索窗口标题并检测应用程序是否在所有登录用户的前台?

尝试以下代码,我们无法从正在运行的其他用户登录的应用程序中检索标题。

// to get the processes
Process[] processlist = Process.GetProcesses();
// and this to get the title:
process.MainWindowTitle

1 个答案:

答案 0 :(得分:1)

您需要使用winapi中的getforegroundwindow函数。但这只是一个问题。它必须在用户会话的上下文中执行。这意味着您必须在获取用户令牌后枚举计算机中的所有用户会话,并使用此用户令牌,通过CreateProcessAsUser在用户会话中执行辅助进程。此辅助进程可以执行getforegroundwindow,您必须实现任何ipc方法以将信息返回给主应用程序。我在windows服务中使用此代码,在用户会话的上下文中执行小程序:

[StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        } 

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
        [StructLayout(LayoutKind.Sequential)]
        internal struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }
        [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUserW", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool CreateProcessAsUser(
                IntPtr hToken,
                string lpApplicationName,
                string lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandles,
                UInt32 dwCreationFlags,
                IntPtr lpEnvironment,
                string lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern int WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);

        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

        [DllImport("wtsapi32.dll")]
        static extern void WTSCloseServer(IntPtr hServer);

        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern Int32 WTSEnumerateSessions(
            IntPtr hServer,
            [MarshalAs(UnmanagedType.U4)] Int32 Reserved,
            [MarshalAs(UnmanagedType.U4)] Int32 Version,
            ref IntPtr ppSessionInfo,
            [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);

        [DllImport("wtsapi32.dll")]
        static extern void WTSFreeMemory(IntPtr pMemory);

        [StructLayout(LayoutKind.Sequential)]
        private struct WTS_SESSION_INFO
        {
            public Int32 SessionID;

            [MarshalAs(UnmanagedType.LPStr)]
            public String pWinStationName;

            public WTS_CONNECTSTATE_CLASS State;
        }

        public enum WTS_CONNECTSTATE_CLASS
        {
            WTSActive,
            WTSConnected,
            WTSConnectQuery,
            WTSShadow,
            WTSDisconnected,
            WTSIdle,
            WTSListen,
            WTSReset,
            WTSDown,
            WTSInit
        }
    public static IntPtr OpenServer(String Name)
    {
        IntPtr server = WTSOpenServer(Name);
        return server;
    }
    public static void CloseServer(IntPtr ServerHandle)
    {
        WTSCloseServer(ServerHandle);
    }
    public static List<uint> ListSessions(String ServerName)
    {
        IntPtr server = IntPtr.Zero;
        List<uint> ret = new List<uint>();
        server = OpenServer(ServerName);

        try
        {
            IntPtr ppSessionInfo = IntPtr.Zero;

            Int32 count = 0;
            Int32 retval = WTSEnumerateSessions(server, 0, 1, ref ppSessionInfo, ref count);
            Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));

            Int64 current = (int)ppSessionInfo;

            if (retval != 0)
            {
                for (int i = 0; i < count; i++)
                {
                    WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
                    current += dataSize;

                    ret.Add((uint)si.SessionID);
                }

                WTSFreeMemory(ppSessionInfo);
            }
        }
        finally
        {
            CloseServer(server);
        }

        return ret;
    }

    protected override void OnStart(string[] args)
    {
        List<uint> retVal =  ListSessions("COMPUTER_NAME");

        for (int i = 0; i < retVal.Count; i++)
        {
            IntPtr userToken = new IntPtr();
            WTSQueryUserToken(retVal[i], out userToken);


            STARTUPINFO info = new STARTUPINFO();
            PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION();

             CreateProcessAsUser(userToken, null, @"c:\windows\notepad.exe",
              IntPtr.Zero, IntPtr.Zero, false, (UInt32)0, IntPtr.Zero, null,
            ref info, out procInfo);


        }   

}

此代码适用于Windows服务,入口点为OnStart()函数。在Windows中,SYSTEM帐户具有执行此代码的所有必要权限。我没有在Admin上下文中检查它,但可能它也会工作。

此代码将在所有用户会话中执行notepad.exe。你必须使用getforegroundwindow和某种进程间通信来创建程序