C# 在桌面上获取所有进程

C# 在桌面上获取所有进程,c#,.net,winapi,C#,.net,Winapi,我已经使用CreateDesktop创建了一个新的桌面,并希望能够枚举该桌面中的所有进程 我试过这个: foreach (Process process in Process.GetProcesses()) { foreach (ProcessThread processThread in process.Threads) { IntPtr hDesk = GetThreadDesktop((uint)processThread.Id); if (

我已经使用CreateDesktop创建了一个新的桌面,并希望能够枚举该桌面中的所有进程

我试过这个:

foreach (Process process in Process.GetProcesses())
{
    foreach (ProcessThread processThread in process.Threads)
    {
        IntPtr hDesk = GetThreadDesktop((uint)processThread.Id);
        if (hDesk == desk)
        {
            // Do something
        }
    }
}
然而,我得到访问被拒绝的例外。我也可以用

EnumDesktopWindows
但是,这不适用于命令行应用程序。(我试图阻止键盘记录者)

有没有办法在桌面上获取所有进程?
谢谢

我花了最后一个小时玩这个,我在控制台的窗口里玩得很好。代码很混乱,但您应该能够通过它:

class Program
{
    private static class Win32Native
    {
        [Flags]
        public enum CreateDesktopFlags : uint
        {
            DF_NONE = 0,
            DF_ALLOWOTHERACCOUNTHOOK = 1
        }

        [Flags]
        public enum CreateWindowAccessMask : uint
        {
            DESKTOP_READOBJECTS = 0x0001,
            DESKTOP_CREATEWINDOW = 0x0002,
            DESKTOP_CREATEMENU = 0x0004,
            DESKTOP_HOOKCONTROL = 0x0008,
            DESKTOP_JOURNALRECORD = 0x0010,
            DESKTOP_JOURNALPLAYBACK = 0x0020,
            DESKTOP_ENUMERATE = 0x0040,
            DESKTOP_WRITEOBJECTS = 0x0080,
            DESKTOP_SWITCHDESKTOP = 0x0100,
            DESKTOP_ALL_ACCESS = 0x01FF
        }

        [Flags]
        public enum CreateProcessFlags : uint
        {
            CREATE_NEW_CONSOLE = 0x00000010,
            CREATE_NEW_PROCESS_GROUP = 0x00000200
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct STARTUPINFO
        {
            public int cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public int dwX;
            public int dwY;
            public int dwXSize;
            public int dwYSize;
            public int dwXCountChars;
            public int dwYCountChars;
            public int dwFillAttribute;
            public int dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }

        [DllImport("user32.dll")]
        public static extern IntPtr GetProcessWindowStation();

        [return: MarshalAs(UnmanagedType.Bool)]
        public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        [return: MarshalAs(UnmanagedType.Bool)]
        public delegate bool EnumDesktopProc([MarshalAs(UnmanagedType.LPWStr)] string lpszDesktop, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpfn, IntPtr lParam);

        [DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Unicode)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Unicode)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode)]
        public static extern IntPtr CreateDesktop(
            string lpszDesktop, IntPtr lpszDevice,
            IntPtr pDevMode, CreateDesktopFlags dwFlags,
            CreateWindowAccessMask dwDesiredAccess,
            IntPtr lpsa);

        [DllImport("user32.dll", SetLastError = true, EntryPoint = "EnumDesktopsW", CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseDesktop(IntPtr hDesktop);

        [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "CreateProcessW", CharSet = CharSet.Unicode)]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool CreateProcess(
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            CreateProcessFlags dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("kernel32.dll")]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll")]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
    }

    static int Main(string[] args)
    {
        StringBuilder sbWndText = new StringBuilder(512),
            sbWndClass = new StringBuilder(512);

        Console.WriteLine("Trying current desktop:");
        if(!Win32Native.EnumDesktopWindows(IntPtr.Zero, (hWnd, lParam) =>
        {
            Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
            Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);

            Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");

            return true;
        }, IntPtr.Zero))
        {
            var error = Marshal.GetLastWin32Error();
            Console.WriteLine($"EnumDesktopWindows for current desktop failed with error {error}");
        }

        Console.WriteLine("Current desktops: ");
        Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
        {
            Console.WriteLine($"Found desktop: {desktopName}");
            return true;
        }, IntPtr.Zero);

        Console.WriteLine("Trying new desktop:");
        const string DesktopName = "ANDY DESKTOP NEATO 2";

        var hDesktop = Win32Native.CreateDesktop(
            DesktopName, IntPtr.Zero, IntPtr.Zero,
            Win32Native.CreateDesktopFlags.DF_ALLOWOTHERACCOUNTHOOK,
            Win32Native.CreateWindowAccessMask.DESKTOP_ALL_ACCESS,
            IntPtr.Zero);

        if(hDesktop != IntPtr.Zero)
        {
            Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
            {
                Console.WriteLine($"Found desktop: {desktopName}");
                return true;
            }, IntPtr.Zero);

            var si = new Win32Native.STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = DesktopName;
            var pi = new Win32Native.PROCESS_INFORMATION();

            if(!Win32Native.CreateProcess(
                null, "cmd.exe", IntPtr.Zero, IntPtr.Zero, false,
                Win32Native.CreateProcessFlags.CREATE_NEW_CONSOLE |
                    Win32Native.CreateProcessFlags.CREATE_NEW_PROCESS_GROUP,
                IntPtr.Zero, null, ref si, out pi))
            {
                var error = Marshal.GetLastWin32Error();
                Console.WriteLine($"Unable to create process on new desktop: {error}");
            }

            Console.WriteLine("WAITING 2 SECONDS FOR PROCESS TO START...");
            Thread.Sleep(2000); // breath so the process starts

            if (!Win32Native.EnumDesktopWindows(hDesktop, (hWnd, lParam) =>
            {
                Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
                Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);

                Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");

                return true;
            }, IntPtr.Zero))
            {
                var error = Marshal.GetLastWin32Error();
                Console.WriteLine($"EnumDesktopWindows for new desktop failed with error {error}");
            }

            // IMPORTANT: close the processes you start, otherwise you desktop won't self-destruct.
            Win32Native.TerminateProcess(pi.hProcess, 42);
            Win32Native.CloseHandle(pi.hProcess);
            Win32Native.CloseHandle(pi.hThread);
            Win32Native.CloseDesktop(hDesktop);
        }
        else
        {
            Console.WriteLine($"Unable to create desktop: {Marshal.GetLastWin32Error()}");
        }

        return 0;
    }
}
因此,我认为您在使用
EnumDesktopWindows
时遇到的问题是,当您调用
CreateDesktop
时,您没有请求足够的权限。我将所有权限设置为(值为
0x1FF
),然后
EnumDesktopWindows
为我工作

请记住,如果调用
EnumDesktopWindows
但没有要枚举的窗口,则调用
GetLastError
时,它将返回值为
0
false

因此,我所做的是在新桌面中创建一个进程(
cmd.exe
),然后称为
EnumDesktopWindows
,以证明它确实有效

另外请记住,如果您没有销毁新桌面中的所有进程,那么桌面将不会“自毁”,并且在所有进程被销毁或您注销/重新启动之前,它将处于活动状态

我也以普通用户的身份运行了这个。我不需要提升为管理员来完成这项工作

但是,这不适用于命令行应用程序。)我正在努力 防止键盘记录者)

假设您想要阻止桌面的输入

因为hook需要一个消息循环来接收键盘消息,这需要创建一个窗口。因此,限制其他用户创建与桌面关联的窗口应用程序可以防止他们记录键盘输入

如果要检查给定进程的桌面名称,查看其是否与桌面名称相同(应用于窗口应用程序),可以按照以下步骤操作:

  • 调用以从目标进程ID获取
    句柄
  • 调用以检索进程的
    PEB
    结构的地址
  • 调用以读取
    PEB
    。它是
    ProcessParams。DesktopName
    字段包含当前与该进程关联的工作站/桌面的名称(MSDN中还有更多可用字段)

  • 请参阅“”

    您是否尝试使用CMD作为管理员?是的,它仍然显示访问被拒绝感兴趣。我要试试这个。所以您想创建一个桌面,然后枚举创建的桌面上的所有窗口,对吗?如果使用
    IntPtr.Zero
    作为第一个参数调用
    EnumDesktopWindows
    ,会发生什么情况?我知道如何使用Windows,但是控制台应用程序呢?这就是我想说的achieve@Andy非常感谢您抽出时间!评论不用于扩展讨论;这段对话已经结束。