1

我正在尝试编写一个应用程序,它将使用 Win32 API 创建一个新桌面。

下面的代码在 Windows 7 中有效,但在 Windows 8 中,创建的桌面没有桌面图标和空任务栏。

public class Desktop
{
    private const int NORMAL_PRIORITY_CLASS = 0x00000020;

    private const long DF_ALLOWOTHERACCOUNTHOOK = 0x0001L;

    private const uint DELETE = 0x00010000;
    private const uint READ_CONTROL = 0x00020000;
    private const uint WRITE_DAC = 0x00040000;
    private const uint WRITE_OWNER = 0x00080000;

    private const uint STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER;

    private const long DESKTOP_CREATEWINDOW = 0x0002L;
    private const long DESKTOP_ENUMERATE = 0x0040L;
    private const long DESKTOP_WRITEOBJECTS = 0x0080L;
    private const long DESKTOP_SWITCHDESKTOP = 0x0100L;
    private const long DESKTOP_CREATEMENU = 0x0004L;
    private const long DESKTOP_HOOKCONTROL = 0x0008L;
    private const long DESKTOP_READOBJECTS = 0x0001L;
    private const long DESKTOP_JOURNALRECORD = 0x0010L;
    private const long DESKTOP_JOURNALPLAYBACK = 0x0020L;
    private const uint AccessRights = (uint)DESKTOP_JOURNALRECORD |
        (uint)DESKTOP_JOURNALPLAYBACK |
        (uint)DESKTOP_CREATEWINDOW |
        (uint)DESKTOP_ENUMERATE |
        (uint)DESKTOP_WRITEOBJECTS |
        (uint)DESKTOP_SWITCHDESKTOP |
        (uint)DESKTOP_CREATEMENU |
        (uint)DESKTOP_HOOKCONTROL |
        (uint)DESKTOP_READOBJECTS |
        STANDARD_RIGHTS_REQUIRED;

    private delegate bool EnumDesktopProc(string lpszDesktop, IntPtr lParam);

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

    [DllImport("user32.dll")]
    private static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern IntPtr CreateDesktop(string desktopName, string device, string deviceMode, int flags, uint accessMask, [In] ref SECURITY_ATTRIBUTES attributes);

    [DllImport("user32.dll")]
    private static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags, bool fInherit, uint dwDesiredAccess);

    [DllImport("user32.dll")]
    private static extern bool SwitchDesktop(IntPtr hDesktop);

    [DllImport("kernel32.dll")]
    private static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, ref PROCESS_INFORMATION lpProcessInformation);

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

    [StructLayout(LayoutKind.Sequential)]
    private 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)]
    private struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    private static List<string> _desktops = new List<string>();

    public static IntPtr Create(string name)
    {
        var securityAttributes = new SECURITY_ATTRIBUTES();
        securityAttributes.nLength = Marshal.SizeOf(securityAttributes);

        return CreateDesktop(name, null, null, (int) DF_ALLOWOTHERACCOUNTHOOK, AccessRights, ref securityAttributes);
    }

    public static IntPtr Open(string name)
    {
        return OpenDesktop(name, 0, false, AccessRights);
    }

    public static bool Show(IntPtr desktopPrt)
    {
        if (desktopPrt == IntPtr.Zero) return false;
        return SwitchDesktop(desktopPrt);
    }

    public static void Prepare(string desktopName)
    {
        CreateProcess("C:\\Windows\\explorer.exe", desktopName);
    }

    public static bool Exists(string name)
    {
        return GetDesktops().Any(s => s == name);
    }

    private static void CreateProcess(string path, string desktopName)
    {
        STARTUPINFO si = new STARTUPINFO();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = desktopName;

        PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

        var lpCurrentDirectory = Path.GetDirectoryName(path);
        CreateProcess(path, null, IntPtr.Zero, IntPtr.Zero, true, NORMAL_PRIORITY_CLASS, IntPtr.Zero, lpCurrentDirectory, ref si, ref pi);
    }

    private static string[] GetDesktops()
    {
        IntPtr windowStation = GetProcessWindowStation();
        if (windowStation == IntPtr.Zero) return new string[0];

        _desktops.Clear();

        bool result = EnumDesktops(windowStation, DesktopEnumProc, IntPtr.Zero);
        if (!result) return new string[0];

        return _desktops.ToArray();
    }

    private static bool DesktopEnumProc(string lpszDesktop, IntPtr lParam)
    {
        _desktops.Add(lpszDesktop);
        return true;
    }
}

用法:

var desktopName = "TestDesktop";
var desktopPrt = Desktop.Create(desktopName);
Desktop.Show(desktopPrt);
Desktop.Prepare(desktopName);

Sysinternals 桌面应用程序 ( http://technet.microsoft.com/en-us/sysinternals/cc817881.aspx ) 使用相同的 API,它在 Windows 8 中工作,所以一定有我遗漏的东西。

有人对我有任何指示吗?或者有谁知道我在哪里可以找到如何使用这个 API 的例子?API 调用的 MSDN 提供了很多信息,但没有太多示例。

感谢:D

4

1 回答 1

1

编辑:对不起,我意识到你在你的代码片段中运行它,请忽略我的评论。

explorer.exe为您创建的每个桌面显式运行如何?那个处理图标、任务栏等......当您运行 SysInternals Desktops 应用程序时,您可以看到它实际上是这样做的。

于 2014-01-10T14:48:37.160 回答