Jak rozpoznać, który proces jest uruchomiony, które okno w Mac OS X?

28

Chciałbym wiedzieć, czy można określić, który proces jest odpowiedzialny za utworzenie / zarządzanie oknem w Mac OS X.

Na przykład, gdy uruchomionych jest wiele instancji aplikacji, jak mogę uzyskać identyfikator procesu (PID) odpowiadający jednemu konkretnemu oknu? Lub jeśli istnieje modalne okno dialogowe bez tytułu, jak mogę uzyskać PID jego właściciela?

Wiem, że w systemie Windows możliwe jest użycie narzędzia Sysinternals Suite , które umożliwia wyszukiwanie biblioteki działającej z niektórymi danymi.

Szukam mechanizmu podobnego do tego, który pojawia się na tym blogu .

W tym przypadku, korzystając z Sysinternals Suite (i Process Explorer), znaleźli bibliotekę DLL / program korzystający z kamery internetowej, szukając biblioteki DLL lub podłańcucha (w tym przypadku przy użyciu fizycznej nazwy urządzenia).

Czy istnieje jakiś mechanizm lub program, czy masz pojęcie o tym, jak wyszukać coś podobnego dla Mac OS X? Jak rozpoznać, który proces uruchomił okno?

I.Cougil
źródło
„… Który proces pokazuje, które okno…” Jest to mylące w porównaniu z przykładem Windows „… która biblioteka DLL / program używała kamery internetowej, szukając biblioteki DLL lub podłańcucha”. Czy możesz edytować swoje pytanie, aby wyjaśnić.
JakeGould,
1
Niektóre procesy działają bez okien, a być może nawet bez kontrolującego terminala.
Basile Starynkevitch,

Odpowiedzi:

22

Użyłem skryptu Python . Nie jest niezawodny, ale działa całkiem dobrze dla mnie.

Nie będę ponownie publikować pełnego skryptu bez pozwolenia, ale oto podsumowanie: Używa CGWindowListCopyWindowInfo, które jest importowane Quartz, aby zebrać informacje o oknie z systemu, następnie prosi użytkownika o przeniesienie żądanego okna, a następnie ponownie zbiera informacje o oknie i pokazuje informacje dla tych, którzy się zmienili. Zrzucone informacje obejmują identyfikator procesu, as kCGWindowOwnerPID.

Oto kod:

#!/usr/bin/env python

import time
from Quartz import CGWindowListCopyWindowInfo, kCGWindowListExcludeDesktopElements, kCGNullWindowID
from Foundation import NSSet, NSMutableSet

wl1 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
print 'Move target window'
time.sleep(5)
wl2 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)

w = NSMutableSet.setWithArray_(wl1)
w.minusSet_(NSSet.setWithArray_(wl2))
print '\nList of windows that moved:'
print w
print '\n'

Skrypt drukuje informacje dla okna, które zmieniło pozycję w odstępie 5 sekund. Wynik wygląda następująco:

List of windows that moved:
{(
        {
        kCGWindowAlpha = 1;
        kCGWindowBounds =         {
            Height = 217;
            Width = 420;
            X = 828;
            Y = 213;
        };
        kCGWindowIsOnscreen = 1;
        kCGWindowLayer = 8;
        kCGWindowMemoryUsage = 406420;
        kCGWindowName = "";
        kCGWindowNumber = 77;
        kCGWindowOwnerName = UserNotificationCenter;
        kCGWindowOwnerPID = 481;
        kCGWindowSharingState = 1;
        kCGWindowStoreType = 2;
    }
)}
echo włączone
źródło
Cóż, nie było to dokładnie to, czego szukałem, ale to dobry punkt wyjścia. Dziękuję @echo dalej!
I.Cougil,
@echo on - nie jestem pewien, jak zastosować to, co pokazuje ta strona, czy mógłbyś to rozwinąć?
C_K
Wygląda na to, że łącze do skryptu python nie działa. Wydaje
Mark Ebbert,
To niesamowity scenariusz. Pomogło mi znaleźć nieprzyjemne oprogramowanie, którego nie mogłem zidentyfikować.
Samvel Avanesov
MIŁY!! Jest to rzeczywiście czysty, poprawny sposób identyfikowania i usuwania złośliwego oprogramowania, które wyskakuje w oknach ostrzegawczych. Znacznie lepiej niż instalowanie i uruchamianie programu antywirusowego, który - jak wiadomo - może być złośliwym oprogramowaniem.
Jerry Krinock
15

Zrobiłem narzędzie o nazwie lswin

$ python lswin.py

    PID WinID  x,y,w,h                  [Title] SubTitle
------- -----  ---------------------    -------------------------------------------
    169  1956 {0,-38,1280,25        }   [Window Server] Backstop Menubar
    169  1955 {0,-60,1280,22        }   [Window Server] Menubar
    169   396 {0,-38,1280,25        }   [Window Server] Backstop Menubar
    169   395 {0,-60,1280,22        }   [Window Server] Menubar
    169     6 {0,0,0,0              }   [Window Server] Cursor
    169     4 {0,22,1280,25         }   [Window Server] Backstop Menubar
    169     3 {0,0,1280,22          }   [Window Server] Menubar
    169     2 {0,0,1280,800         }   [Window Server] Desktop
    262   404 {0,-38,1280,38        }   [Google Chrome] 
    262   393 {0,0,1280,800         }   [Google Chrome] 
    262   380 {100,100,1,1          }   [Google Chrome] Focus Proxy
    ... ...

Następnie możesz użyć grep, aby znaleźć pid swojego okna.

Oto kod źródłowy skryptu:

#!/usr/bin/env python

import Quartz

#wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID)
wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)

wl = sorted(wl, key=lambda k: k.valueForKey_('kCGWindowOwnerPID'))

#print wl

print 'PID'.rjust(7) + ' ' + 'WinID'.rjust(5) + '  ' + 'x,y,w,h'.ljust(21) + ' ' + '\t[Title] SubTitle'
print '-'.rjust(7,'-') + ' ' + '-'.rjust(5,'-') + '  ' + '-'.ljust(21,'-') + ' ' + '\t-------------------------------------------'

for v in wl:
    print ( \
        str(v.valueForKey_('kCGWindowOwnerPID') or '?').rjust(7) + \
        ' ' + str(v.valueForKey_('kCGWindowNumber') or '?').rjust(5) + \
        ' {' + ('' if v.valueForKey_('kCGWindowBounds') is None else \
            ( \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('X')))     + ',' + \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Y')))     + ',' + \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Width'))) + ',' + \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Height'))) \
            ) \
            ).ljust(21) + \
        '}' + \
        '\t[' + ((v.valueForKey_('kCGWindowOwnerName') or '') + ']') + \
        ('' if v.valueForKey_('kCGWindowName') is None else (' ' + v.valueForKey_('kCGWindowName') or '')) \
    ).encode('utf8')
osexp2003
źródło
Działa świetnie. Dziękujemy za udostępnienie @ osexp2003!
Hay,
10

@kenorb Połączyłem twoje 2 wersje skryptu, w zasadzie działa jak pierwsza, pokazuje różnicę, ale formatowanie jest z drugiej. Również jeśli okno nie jest wyświetlane na ekranie - nie jest drukowane, w przeciwnym razie powoduje zbyt wiele śmieci

import Quartz
import time
from Foundation import NSSet, NSMutableSet
def transformWindowData(data):
    list1 = []
    for v in data:
        if not v.valueForKey_('kCGWindowIsOnscreen'):
            continue


        row = ( \
            str(v.valueForKey_('kCGWindowOwnerPID') or '?').rjust(7) + \
            ' ' + str(v.valueForKey_('kCGWindowNumber') or '?').rjust(5) + \
            ' {' + ('' if v.valueForKey_('kCGWindowBounds') is None else \
                ( \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('X')))     + ',' + \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Y')))     + ',' + \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Width'))) + ',' + \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Height'))) \
                ) \
                ).ljust(21) + \
            '}' + \
            '\t[' + ((v.valueForKey_('kCGWindowOwnerName') or '') + ']') + \
            ('' if v.valueForKey_('kCGWindowName') is None else (' ' + v.valueForKey_('kCGWindowName') or '')) \
        ).encode('utf8')
        list1.append(row)

    return list1;

def printBeautifully(dataSet):
    print 'PID'.rjust(7) + ' ' + 'WinID'.rjust(5) + '  ' + 'x,y,w,h'.ljust(21) + ' ' + '\t[Title] SubTitle'
    print '-'.rjust(7,'-') + ' ' + '-'.rjust(5,'-') + '  ' + '-'.ljust(21,'-') + ' ' + '\t-------------------------------------------'

    # print textList1
    for v in dataSet:
        print v;

#grab initial set
wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
wl = sorted(wl, key=lambda k: k.valueForKey_('kCGWindowOwnerPID'))

#convert into readable format
textList1 = transformWindowData(wl);

#print everything we have on the screen
print 'all windows:'
printBeautifully(textList1)

print 'Move target window'
time.sleep(5)

#grab window data the second time
wl2 = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
textList2 = transformWindowData(wl2)

#check the difference
w = NSMutableSet.setWithArray_(textList1)
w.minusSet_(NSSet.setWithArray_(textList2))

#print the difference
printBeautifully(w)
Ruzard
źródło
Fantastyczny. Krok bliżej do xkill na Maca!
Michael Fox,
2
z odrobinąpip install pyobjc-framework-Quartz
CupawnTae
Pamiętaj, że skrypt nie działa w 100% w przypadku konfiguracji z wieloma monitorami. Jeśli uruchomisz to w terminalu na jednym ekranie, a następnie przeniesiesz okno na inny ekran, zobaczysz wiele okien wymienionych na liście różnic. Wszystkie wydają się być oknami systemowymi i ikonami na pasku menu itp. Najlepiej przenieść terminal i tajemnicze okno na ten sam ekran przed uruchomieniem.
DaveBurns