Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Guida al Visual Basic .NET - Lavorare con i processi

Guida al Visual Basic .NET

Capitolo 86° - Lavorare con i processi

<< Precedente Prossimo >>

Premessa: Se non vi ricordate, o se non sapete, cos'è un processo, vi rimando alla prima lezione sulla Reflection.

La classe Process

La classe che contiene tutte le informazioni su un processo è Process. Ecco una lista dei suoi membri più significiativi:

  • BasePriority : restituisce un numero intero che identifica la priorità di un processo. I valori che può assumere sono: 4 (solo per il ciclo Idle del sistema), 8 (priorità normale), 13 (priorità alta) e 24 (molto alta, usata per le applicazioni in tempo reale). La priorità di ciuascun processo influenza la quantità di tempo macchina che il processore gli concede
  • Close() : chiude il processo e rilascia le risorse ad esso associate
  • CloseMainWindow() : chiude il processo comunicando alla sua finestra principale di chiudersi. Funziona solo se tale processo dispone di un'interfaccia grafica qualsiasi
  • EnableRaisingEvent : determina se l'oggetto Process debba generare un evento quando viene chiuso. In questo modo si può monitorare un processo e visualizzare informazioni e messaggi alla sua chiusura
  • ExitCode : restituisce il codice di chiusura del processo (questa informazione, ad esempio, può essere chiamata quando il processo genera l'evento Exited per sapere se ha dato buoni risultati oppure no). Si può pensare al processo anche come a una funzione: il sistema operativo gli passa degli argomenti (da linea di comando) e il processo restituisce un codice intero che determina il risultato delle sue operazioni. Questo codice viene determinato dallo stesso programmatore che ha scritto il programma, ed generalmente è 0 quando il processo ha dato esiti positivi (chi sa il C conosce bene il return 0 finale di Main). Se si tenta di accedere a questa proprietà prima della chiusura, verrà generato un errore
  • ExitTime : restituisce la data e l'ora esatta della chiusura del processo. Anche questa proprietà è molto utile per monitorare i processi
  • Handle : restituisce l'indirizzo di memoria del processo, sottoforma di puntatore a intero (IntPtr)
  • HandleCount : ottiene il numero di handles aperti dal processo (questo numero potrebbe anche corrispondere al numero di finestre aperte, dato che ogni finestra ha un proprio handle
  • HasExited : restituisce True se il processo è stato chiuso, altrimenti False
  • Get... : analizzerò le funzioni che iniziano per "Get" a parte
  • Id : ottiene l'identificativo univoco del processo, che non è altro che un Int32. Questo numero può essere utile nell'uso di altre funzioni, come ad esempio GetProcessesById
  • Kill() : ferma immediatamente il processo. È più brutale di Close
  • MachineName : nome della macchina sulla quale il processo è in esecuzione. Generalmente restituisce il nome del computer stesso, ma può cambiare ad esempio se si usa una macchina virtuale
  • MainModule : restituisce un oggetto System.Diagnostics.ProcessModule che identifica il modulo principale del processo. Con modulo si intende l'assembly dal quale il programma è stato fatto partire. I membri che questo oggetto espone sono:
    • BaseAddress : restituisce l'indirizzo di memoria (IntPtr) all'inizio del quale il modulo è stato caricato. Ad esempio, in un'applicazione console, questa proprietà restituisce l'indirizzo di memoria di Module1
    • EntryPointAddress : restituisce l'indirizzo di memoria in cui è collocato l'entry point, ossia il metodo principale, da cui il programma è stato avviato. Ad esempio, in un'applicazione console, questa proprietà restituisce l'indirizzo della procedura Main
    • FileName : restituisce il nome del file dal quale è stato caricato il modulo, ossia il percorso su disco del programma
    • FileVersionInfo : restituisce una caterva di informazioni sulla versione dell'eseguibile. Non sto neanche ad analizzare tutti i suoi membri
    • ModuleMemorySize : restituisce la quantità di memoria, in bytes, che il modulo occupa
    • ModuleName : nome del modulo
  • MainWindowHandle : handle della finestra principale. Si tratta dello stesso handle ottenuto con EnumDesktopWindows nel capitolo precedente
  • MainWindowTitle : titolo della finestra principale. Si tratta dello stesso titolo ottenuto con GetWindowText nel capitolo precedente
  • Modules : restituisce una collezione di tutti i moduli caricati dal processo
  • PriorityClass : come BasePriority restituisce la priorità del processo, ma attraverso un enumeratore. Può assumere i seguenti valori: Idle (ciclo Idle del sistema), BelowNormal (bassa), Normal (normale), AboveNormal (alta), High (altissima), RealTime (rappresenta il maggior valore di priorità possibile: un processo con priorità RealTime ha quasi il 100% di tempo macchina)
  • PrivilegedProcessorTime : restituisce un oggetto TimeSpan che indica quanto tempo il processo ha passato ad eseguire del codice nel sistema operativo
  • ProcessName : nome del processo
  • Responding : restituisce False se il processo non risponde ai comandi, altrimenti True
  • Start / StartInfo : analizzerò questi due membri in seguito
  • Threads : restituisce una collezione di ProcessThread che rappresentano tutti i thread aperti dal processo. Ogni oggetto della collezione espone i seguenti membri:
    • BasePriority : priorità di base del thread, espressa tramite un numero
    • CurrentPriority : priorità corrente del thread. Questa proprietà esiste poiché il thread può cambiare la sua priorità
    • Id : restituisce l'identificatore univoco del thread (simile a Process.Id)
    • IdealProcess : determina l'indice del processore sul quale il thread verrebbe eseguito in maniera ottimale. Vale solo per computer multiprocessore
    • PriorityBoostEnabled : determina se il thread può ricevere un aumento di priorità quanto la sua finestra riceve il focus, ossia viene selezionata dall'utente
    • PrivilegedProcessorTime : restituisce un oggetto TimeSpan che indica quanto tempo il thread ha passato ad eseguire del codice nel sistema operativo
    • StartAddress : restituisce l'indirizzo di membria del metodo principale di questo thread
    • StartTime : restituisce la data e l'ora esatta in cui il thread è stato avviato
    • ThreadState : stato del thread
    • TotalProcessorTime : restituisce un oggetto TimeSpan che indica da quanto tempo il thread è attivo
    • UserProcessorTime : restituisce un oggetto TimeSpan che indica quanto tempo il thread ha passato ad eseguire del codice all'interno dell'applicazione
  • TotalProcessorTime : restituisce un oggetto TimeSpan che indica da quanto tempo il processo è attivo
  • UserProcessorTime : restituisce un oggetto TimeSpan che indica quanto tempo il processo ha passato ad eseguire del codice all'interno dell'applicazione

 

Ottenere i processi in esecuzione

La classe process espone anche quattro funzioni statiche che permettono di ottenere un array dei processi in esecuzione, basandosi su determinati parametri. Ad esempio, Process.GetCurrentProcess restituisce il processo attualmente in esecuzione, e perciò quello associato direttamente all'applicazione. Process.GetProcess ottiene invece un array contenente tutti i processi attivi sul computer. Invece, Process.GetProcessesByName("nome") restituisce un array di tutti i processi con dato nome, dove tale nome non è altero che il nome dell'eseguibile dal quale sono partiti, ma senza l'estensione. Ad esempio Process.GetProcessesByName("explorer") restituisce un solo processo, "explorer.exe", che costituisce il programma principale dell'interfaccia di windows. In ultimo, Process.GetProcessById(id) ottiene un processo con dato id. Nell'esempio che segue, si chiede all'utente di immettere il nome di un processo e, se ne esiste un con quel nome, il programma visualizza tutte le informazioni possibili su di esso, usando le proprietà spiegate nel paragrafo precedente:

Module Module1
    'Ottiene tutte le informazioni possibili su un modulo
    Public Sub ScanModule(ByVal M As ProcessModule)
        Console.WriteLine("    Nome modulo: {0}", M.ModuleName)
        Console.WriteLine("    Handle: {0:X8}", M.BaseAddress.ToInt32)
        Console.WriteLine("    Handle del metodo principale: {0:X8}", _ 
            M.EntryPointAddress.ToInt32)
        Console.WriteLine("    Memoria occupata: {0:N0} bytes", _ 
            M.ModuleMemorySize)
        Console.WriteLine("    Informazioni versione del programma:")
        With M.FileVersionInfo
            Console.WriteLine("      Nome file: {0}", .FileName)
            Console.WriteLine("      Versione file: {0}", .FileVersion)
            Console.WriteLine("      Descrizione file: {0}", _ 
                .FileDescription)
            Console.WriteLine("      Versione prodotto: {0}", _ 
                .ProductVersion)
            Dim Rel As String = "Nessuna"
            If .IsDebug Then
                Rel = "Debug"
            ElseIf .IsPatched Then
                Rel = "Patch"
            ElseIf .IsPreRelease Then
                Rel = "Beta"
            ElseIf .IsPrivateBuild Then
                Rel = "Release privata"
            ElseIf .IsSpecialBuild Then
                Rel = "Release speciale"
            End If
            Console.WriteLine("      Caratteristiche: {0}", Rel)
            Console.WriteLine("      Copyright: {0}", .LegalCopyright)
            Console.WriteLine("      Trademark: {0}", .LegalTrademarks)
            Console.WriteLine("      Commenti: {0}", .Comments)
            Console.WriteLine("      Nome compagnia: {0}", .CompanyName)
        End With
    End Sub

    'Formatta un valore timespan
    Public Function FormatTime(ByVal T As TimeSpan) As String
        Return String.Format("{0}h {1}m {2}s", T.Hours, T.Minutes, T.Seconds)
    End Function

    'Ottiene tutte le informazioni possibili su un processo
    Public Sub ScanProcess(ByVal P As Process)
        Console.WriteLine("Nome processo: " & P.ProcessName)
        Console.WriteLine("  Handle: {0:X8}", P.Handle.ToInt32)
        Console.WriteLine("  Handles usati: {0}", P.HandleCount)
        Console.WriteLine("  Id: {0}", P.Id)
        Console.WriteLine("  Nome macchina: {0}", P.MachineName)
        Console.WriteLine("  Moduli:")
        For Each M As ProcessModule In P.Modules
            Console.WriteLine()
            ScanModule(M)
        Next
        Console.WriteLine()
        Console.WriteLine("  Handle finestra principale: {0:X8}", _ 
            P.MainWindowHandle.ToInt32)
        Console.WriteLine("  Titolo finestra principale: {0}", _ 
            P.MainWindowTitle)
        Console.WriteLine("  Threads: {0}", P.Threads.Count)
        Console.WriteLine("  Tempo di esecuzione su OS: {0}", _ 
            FormatTime(P.PrivilegedProcessorTime))
        Console.WriteLine("  Tempo di esecuzione user: {0}", _ 
            FormatTime(P.UserProcessorTime))
        Console.WriteLine("  Tempo di esecuzione totale: {0}", _ 
            FormatTime(P.TotalProcessorTime))
    End Sub

    Sub Main()
        Dim Name As String
        Dim Processes() As Process

        'Fa inserire il nome del processo
        Console.WriteLine("Inserire il nome di un processo:")
        Name = Console.ReadLine

        'Inizializza la collezione
        Processes = Process.GetProcessesByName(Name)
        'Se l'array è vuoto, non c'è nessun processo
        'aperto con quel nome
        If Processes.Length = 0 Then
            Console.WriteLine("Non esiste alcun processo con questo nome!")
        Else
            'Altrimenti enumera tutti i processi aperti
            For Each P As Process In Processes
                Console.WriteLine()
                ScanProcess(P)
            Next
        End If

        Console.ReadKey()
    End Sub
End Module 

 

Avviare nuovi processi

Per avviare un nuovo processo, è possibile scegliere due strade diverse. La prima comporta l'uso di un nuovo oggetto Process e della sua proprietà StartInfo, mentre la seconda usa solamente il metodo statico Process.Start.
Cominciamo a descrivere la prima. Dopo aver inizializzato un nuovo oggetto Process:

Dim P As New Process 

Si accede alla proprietà StartInfo e tramite questa si specificano tutte le informazioni necessarie all'avvio. I membri di StartInfo sono:

  • Arguments : determina gli argomenti passati a linea di comando. È una semplice stringa. Per saperne di più sui parametri passati da linea di comando, vedere il tutorial associato nella sezione Appunti
  • CreateNoWindow : determina se il processo debba essere avviato in una nuova finestra
  • EnvironmentVariables : è una collezione di stringhe che rappresenta tutte le variabili d'ambiente. Queste ultime sono speciali tipi di variabili globali, che non vengono definite dall'applicazione ma dal sistema operativo (o dal programma che richiama l'applicazione stessa) e possono essere utilizzate in qualsiasi punto del codice. È possibile ottenere una variabile d'ambiente precedentemente impostata con la funzione Environment.GetEnvironmentVariable("nome variabile"). Di queste ne esistono alcune predefinite, che sono valide per ogni processo avviato sul computer: per saperle, possiamo usare questo breve codice:
    Module Module1
        Sub Main()
            Console.WriteLine("Variabili d'ambiente:")
            Console.WriteLine()
    
            For Each Name As String In Environment.GetEnvironmentVariables.Keys
                Console.WriteLine("{0} = {1}", Name, _
                    Environment.GetEnvironmentVariable(Name))
            Next
    
            Console.ReadKey()
        End Sub
    End Module 
    Sul mio computer, questo è il risultato:

    EnvironmentVariables.PNG
    P.S.: io non mi chiamo Nicola, eh: quando il tecnico ha fatto backup e formattazione ha capito male il mio nome, e non mi sono ancora preso la briga di cambiare le impostazioni
  • FileName : nome del file da avviare. Se si tratta di un eseguibile, verrà avviato il programma relativo. Se si tratta, invece, di un qualsiasi altro tipo di file, questo verrà aperto con il programma associato, se esiste (ad esempio, un'immagine sarà aperta con Paint). Se l'estensione del file non è associata a nessun applicativo, verrà restituito un errore
  • UserName / Password : se il processo deve essere avviato in un certo account, potrebbero essere richieste delle credenziali. Password è di tipo SecureString (vedi capitolo "Lavorare con le stringhe")
  • Verb : se il file non è eseguibile, questa stringa determina quale azione si debba usare per aprirlo. Ad esempio, se FileName è un file *.txt, si potrebbe usare "print" in questa proprietà per stamparlo. Le azioni disponibili per un certo tipo di file variano sulla base dei programmi associati e sono reperibili nel registro di sistema
  • WindowStyle : determina come visualizzare la finestra aperta dal processo, se Massimizzata, Minimizzata, Normale con focus o Normale senza focus
  • WorkingDirectory : determina la directory di lavoro del processo

Dopo aver impostato le adeguate proprietà, si richiama semplicemente Start:

Dim P As New Process
    With P.StartInfo
        .FileName = "C:programma.exe"
        .Arguments = "-t"
        .WorkingDirectory = "C:cartella"
        .WindowStyle = ProcessWindowStyle.Maximized
    End With
    P.Start() 

Questo codice equivale ad aprire il prompt dei comandi di windows e scrivere:

CD "C:cartella"
C:programma.exe -t 

La seconda possibilità consiste nell'usare la versione statica di Start:

Process.Start("nome file") 

Essa accetta anche altri parametri, che permettono di impostare i dati come si farebbe con StartInfo.

<< Precedente Prossimo >>
A proposito dell'autore

C#, TypeScript, java, php, EcmaScript (JavaScript), Spring, Hibernate, React, SASS/LESS, jade, python, scikit, node.js, redux, postgres, keras, kubernetes, docker, hexo, etc...