Як визначити, який процес працює в якому вікні в Mac OS X?


28

Мені хотілося б знати, чи можна визначити, який процес відповідає за створення / управління вікном у Mac OS X.

Наприклад, коли запускаються кілька екземплярів програми, як я можу отримати ідентифікатор процесу (PID), відповідний одному конкретному вікну? Або якщо є модальне діалогове вікно без заголовка, як я можу отримати PID його власника?

Я знаю, що в Windows можливо за допомогою інструмента Sysinternals Suite , який забезпечує спосіб пошуку бібліотеки, яка працює з деякими даними.

Я шукаю механізм, подібний до того, який з’являється в цьому пості .

У цьому випадку, використовуючи Sysinternals Suite (та Провідник процесів), вони виявили, яка DLL / програма використовує веб-камеру, шукаючи DLL або підрядку (у цьому випадку, використовуючи фізичну назву пристрою).

Отже, чи є якийсь механізм чи програма, чи є у вас ідеї про те, як шукати щось подібне для Mac OS X? Як я можу визначити, який процес запустив вікно?


“… Який процес показує, яке вікно…” Це заплутано в порівнянні з вашим прикладом Windows “… яка DLL / програма використовувала веб-камеру, шукаючи DLL або підрядку”. Чи можете ви редагувати своє запитання для уточнення.
JakeGould

1
Деякі процеси працюють без вікон, а можливо навіть без керуючого терміналу.
Василь Старинкевич

Відповіді:


22

Я використав сценарій Python . Це не дурно, але працює для мене досить добре.

Я не переспівую повний сценарій без дозволу, але ось короткий опис: він використовує CGWindowListCopyWindowInfo, який імпортується з Quartz, для збору інформації про вікно з системи, потім просить користувача перемістити потрібне вікно, потім знову збирає інформацію про вікно та показує інформація для тих, хто змінився. Додана інформація включає ідентифікатор процесу, як kCGWindowOwnerPID.

Ось код:

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

Сценарій друкує інформацію для вікна, яке змінило положення протягом 5-секундного інтервалу. Отже, результат виглядає так:

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 на!
І.Кугіль

@echo on - Я не впевнений, як застосувати те, що показує цей сайт, ви могли б розробити?
C_K

Схоже, посилання на скрипт python мертве. Я вважаю, що я знайшов ту саму публікацію на новому сайті блогу тут: cadebaba.blogspot.com/2014/04/…
Марк Ебберт

Це дивовижний сценарій. Це допомогло моєму знайти неприємне програмне забезпечення, яке я не міг ідентифікувати.
Самвел Аванесов

НІСКО !! Це дійсно чистий правильний спосіб виявлення та видалення зловмисного програмного забезпечення, яке спливає вікна сповіщень. Набагато краще, ніж установка та запуск антивірусної програми, яка, хто знає, сама по собі може бути шкідливим програмним забезпеченням.
Джеррі Крінок

15

Я зробив інструмент на ім’я 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
    ... ...

Тоді ви можете використати grep, щоб знайти під вашого вікна.

Ось вихідний код сценарію:

#!/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!
Хей

10

@kenorb Я комбінував ваші 2 версії сценарію, в основному він працює як перший, показуючи різницю, але форматування - від другого. Також якщо вікна немає на екрані - воно не друкується, інакше воно дає занадто багато сміття

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)

Фантастичний. На крок ближче до xkill для Mac!
Майкл Фокс

2
з трішкиpip install pyobjc-framework-Quartz
CupawnTae

Зауважте, що сценарій не працює на 100% при налаштуваннях на декілька моніторів. Якщо запустити це в терміналі на одному екрані, а потім перемістити вікно на інший екран, ви побачите багато вікон, перелічених у розл. Всі вони, здається, є системними вікнами та піктограмами у рядку меню тощо. Найкраще перемістити термінал та вікно таємниць на один і той же екран перед запуском.
DaveBurns
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.