SwitchDesktop可以暂时工作,但过了一会儿就会切换回来

时间:2012-09-25 13:11:02

标签: c++ windows winapi

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

一些选择的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;
    }
}

3 个答案:

答案 0 :(得分:1)

我的猜测是SetThreadDesktop()失败了。

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

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

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

答案 1 :(得分:1)

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

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

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

近两年前向雅虎发送的概念证据至今仍未得到回应。

答案 2 :(得分: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循环的结束条件,因此当您按下该键时,您将立即返回原始键桌面!