Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[70-536, #18] Le classi Process e ProcessModule, con un bel contorno di Reflection

Nel post di oggi scendiamo un po' più a basso livello nella combinata software + hardware gestito autonomamente dal sistema operativo. Vedremo infatti come ottenere l'elenco dei processi attivi (classe Process del FX) in questo momento e come leggerne le proprietà. Ogni processo inoltre è composto da uno o più moduli (class ProcessModule del FX), anch'essi dotati di proprietà specifiche.

Annuncio che per preparare questo post ho fatto anche un banale progetto con VS2005 che è disponibile per il download da questo indirizzo. E' molto semplice: contiene una sola Windows Forms (FormProcess) le cui caratteristiche essenziali sono le seguenti:

  • un oggetto TreeView e un oggetto ListView
  • i Process sono mostrati sulla TreeView come nodi a livello 0. I moduli invece come nodi a livello 1 (indentati rispetto al nodo corrispondente al processo padre)
  • la ListView serve invece a mostrare le proprietà del Process o del ProcessModule selezionato
  • c'è un membro privato Process[] currentProcess
  • c'è un metodo privato GetCurrentProcesses()
  • c'è un metodo privato writeProcessDetails(Process pc)
  • c'è un metodo privato writeProcessModuleDetails(ProcessModule md)

Come passo passo come ho implementato i metodi di cui sopra. Innanzitutto, ho gestito l'evento Load del form per lanciare il metodo GetCurrentProcesses che, come dice il nome stesso, si occupa di rilevare con il metodo statico GetProcesses() della classe Process, tutti i processi attivi in questo momento. Quindi:

private void FormProcess_Load(object sender, EventArgs e)
{
    GetCurrentProcesses();
}

private void getCurrentProcesses()
{
    
// Ottengo i Process correnti
    
currentProcess = Process.GetProcesses();
    
// Non posso fare databinding diretto tra il TreeView e
    // currentProcess, quindi ottengo un IEnumerator
    // e popolo manualmente tutti i Nodes
    
IEnumerator cycle = currentProcess.GetEnumerator();
    
while(cycle.MoveNext())
    {
        Process tmp = (Process) cycle.Current;
        TreeNode nd = 
new TreeNode(tmp.ProcessName);
        trvProcesses.Nodes.Add(nd);
    }
}

A questo punto, non ho potuto bindare la TreeView direttamente al mio oggetto currentProcess, per cui l'ho fatto a manina facendomi ritornare un IEnumerator. Per mostrare il processo sulla TreeView utilizzo la proprietà ProcessName. A questo punto, abbiamo popolato tutti i Nodes della TreeView a livello 0 con i processi. Ho gestito l'evento MouseDoubleClick, facendo in modo di aggiungere altri Nodes rispetto a quello selezionato, visualizzando i Modules associati a quel processo. Riporto qui sotto la parte di codice più interessante, per il resto vi rimando al download del mio progetto:

ProcessModuleCollection coll = currentProcess[node.Index].Modules;
IEnumerator cycle = coll.GetEnumerator();
node.Text += " [" + coll.Count + "]";

view.BeginUpdate();
while (cycle.MoveNext())
{
    ProcessModule tmp = (ProcessModule)cycle.Current;
    node.Nodes.Add(tmp.ModuleName);
}
view.EndUpdate();

In questo caso, uso la proprietà ModuleName di ogni singolo modulo.

Dove ho usato Reflection? Beh, qui!
Nel titolo di questo post ho accennato a Reflection. Se vi state chiedendo dove e perchè l'ho usata (perchè mi viene da dire Reflection al femminile?), continuate a leggere.  Restano infatti da vedere gli altri due metodi privati del form, ovvero writeProcessDetails e writeProcessModuleDetails. L'idea che volevo fare era quella di mostrare le proprietà di ogni Process e ProcessModule sulla ListView. Cioè, per spiegarmi meglio: lancio il progetto, vedo l'elenco dei processi. Quando seleziono un nodo:

  • se node.Level = 0, ho selezionato un Process e chiamo writeProcessDetails
  • se node.Level = 1, ho selezionato un ProcessModule e chiamo writeProcessModuleDetails

La ListView quindi potrebbe contenere le proprietà di entrambi gli oggetti, quindi ho scritto quanto segue.

private void writeProcessDetails(Process pc)
{
    Type type = 
typeof(Process);
    
// Ottengo l'elenco delle properties della classe Process
    
PropertyInfo[] props = type.GetProperties();
    IEnumerator cycle = props.GetEnumerator();

    
// Popolo la listview con i nomi delle property
    // ed il loro valore
    
this.lvwDetails.BeginUpdate();
    
this.lvwDetails.Items.Clear();
    
while (cycle.MoveNext())
    {
        PropertyInfo info = (PropertyInfo) cycle.Current;
        ListViewItem itm = 
new ListViewItem(info.Name);
        
try
        
{
            itm.SubItems.Add(info.GetValue(pc, 
null).ToString());
        }
        
catch { }

        
this.lvwDetails.Items.Add(itm);
    }
    
this.lvwDetails.EndUpdate();
}

Usando Reflection, appunto, ottengo un array di PropertyInfo[] ritornati dal metodo GetProperties() della classe Type. Dopo, nulla di particolare: ottengo un IEnumerator e popolo le due colonne della ListView: una per il Name ed una per il Value di ogni proprietà. Notare l'utilizzo del metodo GetValue() per ottenere il valore di ogni proprietà: ritorna un object. Quando si tratta di proprietà semplici, tutto bene, lo castiamo e siamo a posto. Se fosse una proprietà più complessa, dobbiamo usare anche il secondo parametro: non so approfondire la questione perchè non ne ho avuto bisogno. E' stato bello usare Reflection, ma ci sono ovviamente alcuni svantaggi:

  1. performance? sbaglio, o usare Reflection non è il massimo della vita?
    Diciamo che per stavolta può anche andar bene...
  2. se volessi formattare alcune delle proprietà in modo diverso, come faccio?
    Ad esempio, gli address in esadecimale...o usando font diversi...bla bla bla...
  3. se volessi mostrare alcune delle proprietà e non tutte, come faccio?
  4. a scopo didattico, non imparo i nomi delle proprietà

Altri utilizzi della classe Process
La classe Process dispone di un altro metodo statico, Start, che ci permette di avviare un nuovo processo secondo diverse modalità: il percorso del file da avviare (che può essere un eseguibile o un documento da aprire - addio, ShellExecuteEx con VB6, è stato bello, ma prima o poi doveva finire!), una classe ProcessStartInfo (davvero carina ed utile), etc. etc. Inoltre, da sapere che i metodi statici della classe Process possono lavorare anche su macchine remote - presumo avendo i permessi per farlo.

Ho aggiunto questo pezzo direttamente nell'HTML di .TEXT da FireFox: speriamo che si legga.
Il codice è disponibile qui (ProcessViewer.zip, circa 40Kb).

powered by IMHO 1.2

Print | posted on Friday, February 24, 2006 11:52 AM | Filed Under [ Esame 70-536 ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET