Mac OS Xでどのプロセスがどのウィンドウを実行しているかを識別する方法は?


28

Mac OS Xでウィンドウの作成/管理を担当するプロセスを特定できるかどうか知りたいのですが。

たとえば、アプリケーションの複数のインスタンスが開始された場合、特定の1つのウィンドウに対応するプロセスID(PID)を取得するにはどうすればよいですか?または、タイトルのないモーダルダイアログウィンドウがある場合、その所有者のPIDを取得するにはどうすればよいですか?

Windows では、一部のデータで実行されているライブラリを検索する方法を提供するSysinternals Suiteツールを使用できることがわかっています。

私はこのブログ投稿に登場するメカニズムに似たメカニズムを探しています。

この場合、Sysinternals Suite(およびProcess Explorer)を使用して、DLLまたはサブストリング(この場合はデバイスの物理名を使用)を検索することで、Webカメラを使用しているDLL /プログラムを見つけました。

それでは、メカニズムやプログラムはありますか、それともMac OS Xに似たものを検索する方法について何か考えがありますか?どのプロセスがウィンドウを起動したかを特定するにはどうすればよいですか?


「…どのプロセスがどのウィンドウを示しているか…」これは、「…DLLまたはサブストリングを検索してWebカメラを使用しているDLL /プログラム」のWindowsの例と比較すると混乱します。
JakeGould

1
一部のプロセスは、ウィンドウなしで、おそらく制御端末なしでも実行されています。
バジルStarynkevitch

回答:


22

Pythonスクリプトを使用しました。それは絶対確実ではありませんが、私にとってはかなりうまく機能します。

完全なスクリプトを許可なしに再投稿することはしませんが、概要は次のとおりです:CGWindowListCopyWindowInfoからインポートされるを使用Quartzして、システムからウィンドウ情報を収集し、目的のウィンドウを移動するようにユーザーに要求してから、ウィンドウ情報を再度収集し、表示します変更されたものの情報。ダンプされる情報には、プロセスIDが含まれ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 onありがとうございます!
I.Cougil

@echo on-そのサイトが示すものをどのように適用するかわからない、詳しく説明してもらえますか?
C_K

pythonスクリプトへのリンクが死んでいるようです。新しいブログサイトで同じ投稿を見つけたと思います。cadebaba.blogspot.com
Mark Ebbert

これは素晴らしいスクリプトです。見つけられない厄介なソフトウェアを見つけるのに役立ちました。
サンベルアヴァネソフ

ナイス!! これは確かに、警告ウィンドウをポップアップ表示するマルウェアを識別して削除するためのクリーンで正しい方法です。それ自体がマルウェアである可能性のあるウイルス対策プログラムをインストールして実行するよりもはるかに優れています。
ジェリークリノック

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を共有していただきありがとうございます!
ヘイ

10

@kenorb 2つのバージョンのスクリプトを組み合わせたところ、基本的には最初のバージョンと同様に機能し、違いを示していますが、フォーマットは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)

素晴らしい。Macのxkillに一歩近づいた!
マイケルフォックス

2
少しでpip install pyobjc-framework-Quartz
CupawnTae

マルチモニター設定では、スクリプトが100%動作しないことに注意してください。ある画面上の端末でこれを実行し、別の画面でウィンドウを移動すると、差分に多くのウィンドウがリストされます。それらはすべてシステムウィンドウやメニューバーのアイコンなどのようです。実行する前に端末とミステリーウィンドウを同じ画面に移動するのが最善です。
デイブバーンズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.