48 votes

Comment identifier quel processus exécute quelle fenêtre dans Mac OS X ?

J'aimerais savoir s'il est possible d'identifier le processus responsable de la création/gestion d'une fenêtre dans Mac OS X.

Par exemple, lorsque plusieurs instances d'une application sont lancées, comment puis-je obtenir l'ID du processus (PID) correspondant à une fenêtre spécifique ? Ou encore, s'il existe une fenêtre de dialogue modale sans titre, comment puis-je obtenir le PID de son propriétaire ?

Je sais que sous Windows, il est possible d'utiliser la fonction Sysinternals Suite qui permet de rechercher une bibliothèque fonctionnant avec certaines données.

Je cherche un mécanisme similaire à celui qui apparaît dans le document ce billet de blog .

Dans ce cas, en utilisant Sysinternals Suite (et Process Explorer), ils ont trouvé quelle DLL/quel programme utilisait la webcam en recherchant une DLL ou une sous-chaîne (dans ce cas, en utilisant le nom physique du périphérique).

Existe-t-il un mécanisme ou un programme, ou avez-vous une idée sur la façon de rechercher quelque chose de similaire pour Mac OS X ? Comment puis-je identifier le processus qui a lancé une fenêtre ?

35voto

Kit Sunde Points 2829

J'ai utilisé ce Python 2 script . Cette méthode n'est pas infaillible, mais elle fonctionne assez bien pour moi.

Voici un résumé de ce qu'il fait : il utilise CGWindowListCopyWindowInfo qui est importé de Quartz L'utilisateur doit ensuite déplacer la fenêtre souhaitée, puis collecter à nouveau les informations sur la fenêtre et afficher les informations sur celles qui ont été modifiées. Les informations récupérées comprennent l'identifiant du processus, en tant que kCGWindowOwnerPID .

Voici le 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'

Le script script imprime des informations sur la fenêtre qui a changé de position dans un intervalle de 5 secondes. La sortie ressemble donc à ceci :

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;
    }
)}

30voto

osexp2003 Points 538

J'ai créé un outil appelé 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
    ... ...

Vous pouvez ensuite utiliser grep pour trouver le pid de votre fenêtre.

Voici le code source du script :

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

12voto

Ruzard Points 221

@kenorb J'ai combiné vos 2 versions du script, en gros ça fonctionne comme la première, en montrant la différence mais le formatage est celui de la seconde. De plus, si la fenêtre n'est pas à l'écran, elle n'est pas imprimée, sinon il y a trop de déchets.

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)

6voto

Zohar81 Points 211

Il existe un outil OS convivial pour inspecter chaque fenêtre qui fournit des informations complètes en plus du processus connexe, comme la hiérarchie du code d'origine : il se trouve sous Xcode Developer Tools, et s'appelle Accessibility Inspector

4voto

Federico Points 300

Vous pouvez utiliser le Automator.app pour cela :

  1. Démarrer Automator (dans le type spotlight Automator.app + Enter )
  2. Créer un nouveau flux de travail.
  3. Dans le menu, sélectionnez Flux de travail > Enregistrer (ou cliquez sur le bouton [Enregistrer] dans la barre d'outils).
  4. Interagissez avec la fenêtre que vous souhaitez inspecter, puis cliquez sur le bouton [Stop] dans la barre d'outils d'enregistrement. ( Si le système vous demande s'il manque un accès à l'accessibilité, accordez-le dans les paramètres du système. )
  5. Faites glisser les étapes enregistrées qui vous intéressent à partir de la fenêtre Watch Me Do vers le panneau vide à droite (un bouton plus apparaît pendant le déplacement). INDICE : Vous pouvez également sélectionner toutes les étapes et les faire glisser ensemble afin de créer un seul script.
  6. Inspectez l'AppleScript généré pour obtenir les détails dont vous avez besoin.

NOTE : Vous pouvez utiliser cette méthode pour générer du code AppleScript pour localiser des fenêtres, des boîtes de dialogue, définir du texte, cliquer sur des boutons, etc.

Voici un exemple exemple vidéo pour l'enregistrement des actions de la souris.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X