maurogsc.eu
mauro gamberini


home ==> Excel: articoli ==> Celle - Aprire e chiudere un programma con una macro(32/64 bit)

Sistema - Aprire e chiudere un programma con una macro(32/64 bit)

Situazione.
Abbiamo la necessità di aprire un programma da codice, utilizzarlo e quindi di poterlo eventualmente chiudere sempre da macro.

Nota.
Il codice è fornito *così com'è* e l’autore declina ogni responsabilità per eventuali problemi causati dal codice se usato impropriamente. Utilizzate il codice in files di test per le vostre prove. Il codice è stato testato con(e quindi validi per) Excel 2003/2007/2010.

Aprire un programma.
Nelllo specifico apriremo il Blocco Note(Notepad) di Windows. Quello che dobbiamo fare è richiamare il Notepad con la funzione Shell(vedere anche la guida del vb di Excel).  Questo il codice da inserire, ad esempio, in un modulo di codice standard(Inserisci-->Modulo o vedi qui: xlsdoveinserirecodice.aspx)

Public Sub m_1()
    Shell ("Notepad.exe"), vbNormalNoFocus
End Sub

Una soluzione diversa per aprire il Notepad è questa:

Public Sub m_2()
    Dim v As Variant
    v = Shell("Notepad.exe", vbNormalNoFocus)
End Sub

Quanto visto fino ad ora si può facilmente ricavare dalla guida di Excel. E sempre nella guida, si legge che viene restituito alla variabile che abbiamo dichiarato un valore di tipo Variant(Double),  Come posssiamo utilizzare quel vaolre? Per esempio per gestire una eventuale eccezione(errore) nel caso il programma non sia disponibile. Nel codice della macro m_3() ho aggiunto una x davanti a Notepad.exe; il programma non esiste e quindi il valore di v sarà 0( o  False se vogliamo vederlo come tipo Variant(Boolean), ma non complichiamo troppo la cosa):

Public Sub m_3()
    Dim v As Variant
    On Error Resume Next
    v = Shell("xNotepad.exe", vbNormalNoFocus)
    If v = 0 Then
        MsgBox "Programma non trovato"
    Else
        MsgBox v
    End If
End Sub

Se togliamo la x, ci verrà restituito un valore di tipo Variant(Double). Sì, ma cos'è quel valore? La guida ci dice che è l'idetificativo(univoco) del task del programma avviato. In altre parole, il processore sa che qul identificativo si riferisce ad un determinato programma eseguito(non può riferirsi al nome del programma, ad esempio Excel; potreste avere più sessioni di Excel aperte contemporaneamente). Vediamo come utilizzare quel valore per chiudere il programma non con quello che il programma stesso mette a disposizione, ma con il nostro codice. Abbiamo bisogno di utilizzare le API di Windows e qui la cosa si complica un po' perchè sono diverse in sistemi operativi Windows a 32 o 64 bit e in più abbiamo Office a 32 o 64 bit.

1 - Il codice qui sotto , sempre da copia/incollare in un modulo standard, apre o chiude il Notepad in sistemi operativi a 32 bit con tutte le versioni a 32 bit di Office:

Public v As Variant

Private Const PROCESS_ALL_ACCESS = &H1F0FFF

Private Declare Function OpenProcess Lib "kernel32" _
  (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
   ByVal dwProcessId As Long) As Long

Private Declare Function GetExitCodeProcess Lib "kernel32" _
   (ByVal hProcess As Long, lpExitCode As Long) As Long

Private Declare Function TerminateProcess Lib "kernel32" _
   (ByVal hProcess As Long, ByVal uExitCode As Long) As Long


Public Sub mApriProgramma()
    v = Shell("Notepad.exe", vbNormalFocus)
End Sub

Public Sub mChiudiProgramma()

    Dim lng1 As Long
    Dim lng2 As Long

    lng1 = OpenProcess(PROCESS_ALL_ACCESS, 0&, v)
    
    If lng1 Then
        GetExitCodeProcess lng1, lng2
        If lng2 Then TerminateProcess lng1, lng2
    End If
    
End Sub

2 - Il codice qui sotto apre o chiude il Notepad nelle versioni a 64 bit del sistema operativo con installato Office 2010 e con le versioni a 32 bit del sitema operativo con installato Office 2010:

Public v As Variant

Private Const PROCESS_ALL_ACCESS = &H1F0FFF

Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
  (ByVal dwDesiredAccess As LongPtr, ByVal bInheritHandle As LongPtr, _
   ByVal dwProcessId As LongPtr) As Long

Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" _
   (ByVal hProcess As LongPtr, lpExitCode As LongPtr) As Long

Private Declare PtrSafe Function TerminateProcess Lib "kernel32" _
   (ByVal hProcess As LongPtr, ByVal uExitCode As LongPtr) As Long


Public Sub mApriProgramma()
    v = Shell("Notepad.exe", vbNormalFocus)
End Sub

Public Sub mChiudiProgramma()

    Dim lng1 As Long
    Dim lng2 As LongPtr

    lng1 = OpenProcess(PROCESS_ALL_ACCESS, 0&, v)
    
    If lng1 Then
        GetExitCodeProcess lng1, lng2
        If lng2 Then TerminateProcess lng1, lng2
    End If
    
End Sub

3 - Il codice qui sotto apre e chiude il Notepad e grazie all'struzione di compilazione #If...Then...#EndI If e alla costante Win64 discrimina fra sistemi operativi a 32 o 64 bit:

Public v As Variant
Private Const PROCESS_ALL_ACCESS = &H1F0FFF

#If Win64 Then

    Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
      (ByVal dwDesiredAccess As LongLong, ByVal bInheritHandle As LongLong, _
       ByVal dwProcessId As LongLong) As Longlong
    
    Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" _
       (ByVal hProcess As LongLong, lpExitCode As LongLong) As LongLong
    
    Private Declare PtrSafe Function TerminateProcess Lib "kernel32" _
       (ByVal hProcess As LongLong, ByVal uExitCode As LongLong) As LongLong
       
#Else

    Private Declare Function OpenProcess Lib "kernel32" _
      (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
       ByVal dwProcessId As Long) As Long
    
    Private Declare Function GetExitCodeProcess Lib "kernel32" _
       (ByVal hProcess As Long, lpExitCode As Long) As Long
    
    Private Declare Function TerminateProcess Lib "kernel32" _
       (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
       
#End If


Public Sub mApriProgramma()
    v = Shell("Notepad.exe", vbNormalFocus)
End Sub

Public Sub mChiudiProgramma()

    Dim lng1 As Long
    #If VBA7 Then
        Dim lng2 As LongLong
    #Else
        Dim lng2 As Long
    #End If

    lng1 = OpenProcess(PROCESS_ALL_ACCESS, 0&, v)
    
    If lng1 Then
        GetExitCodeProcess lng1, lng2
        If lng2 Then TerminateProcess lng1, lng2
    End If
    
End Sub

4 - Il codice qui sotto apre e chiude il Notepad e grazie all'struzione di compilazione #If...Then...#EndI If e alla costante VBA7 discrimina fra versioni di Office con la versione 7 del VBA, introdotta con Office 2010 e le precedenti:

Public v As Variant
Private Const PROCESS_ALL_ACCESS = &H1F0FFF

#If VBA7 Then

    Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
      (ByVal dwDesiredAccess As LongPtr, ByVal bInheritHandle As LongPtr, _
       ByVal dwProcessId As LongPtr) As Long
    
    Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" _
       (ByVal hProcess As LongPtr, lpExitCode As LongPtr) As Long
    
    Private Declare PtrSafe Function TerminateProcess Lib "kernel32" _
       (ByVal hProcess As LongPtr, ByVal uExitCode As LongPtr) As Long
       
#Else
    Private Declare Function OpenProcess Lib "kernel32" _
      (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
       ByVal dwProcessId As Long) As Long
    
    Private Declare Function GetExitCodeProcess Lib "kernel32" _
       (ByVal hProcess As Long, lpExitCode As Long) As Long
    
    Private Declare Function TerminateProcess Lib "kernel32" _
       (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
       
#End If


Public Sub mApriProgramma()
    v = Shell("Notepad.exe", vbNormalFocus)
End Sub

Public Sub mChiudiProgramma()

    Dim lng1 As Long
    #If VBA7 Then
        Dim lng2 As LongPtr
    #Else
        Dim lng2 As Long
    #End If

    lng1 = OpenProcess(PROCESS_ALL_ACCESS, 0&, v)
    
    If lng1 Then
        GetExitCodeProcess lng1, lng2
        If lng2 Then TerminateProcess lng1, lng2
    End If
    
End Sub

5 - Il codice qui sotto apre e chiude il Notepad se lavorate in ambiente tutto a 64 bit, sistema operativo e Office:

Public v As Variant

Private Const PROCESS_ALL_ACCESS = &H1F0FFF

Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
  (ByVal dwDesiredAccess As LongLong, ByVal bInheritHandle As LongLong, _
   ByVal dwProcessId As LongPtr) As LongLong

Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" _
   (ByVal hProcess As LongLong, lpExitCode As LongLong) As LongLong

Private Declare PtrSafe Function TerminateProcess Lib "kernel32" _
   (ByVal hProcess As LongLong, ByVal uExitCode As LongLong) As LongLong


Public Sub mApriProgramma()
    v = Shell("Notepad.exe", vbNormalFocus)
End Sub

Public Sub mChiudiProgramma()

    Dim lng1 As LongLong
    Dim lng2 As LongLong

    lng1 = OpenProcess(PROCESS_ALL_ACCESS, 0&, v)
    
    If lng1 Then
        GetExitCodeProcess lng1, lng2
        If lng2 Then TerminateProcess lng1, lng2
    End If
    
End Sub

Quindi, quale utilizzare delle soluzioni proposte?

  1. Se lavorate esclusivamente in ambienti con sistemi operativi a 32 bit
  2. Se lavorate in ambienti con sistemi operativi a 64 bit o a 32 bit con Office 2010
  3. Quando volete essere sicuri di utilizzare la giusta dichiarazione per le versioni a 32 o 64 bit del sistema operativo
  4. Quando scrivete codice in un sistema a 64 bit e volete utilizzarlo anche nelle versioni ma 32 bit di Office
  5. Se lavorate in ambiente tutto a 64 bit

NOTA.
Per ulteriori informazioni sulla compatibilità fra le versioni a 32 e 64 bit di Office, vedere qui: http://msdn.microsoft.com/en-us/library/ee691831(office.14).aspx .

Per ulteriori informazioni su Microsoft Excel ed il suo Visual Basic, utilizzate questo forum:
http://social.answers.microsoft.com/Forums/it-IT/officeexcelit/threads


Ultimo aggiornamento di questa pagina: 23/11/2010 - mauro gamberini