如何在默认桌面和 Winlogon 桌面之间切换进程?

Posted

技术标签:

【中文标题】如何在默认桌面和 Winlogon 桌面之间切换进程?【英文标题】:How to switch a process between default desktop and Winlogon desktop? 【发布时间】:2013-04-15 08:22:52 【问题描述】:

我正在 Windows 7 (x64) 和 Windows 8 (x64) 上用 C++ 编写一个远程桌面应用程序,例如 TeamViewer

1.是什么让我卡住了

我已经使用 SendInput() 实现了鼠标输入和键盘输入。我发现当进程在winsta0\desktop 下运行时,SendInput() 工作得很好。但是在用户锁定计算机或启动屏保后,它就不起作用了。

如果我在winsta0\winlogon 下运行进程,SendInput()winsta0\default 下不起作用。

2。我尝试过的

我尝试使用 SetThreadDesktop() 将进程从 winsta0\desktop 切换到 winsta0\winlogon,但出现错误 170:“请求的资源正在使用中”,我卡住了。

3.我想知道的

我注意到 TeamViewer 有一个名为TeamViewer_Desktop.exe 的进程,可以在 Winlogon、Default 和 Screensaver 下控制鼠标和键盘。它是怎么做到的?

您能否提供代码以帮助我了解如何解决我的问题?

我想知道**如何让我的应用程序在默认桌面和 Winlogon 桌面之间切换。所以我可以在安全的桌面上控制鼠标和键盘,而无需创建另一个在winlogon.exe 下运行的进程。

【问题讨论】:

如果您想要示例代码,请使用开源 VNC 项目之一。在这里要求演示代码要求太多。这个问题太笼统了。 @DavidHeffernan 感谢您的建议。我将尝试从开源 VNC 项目中阅读并找出我的问题的代码。我编辑了我的问题并清楚地说明了。 【参考方案1】:

你做对了:SetThreadDesktop 是正确的。该错误告诉您,您在当前桌面上打开了一些资源,例如窗口,这会阻止您切换。如果您曾尝试制作一个最小的测试用例(正如您在这里提问时应该做的那样!),您就会发现这一点。

删除程序的某些部分,直到找到阻止您切换桌面的部分。一些 Windows API 很讨厌,会阻止您切换桌面,因此需要在专用线程中调用。

【讨论】:

你是对的!非常感谢!我已经尝试并制作了一个最小的测试用例。我创建了一个控制台项目并测试了 SetThreadDesktop() 代码。有用!下一步我会找出是什么阻止了 SetThreadDesktop() 在 winform 项目中成功。 @Leon,我已经在 Delphi (question here) 中尝试过,但没有成功:-(。一些建议? 在调用 SetThreadDesktop 之前不要使用 user32.dll 中的任何内容。【参考方案2】:

正如@NicholasWilson 所说,SetThreadDesktop() 是在默认桌面和 winlogon 桌面之间切换进程的正确方法。

出现错误 170,“请求的资源正在使用中”,因为我在调用 SetThreadDesktop() 之前调用了 MessageBox()。调用CreateWindow() 也会导致错误。

我认为在调用SetThreadDesktop() 之前调用的任何与GUI 创建相关的函数都可能导致错误。所以如果要成功调用SetThreadDesktop(),在调用SetThreadDesktop()之前一定要确保不要调用任何GUI创建函数。

代码

这里的代码是如何将进程切换到指定的桌面。

用法: SetWinSta0Desktop(TEXT("winlogon")), SetWinSta0Desktop(TEXT("default"))

SetWinSta0Desktop()函数:

BOOL SetWinSta0Desktop(TCHAR *szDesktopName)

    BOOL bSuccess = FALSE;

    HWINSTA hWinSta0 = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED);
    if (NULL == hWinSta0)  ShowLastErrorMessage(GetLastError(), TEXT("OpenWindowStation")); 

    bSuccess = SetProcessWindowStation(hWinSta0);
    if (!bSuccess)  ShowLastErrorMessage(GetLastError(), TEXT("SetProcessWindowStation")); 

    HDESK hDesk = OpenDesktop(szDesktopName, 0, FALSE, MAXIMUM_ALLOWED);
    if (NULL == hDesk)  ShowLastErrorMessage(GetLastError(), TEXT("OpenDesktop")); 

    bSuccess = SetThreadDesktop(hDesk);
    if (!bSuccess)  ShowLastErrorMessage(GetLastError(), TEXT("SetThreadDesktop")); 

    if (hDesk != NULL)  CloseDesktop(hDesk); 
    if (hWinSta0 != NULL)  CloseWindowStation(hWinSta0); 

    return bSuccess;

ShowLastErrorMessage()函数:

void ShowLastErrorMessage(DWORD errCode, LPTSTR errTitle)

    LPTSTR errorText = NULL;

    FormatMessage(
       FORMAT_MESSAGE_FROM_SYSTEM |
       FORMAT_MESSAGE_ALLOCATE_BUFFER |
       FORMAT_MESSAGE_IGNORE_INSERTS,  
       NULL,
       errCode,
       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
       (LPTSTR)&errorText,
       0,
       NULL);

    if ( NULL != errorText )
    
        WCHAR msg[512] = 0;
        wsprintf(msg, TEXT("%s:\nError Code: %u\n%s\n"), errTitle, errCode, errorText);

        LocalFree(errorText);
        errorText = NULL;

        OutputDebugString(msg);
    

【讨论】:

以上是关于如何在默认桌面和 Winlogon 桌面之间切换进程?的主要内容,如果未能解决你的问题,请参考以下文章

如何在c#中将输入发送到winlogon

如何使用 C#/pinvoke 将输入发送到 WinSta0\Winlogon 桌面

如何在 Windows 上获取 Active Desktop 类型?

Windows下的桌面之间是不是共享剪贴板?

DELPHI编写服务程序总结(在系统服务和桌面程序之间共享内存,在服务中使用COM组件)

我想问问linux怎么切换桌面