2013-04-15 12 views
8

Piszę aplikację zdalnego pulpitu, taką jak TeamViewer w C++ na Windows 7 (x64) i Windows 8 (x64).Jak przełączyć proces między domyślnym pulpitem a pulpitem Winlogon?

1. Co sprawiło, że zatrzymany

I wprowadziły wejście myszki i klawiatury przy użyciu SendInput(). Zauważyłem, że SendInput() działał idealnie, gdy proces był uruchamiany pod numerem winsta0\desktop. Ale po tym, jak użytkownik zablokował komputer lub uruchomiono wygaszacz ekranu, nie zadziałało.

Jeśli uruchomię proces pod numerem winsta0\winlogon, SendInput() nie działa pod numerem winsta0\default.

2. Jakie Próbowałem

Próbowałem, używając SetThreadDesktop(), aby przełączyć się proces od winsta0\desktop do winsta0\winlogon, ale mam błąd 170: „Żądane zasoby są w użyciu”, a ja stucked.

3. Co chcę wiedzieć

zauważyłem, że TeamViewer ma proces o nazwie TeamViewer_Desktop.exe który może kontrolować myszki i klawiatury pod Winlogon, domyślnie i ekranu. Jak to robi?

Czy możesz podać kod, który pomoże mi zrozumieć, jak rozwiązać moje pytanie?

Chcę wiedzieć ** w jaki sposób mogę zmienić sposób przełączania aplikacji między domyślnym pulpitem a pulpitem Winlogon. Dzięki temu mogę sterować myszą i klawiaturą na zabezpieczonym pulpicie bez tworzenia kolejnego procesu działającego pod kontrolą winlogon.exe.

+0

Jeśli chcesz przykładowy kod, należy użyć jeden z projektów open source VNC. Pytanie o kod demo tutaj wymaga zbyt wiele. To pytanie jest zbyt szerokie. –

+0

@DavidHeffernan Dziękuję za porady. Spróbuję przeczytać i znaleźć kod mojego pytania z projektów VNC o otwartym kodzie źródłowym. I zredagowałem moje pytanie i jasno je sformułowałem. – Leon

Odpowiedz

7

Dobrze zrobiłeś: SetThreadDesktop jest poprawny. Błąd mówi, że niektóre zasoby są otwarte na bieżącym pulpicie, takie jak okno, i które uniemożliwiają przełączanie. Jeśli próbowałeś stworzyć minimalną wersję testową (jak masz zrobić, kiedy zadajesz pytania tutaj!), To byś to odkrył.

Wycinaj części programu, aż znajdziesz fragment, który uniemożliwia przełączanie pulpitu. Niektóre interfejsy API systemu Windows są nieprzyjemne i uniemożliwiają przełączanie pulpitu, dlatego muszą być wywoływane w dedykowanym wątku.

+1

Masz rację! Wielkie dzięki! Próbowałem i wyprodukowałem minimalną próbę. Tworzę projekt konsoli i testuję kod SetThreadDesktop(). To działa! W następnym kroku dowiem się, co zapobiega sukcesowi SetThreadDesktop() w projekcie WinForm. – Leon

+0

@Leon, próbowałem tego w Delphi ([pytanie tutaj] (http://stackoverflow.com/questions/41008676/how-make-setthreaddesktop-api-work-from---onsonsole-application)), ale bez powodzenia :-(Niektóre sugestie? – Saulo

+0

Nie używaj niczego od user32.dll przed wywołaniem SetThreadDesktop. –

4

Jak powiedział @NicholasWilson, SetThreadDesktop() to poprawny sposób przełączania procesu między domyślnym pulpitem a pulpitem winlogon.

Błąd 170, "Żądany zasób jest w użyciu", wystąpił, ponieważ wywołałem MessageBox() przed wywołaniem SetThreadDesktop(). Również wywołanie CreateWindow() może spowodować błąd.

Myślę, że każda funkcja związana z tworzeniem GUI wywołanym przed wywołaniem SetThreadDesktop() może spowodować błąd. Jeśli chcesz pomyślnie wywołać SetThreadDesktop(), musisz się upewnić, że nie wywołasz żadnej funkcji tworzenia GUI przed wywołaniem SetThreadDesktop().

Kod

kod tutaj jest jak przełączyć proces do określonego komputera.

Zastosowanie:SetWinSta0Desktop(TEXT("winlogon")), SetWinSta0Desktop(TEXT("default"))

SetWinSta0Desktop() funkcja:

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() funkcja:

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); 
    } 
} 
Powiązane problemy