Wie erkenne ich, welcher Prozess in welchem ​​Fenster von Mac OS X ausgeführt wird?

28

Ich möchte wissen, ob es möglich ist, zu ermitteln, welcher Prozess für das Erstellen / Verwalten eines Fensters in Mac OS X verantwortlich ist.

Wie kann ich beispielsweise beim Starten mehrerer Instanzen einer Anwendung die Prozess-ID (PID) ermitteln, die einem bestimmten Fenster entspricht? Oder wenn es ein modales Dialogfenster ohne Titel gibt, wie kann ich die PID seines Besitzers erhalten?

Ich weiß, dass es unter Windows möglich ist, mit dem Sysinternals Suite- Tool nach einer Bibliothek zu suchen, die mit einigen Daten ausgeführt wird.

Ich suche nach einem ähnlichen Mechanismus wie in diesem Blogpost .

In diesem Fall haben sie mithilfe von Sysinternals Suite (und Process Explorer) herausgefunden, welche DLL / welches Programm die Webcam verwendet, indem sie nach einer DLL oder einem Teilstring gesucht haben (in diesem Fall anhand des physischen Namens des Geräts).

Gibt es einen Mechanismus oder ein Programm oder haben Sie eine Idee, wie Sie nach etwas Ähnlichem für Mac OS X suchen können? Wie kann ich erkennen, welcher Prozess ein Fenster gestartet hat?

I.Cougil
quelle
"... welcher Prozess zeigt welches Fenster an ..." Dies ist verwirrend im Vergleich zu Ihrem Windows-Beispiel für "... welche DLL / welches Programm die Webcam bei der Suche nach einer DLL oder einer Teilzeichenfolge verwendet hat". Können Sie Ihre Frage zur Klärung bearbeiten?
JakeGould
1
Einige Prozesse werden ohne Fenster und möglicherweise sogar ohne steuerndes Terminal ausgeführt.
Basile Starynkevitch

Antworten:

22

Ich habe das Python-Skript verwendet . Es ist nicht narrensicher, aber es funktioniert ziemlich gut für mich.

Ich werde das vollständige Skript nicht ohne Erlaubnis erneut veröffentlichen, aber hier ist eine Zusammenfassung: Es verwendet CGWindowListCopyWindowInfo, was importiert Quartzwird, um Fensterinformationen vom System zu sammeln, fordert den Benutzer dann auf, das gewünschte Fenster zu verschieben, sammelt dann Fensterinformationen erneut und zeigt Infos für diejenigen, die sich geändert haben. Die ausgelesenen Informationen enthalten die Prozess-ID as kCGWindowOwnerPID.

Hier ist der Code:

#!/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'

Das Skript druckt Informationen für das Fenster, dessen Position sich innerhalb von 5 Sekunden geändert hat. Die Ausgabe sieht also so aus:

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 auf
quelle
Nun, es ist nicht genau das, wonach ich gesucht habe, aber es ist ein guter Ausgangspunkt. Vielen Dank an @echo!
I.Cougil,
@echo on - Ich bin mir nicht sicher, wie ich das anwenden soll, was diese Site zeigt. Könnten Sie das näher erläutern?
C_K
Der Link zum Python-Skript scheint nicht mehr zu funktionieren. Ich glaube, ich habe den gleichen Beitrag auf einer neuen Blog-Site hier gefunden: cadebaba.blogspot.com/2014/04/…
Mark Ebbert
Dies ist ein erstaunliches Skript. Es half mir, böse Software zu finden, die ich nicht identifizieren konnte.
Samvel Avanesov
NETT!! Dies ist in der Tat die saubere und korrekte Methode zum Identifizieren und Entfernen von Malware, durch die Warnfenster angezeigt werden. Viel besser, als ein Antivirenprogramm zu installieren und auszuführen, das, wer weiß, selbst Malware sein kann.
Jerry Krinock
15

Ich habe ein Werkzeug namens gemacht 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
    ... ...

Dann können Sie grep verwenden, um die pid Ihres Fensters zu finden.

Hier ist der Quellcode des Skripts:

#!/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
quelle
Funktioniert perfekt. Danke fürs Teilen @ osexp2003!
Hay
10

@kenorb Ich habe Ihre beiden Versionen des Skripts kombiniert. Im Grunde funktioniert es wie die erste, zeigt jedoch einen Unterschied, aber die Formatierung stammt von der zweiten. Auch wenn das Fenster nicht auf dem Bildschirm angezeigt wird, wird es nicht gedruckt, da sonst zu viel Müll entsteht

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
quelle
Fantastisch. Ein Schritt näher an xkill für Mac!
Michael Fox
2
mit ein bisschenpip install pyobjc-framework-Quartz
CupawnTae 20.11.18
Beachten Sie, dass das Skript bei Konfigurationen mit mehreren Monitoren nicht zu 100% funktioniert. Wenn Sie dies in einem Terminal auf einem Bildschirm ausführen und dann das Fenster auf einem anderen Bildschirm verschieben, werden in der Differenz viele Fenster aufgelistet. Bei allen handelt es sich anscheinend um Systemfenster und Symbole in der Menüleiste usw. Am besten verschieben Sie Ihr Terminal und das Mystery-Fenster vor der Ausführung auf denselben Bildschirm.
DaveBurns