2010-04-19 11 views
7

Próbuję znaleźć niezawodny sposób aktywacji/ustawić ostrość do okna zewnętrznej aplikacji przy użyciu C#. Obecnie jestem próbuje to osiągnąć za pomocą następujących wywołań API Windows:Czy istnieje niezawodny sposób aktywowania/ustawiania fokusu na okno przy użyciu C#?

SetActiveWindow(handle); 
SwitchToThisWindow(handle, true); 

Wcześniej miałam też ShowWindow(handle, SW_SHOWMAXIMIZED); przed wykonaniem drugiej 2, ale usunięto go, ponieważ był przyczyną dziwnego zachowania.

Problem z moją obecną implementacją polega na tym, że czasami fokus nie zostanie ustawiony prawidłowo. Okno stanie się widoczne, ale jego górna część będzie nadal wyszarzona, tak jakby nie była ustawiona na ostrość.

Czy istnieje sposób rzetelnego robienia tego, który działa w 100% przypadków, lub czy niespójne zachowanie jest efektem ubocznym, z którego nie mogę uciec? Daj mi znać, jeśli masz jakieś sugestie lub implementacje, które zawsze działają.

Odpowiedz

8

Trzeba użyć AttachThreadInput

Okna utworzone w różnych wątkach zazwyczaj przetwarzają dane wejściowe niezależnie od siebie. Oznacza to, że mają własne stany wejściowe (fokus, aktywny, przechwytywanie okien, stan klucza, stan kolejki itd.) I nie są zsynchronizowane z przetwarzaniem wejściowym innych wątków. Za pomocą funkcji AttachThreadInput wątek może dołączyć przetwarzanie wejściowe do innego wątku. Umożliwia to również wątkom udostępnianie ich stanów wejściowych, dzięki czemu mogą wywołać funkcję SetFocus, aby ustawić fokus klawiatury na okno innego wątku. Umożliwia to również wątkom uzyskiwanie informacji o stanie klucza. Te możliwości nie są na ogół możliwe.

Nie mam pewności co do konsekwencji zastosowania tego API z (prawdopodobnie) Windows Forms. Powiedziałem, że użyłem go w C++, aby uzyskać ten efekt. Kod byłoby coś w następujący sposób:

 DWORD currentThreadId = GetCurrentThreadId(); 
    DWORD otherThreadId = GetWindowThreadProcessId(targetHwnd, NULL); 
    if(otherThreadId == 0) return 1; 
    if(otherThreadId != currentThreadId) 
    { 
     AttachThreadInput(currentThreadId, otherThreadId, TRUE); 
    } 

    SetActiveWindow(targetHwnd); 

    if(otherThreadId != currentThreadId) 
    { 
     AttachThreadInput(currentThreadId, otherThreadId, FALSE); 
    } 

targetHwnd będąc HWND okna chcesz ustawić ostrość na. Zakładam, że możesz opracować podpisy P/Invoke, ponieważ używasz już natywnych API.

+0

Twój wpis był bardzo pouczający. Dziękuję bardzo. Spróbuję tego, gdy tylko będę miał okazję. Mam sygnatury P/Invoke, po prostu nigdy tak naprawdę nie rozumiałem pełnego obrazu za kolejkami wejściowymi, ale wyraźnie to wyraziłeś. :) – gtaborga

+0

Dziękujemy! Właśnie skończyłem pisać prostą aplikację przydatną dla skrótów klawiszowych o nazwie OpenOrSwitchTo. Zasadniczo, po wywołaniu z nazwą exe (OpenOrSwitchTo.exe c: \ path \ to \ someapp.exe), jeśli someapp.exe jest uruchomiony, przełączy się na to, aby można było zacząć go używać, a jeśli nie, to zacznie someapp .exe. Próbowałem co najmniej sześciu metod, aby przejść do okna (SwitchToThisWindow, ShowWindow, BringWindowToTop, SetForegroundWindow, itp). Twój kod w końcu zadziałał, z szybkim wołaniem do ShowWindow, aby przywrócić okno, jeśli zostało ono najpierw zminimalizowane. – iano

+0

Dla mnie (Windows 7) rozwiązanie z 'AttachThreadInput()' nie działa.Rozwiązałem problem, pozwalając, aby _inny wątek_ ustawił jego okno właściciela na _current thread_, a następnie mogę po prostu 'SetActiveWindow()'. Zobacz mój post na blogu http://code.fitness/post/2017/09/how-to-activate-window-of-foreign-process.html –

1

Jeśli to wszystko wewnętrzny w aplikacji, a następnie można uzyskać okna nadrzędnego lub to okno, iw ten sposób ją aktywować (VB przepraszam):

Public Class Form1 : Inherits Form 

    Protected Overrides Sub OnLoad(e As EventArgs) 
     Dim form2 As New Form2 
     form2.Show() 
    End Sub 
End Class 

Class Form2 : Inherits Form 

    Protected Overrides Sub OnLoad(e As EventArgs) 
     MyBase.OnLoad(e) 
     Me.Owner.Activate() 
    End Sub 
End Class 
+0

Niestety to nie jest w mojej aplikacji. Jest to zewnętrzna aplikacja, do której nie mam dostępu. Wyjaśnię w moim poście. Dzięki za twój wysiłek. – gtaborga

2
[DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool SetForegroundWindow(IntPtr hWnd); 

Ten pracował dla mnie

Powiązane problemy