10

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

1.是什么让我卡住了

我已经使用 SendInput() 实现了鼠标输入和键盘输入。我发现当进程在winsta0\desktop. 但是在用户锁定计算机或启动屏幕保护程序后,它就不起作用了。

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

2.我尝试过的

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

3. 我想知道的

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

你能提供代码来帮助我理解如何解决我的问题吗?

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

4

2 回答 2

8

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

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

于 2013-04-15T09:19:52.637 回答
3

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

发生错误 170,“请求的资源正在使用中”,因为我在调用MessageBox()之前SetThreadDesktop()调用过。调用CreateWindow()也可能导致错误。

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

代码

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

用法: 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);
    }
}
于 2013-04-17T01:35:31.600 回答