\\ Home Page : Articolo : Stampa
Con UAC e PCA usate UseShellExecute
Di Marco Tenuti (del 23/01/2013 @ 12:19:42, in Windows, linkato 2192 volte)

Elevazione di previlegi in Windows 8Sto girovagando da un bel po' attorno al problema di gestire l'elevazione dei previlegi con Windows. Il pattern della situazione è alquanto tipico e che capita a tanti sviluppatori, ossia lanciare un eseguibile esterno con diritti di amministratore, semplicemente perché l'eseguibile esterno deve intraprendere operazioni di manutenzione sulle installazione, come ad esempio un software di aggiornamento.

Anzitutto è necessario prevedere che l'eseguibile sia contrassegnato in modo tale che esso pretenda diritti di amministrazione prima di partire. Per fare questo basta scrivere qualcosina del manifest file esterno o iniettarlo nel manifest interno come risorsa:

<?xml version="1.0" encoding="UTF-8" 
  standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" 
  manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <assemblyIdentity version="2.3.0.0" 
    processorArchitecture="X86" name="YourUpdater.exe" 
    type="win32"/>
  <description>Update Tool</description>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
    </application>
  </compatibility>
</assembly>

Come potete vedere, i previlegi pretendono di essere amministratore, requireAdministrator, poi sarà carico del sistema operativo tramite UAC (User Access Control) o tramite PCA (Program Compatibility Assistant) a gestire o meno la richiesta all'utente tramite opportuno dialogo con cui intraprendere l'elevazione.

Purtroppo Microsoft continua a rimettere in discussione le politiche di gestione ed ogni qualche mese, il comportamento cambia a seguito di nuove invenzioni di Redmond. Anche alcuni stessi sviluppatori all'interno di Microsoft hanno manifestato tutto il loro disappunto per continuare a cambiare la carte in tavola, cosa su cui gli sviluppatori impazziscono e gli utenti finali ancor di più.

Sostanzialmente se all'interno dell'eseguibile è presente un manifest che dice cosa fare, il problema non si pone, o meglio, non dovrebbe porsi. Esso dice cosa deve fare il sistema, senza che si inventi nulla in particolare. In realtà, già a partire da Windows Vista, il sistema provava per conto suo a tentare l'elevazione semplicemente perché il nome ed il codice binario conteneva qualche occorrenza delle parole "setup", "installer" e "update". Tutto questo però portava al succedere sia dei "false positive" che dei "false negative", con gravi incazzature degli sviluppatori.

Per rendervi conto dell'evoluzione dei fatti, vi lascio a questi articoli:

Ora vi introduco al codice nel mio processo che gira in modalità standard:

    Try
      updProcess = New Process()
      With updProcess.StartInfo
        .UseShellExecute = False
        .FileName = updPath
        .WorkingDirectory = CurDir()
        .Arguments = arguments
      End With
      updProcess.Start()
      fileExistsAndLaunched = True
    Catch ex As Exception
      MsgBox(ex.ToString)
    End Try

In realtà ho scoperto una cosa molto più semplice e cioè che Process.Start, se impostato con StartInfo.UseShellExecute a falso, non è in grado di far scattare tutto questo sistema di elevazione dei previlegi, ma esso si ferma a sollevare un'eccezione che recita più o meno così:

ex {Name = "Win32Exception" FullName = "System.ComponentModel.Win32Exception"} System.Type
"Per eseguire l'operazione richiesta è necessaria l'esecuzione con privilegi elevati"

La soluzione è semplice: ricordarsi di farlo con UseShellExecute impostato a vero, anche se all'atto dell'istanziazione di oggetto di classe System.Diagnostics.Process, tale proprietà è già impostata a true, quindi il problema non si pone, a meno che non abbiate tra le mani, come è capitato a me, il caso in cui UseShellExecute era stato forzato a falso...