【发布时间】:2021-02-12 23:48:30
【问题描述】:
我正在开发一个小型 C# 应用程序,但发现了一个奇怪的错误。此应用程序的目标是创建一个新桌面并在其中启动一个进程。
为此,我依赖以下win32函数:
[DllImport("user32.dll")]
public static extern IntPtr CreateDesktop(string lpszDesktop,
IntPtr lpszDevice,
IntPtr pDevmode,
uint dwFlags,
uint dwDesiredAccess,
IntPtr lpsa);
[DllImport("user32.dll")]
public 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);
现在的情况是我可以创建桌面,切换到它并最终在新创建的桌面中正确启动一些应用程序,例如:internet explorer 或 Notepad++ 或 putty.exe 等......但对于其他应用程序,这只是简单不起作用。即 Chrome、Firefox、Edge 等... 当我尝试使用 firefox 时,尽管我在 CreateProcess 函数中指定了新桌面的名称,但进程会在默认桌面中启动。
我使用的所有代码都非常简单:
const int NORMAL_PRIORITY_CLASS = 0x0020;
static void Main(string[] args){
var desktopName = "mynewdesktopinwindowsten";
bool result = true;
//create the desktop:
var intHandler = CreateDesktop(desktopName,
IntPtr.Zero,//Reserved; must be NULL.
IntPtr.Zero, //Reserved; must be NULL.
0x0001, //DF_ALLOWOTHERACCOUNTHOOK optional
(uint)AccessRight.GENERIC_ALL,
IntPtr.Zero);
//Switch to the new desktop:
result = SwitchDesktop(intHandler);
SetThreadDesktop(intHandler);
if (result)
{
//launch a process inside the new desktop:
createProcessInsideDesktop(desktopName);
}
}
private static void createProcessInsideDesktop(string desktopName)
{
////set startup parameters:
STARTUPINFO si = new STARTUPINFO();
si.cb = (uint)Marshal.SizeOf(si);
si.lpDesktop = desktopName;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
var filePath = @"C:\Program Files (x86)\Notepad++\notepad++.exe";
bool resultCreateProcess = CreateProcess(
null,
filePath,
IntPtr.Zero,
IntPtr.Zero,
true,
NORMAL_PRIORITY_CLASS,
IntPtr.Zero,
null,
ref si,
ref pi);
//do something to close the desktop and switch to default.......
}
[Flags]
public enum AccessRight : uint
{
DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,
GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK |
DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP)
};
上面的代码在 Notepad++ 上运行良好,但是当我改变这一行时。假设我想启动 Firefox: var filePath = @"C:\Program Files\Mozilla Firefox\firefox.exe"; 该进程不是在新桌面中创建的,而是在默认桌面中创建的。因此,如果有人能在这里发现一些重要的事情来解决这个问题,我们将不胜感激。
【问题讨论】:
-
是否已经有任何 Firefox 实例在运行?可能与Thunderbird cannot be open in more than one virtual desktop on Windows 10有关。
-
我能够重现您的问题,该问题也出现在
explorer进程的开头。我猜是因为这些进程的子进程是在默认桌面而不是当前桌面启动的。可以参考:Creating process to run IE on new Windows desktop -
正如@dxiv 所说,firefox 的实例造成了麻烦。所以我只是确保没有运行此浏览器的实例。
标签: c# windows winapi createprocess