Как определить, какой процесс запущен, какое окно в Mac OS X?

28

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

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

Я знаю, что в Windows это возможно с помощью инструмента Sysinternals Suite , который предоставляет способ поиска библиотеки, работающей с некоторыми данными.

Я ищу механизм, похожий на тот, который появляется в этом посте .

В этом случае, используя Sysinternals Suite (и Process Explorer), они обнаружили, какая DLL / программа использовала веб-камеру, выполнив поиск DLL или подстроки (в данном случае, используя физическое имя устройства).

Так есть ли какой-нибудь механизм или программа, или у вас есть идеи о том, как искать что-то подобное для Mac OS X? Как я могу определить, какой процесс запустил окно?

I.Cougil
источник
«… Какой процесс показывает, какое окно…» Это сбивает с толку по сравнению с вашим примером 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, чтобы найти pid вашего окна.

Вот исходный код скрипта:

#!/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
источник
Работает отлично. Спасибо, что поделились @ osexp2003!
Hay
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)
Ruzard
источник
Фантастика. На шаг ближе к xkill для Mac!
Майкл Фокс
2
с небольшимpip install pyobjc-framework-Quartz
CupawnTae
Обратите внимание, что скрипт не работает на 100% с настройками нескольких мониторов. Если вы запустите это в терминале на одном экране, а затем переместите окно на другом экране, вы увидите много окон, перечисленных в diff. Все они кажутся системными окнами и значками в строке меню и т. Д. Перед запуском лучше всего переместить свой терминал и окно-загадку на один и тот же экран.
Дейв Бернс