5

我有一些代码可以创建一个新桌面并在该桌面中启动一个进程。

一些选择 Windows XP 机器,当这段代码运行时,我可以看到它切换到新桌面并启动该过程,但几乎立即,桌面切换回正常桌面。

这段代码在大约 98% 的机器上运行良好,我似乎无法找出任何原因导致它在其他机器上不起作用。

应该SwitchDesktop靠谱吗?我可以挂钩SwitchDesktop可能从另一个应用程序调用的调用吗?

我的代码:

int DLL_EXP_IMP WINAPI Process_Desktop(char *szDesktopName, char *szPath)
{
    HDESK   hOriginalThread;
    HDESK   hOriginalInput;
    HDESK   hNewDesktop;
    int procSuccess;
    // Save original ...
    hOriginalThread = GetThreadDesktop(GetCurrentThreadId());
    hOriginalInput = OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);

    // Create a new Desktop and switch to it
    hNewDesktop = CreateDesktop(szDesktopName, NULL, NULL, DF_ALLOWOTHERACCOUNTHOOK, GENERIC_ALL, NULL);
    SetThreadDesktop(hNewDesktop);
    SwitchDesktop(hNewDesktop);

    // This call blocks until the process exits, and is confirmed to work on the affected machines
    procSuccess = StartProcess(szDesktopName, szPath);

    // Restore original ...
    SwitchDesktop(hOriginalInput);
    SetThreadDesktop(hOriginalThread);

    // Close the Desktop
    CloseDesktop(hNewDesktop);

    if (procSuccess != 0)
    {
        return procSuccess;
    }
    else
    {
        return 0;
    }
}
4

3 回答 3

1

SwitchDesktop 失败(大部分时间是访问被拒绝,或者由于另一个桌面中的现有句柄而出现错误 170),或者有另一个程序切换回默认桌面。

我知道雅虎工具栏做到了这一点(版本 5-6-7,也许他们现在已修复);KABE4.exe(我不知道这是什么)、Acronis 程序(备份调度程序、AFAIK)等等。所有这些都在没有任何用户干预的情况下调用 SwitchDesktop(一个很大的禁忌)。

我为雅虎工具栏证明了这一点;通过将另一个 dll 注入 yt.dll(由 IE 加载)并从挂钩调用返回 FALSE 来挂钩 SwitchDesktop 解决了我的问题。

大约 2 年前发送给雅虎的概念证明至今仍未得到答复。

于 2013-10-25T16:45:09.973 回答
1

我的猜测是 SetThreadDesktop() 失败。

来自 MSDN:“如果调用线程在其当前桌面上有任何窗口或挂钩,则 SetThreadDesktop 函数将失败(除非 hDesktop 参数是当前桌面的句柄)。”

您提到 StartProcess() 会阻塞,直到进程终止。因此,没有人引用新桌面,因此桌面将消失。

您可能需要考虑在 C++ 中包装易出错的系统调用——在它们失败时抛出异常。当然,CreateDesktop/CloseDesktop 对属于 C++ 资源包装器。这是2013年!

于 2013-06-21T16:11:19.793 回答
0

在您发布的代码中,有那部分:

// Create a new Desktop and switch to it
    hNewDesktop = CreateDesktop(szDesktopName, NULL, NULL, DF_ALLOWOTHERACCOUNTHOOK, GENERIC_ALL, NULL);
    SetThreadDesktop(hNewDesktop);
    SwitchDesktop(hNewDesktop);

    // This call blocks until the process exits, and is confirmed to work on the affected machines
    procSuccess = StartProcess(szDesktopName, szPath);

    // Restore original ...
    SwitchDesktop(hOriginalInput);
    SetThreadDesktop(hOriginalThread);

您对 StartProcess 函数的调用介于对 SwitchDesktop 的两次调用之间。此代码中没有函数停止(暂停)或延迟正在运行的代码、线程或进程,因此当您切换到 hNewDesktop 时,您会立即切换回 hOriginalInput。您应该在调用 StartProcess 之后和第二次调用 SwitchDesktop 之前添加一个带有结束条件的 while 循环。我不知道 while 循环的结束条件是什么,但你知道,你会选择,毕竟这是你的程序。

例如,您可以使用 GetKeyState 或 GetAsyncKeyState 函数来检查键盘上按下了哪个键,并将其作为 while 循环的结束条件,因此当您按下该键时,您将立即返回原来的桌面!

于 2014-08-09T19:25:57.453 回答