2015-01-19 12 views
5

Sto provando a scrivere un gestore certificati e desidero gestire le autorizzazioni sul file del certificato. Preferirei non reinventare la ruota della finestra di dialogo delle autorizzazioni di Windows, quindi idealmente ci sarebbe una sorta di comando di shell che potrei passare il percorso dell'oggetto le cui autorizzazioni vengono gestite. Quindi, potrei semplicemente invocarlo e lasciare che la shell si occupi di aggiornare i permessi.Come si fa a richiamare la finestra di dialogo Autorizzazioni di Windows a livello di programmazione?

Ho visto qualche menzione qui e là di una funzione di shell, SHObjectProperties, ma nulla di chiaro su come usarlo. Qualsiasi aiuto sarebbe apprezzato.

+0

http://www.codeguru.com/csharp/csharp/cs_webservices/security/article.php/c14315/The-Basics-of-Manipulating-File-Access-Control-Lists-with-C. htm – Plutonix

risposta

9

È possibile visualizzare la finestra di permessi dei file di Windows utilizzando ShellExecuteEx (utilizzando la "proprietà", verbo e il parametro "Sicurezza").

Verrà visualizzata una finestra di dialogo simile al seguente all'interno del vostro processo, e la visualizzazione permessi di file e la modifica sarà completamente funzionale proprio come se avessi ottenuto questo dialogo attraverso la shell di Esplora risorse di Windows:

enter image description here

Ecco un esempio con Windows Form in cui è selezionato un file e vengono visualizzate le proprietà di sicurezza di quel file. Ho utilizzato il codice P/Invoke per ShellExecuteEx da this Stackoverflow answer.

using System; 
using System.Runtime.InteropServices; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace FileSecurityProperties 
{ 
    public partial class FileSelectorForm : Form 
    { 
     private static bool ShowFileSecurityProperties(string Filename, IntPtr parentHandle) 
     { 
      SHELLEXECUTEINFO info = new SHELLEXECUTEINFO(); 
      info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info); 
      info.lpVerb = "properties"; 
      info.lpFile = Filename; 
      info.nShow = SW_SHOW; 
      info.fMask = SEE_MASK_INVOKEIDLIST; 
      info.hwnd = parentHandle; 
      info.lpParameters = "Security"; // Opens the file properties on the Security tab 
      return ShellExecuteEx(ref info); 
     } 

     private void fileSelectButton_Click(object sender, EventArgs e) 
     { 
      if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) 
      { 
       ShowFileSecurityProperties(
        openFileDialog.FileName, 
        this.Handle); // Pass parent window handle for properties dialog 
      } 
     } 

     #region P/Invoke code for ShellExecuteEx from https://stackoverflow.com/a/1936957/4486839 
     [DllImport("shell32.dll", CharSet = CharSet.Auto)] 
     static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo); 

     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
     public struct SHELLEXECUTEINFO 
     { 
      public int cbSize; 
      public uint fMask; 
      public IntPtr hwnd; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string lpVerb; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string lpFile; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string lpParameters; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string lpDirectory; 
      public int nShow; 
      public IntPtr hInstApp; 
      public IntPtr lpIDList; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string lpClass; 
      public IntPtr hkeyClass; 
      public uint dwHotKey; 
      public IntPtr hIcon; 
      public IntPtr hProcess; 
     } 

     private const int SW_SHOW = 5; 
     private const uint SEE_MASK_INVOKEIDLIST = 12; 
     #endregion 

     #region Irrelevant Windows forms code 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); 
      this.fileSelectButton = new System.Windows.Forms.Button(); 
      this.SuspendLayout(); 
      // 
      // openFileDialog1 
      // 
      this.openFileDialog.FileName = ""; 
      // 
      // fileSelectButton 
      // 
      this.fileSelectButton.Location = new System.Drawing.Point(52, 49); 
      this.fileSelectButton.Name = "fileSelectButton"; 
      this.fileSelectButton.Size = new System.Drawing.Size(131, 37); 
      this.fileSelectButton.TabIndex = 0; 
      this.fileSelectButton.Text = "Select file ..."; 
      this.fileSelectButton.UseVisualStyleBackColor = true; 
      this.fileSelectButton.Click += new System.EventHandler(this.fileSelectButton_Click); 
      // 
      // FileSelectorForm 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(248, 162); 
      this.Controls.Add(this.fileSelectButton); 
      this.Name = "FileSelectorForm"; 
      this.Text = "File Selector"; 
      this.ResumeLayout(false); 

     } 

     #endregion 

     private System.Windows.Forms.OpenFileDialog openFileDialog; 
     private System.Windows.Forms.Button fileSelectButton; 

     public FileSelectorForm() 
     { 
      InitializeComponent(); 
     } 

     #endregion 
    } 

    static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new FileSelectorForm()); 
     } 
    } 
} 

Se speravate di ottenere la finestra di permessi dei file da solo, piuttosto che come una scheda nella finestra di dialogo generale, le proprietà del file, che è possibile utilizzare aclui.dll, per esempio usando lo EditSecurity function, ma questo NON ti darà quindi il tuo altro requisito di avere la gestione delle autorizzazioni dei file per te, perché devi fornire un'interfaccia che consente di ottenere e impostare le proprietà di sicurezza se scorri lungo tale percorso, e sembra un sacco di codice.

0

Opps il mio cattivo "attrib" è come un tempo.

Quello che stai cercando di fare è "cambiare i descrittori di sicurezza su cartelle e file". Lo strumento da riga di comando è cacls.

consultare: http://en.wikipedia.org/wiki/Cacls

+0

Sì ... Sto cercando di richiamare la finestra di dialogo di Windows per gestirlo. Sto cercando di evitare di dover scrivere personalmente tutta la gestione ACL e il codice UI. Nella peggiore delle ipotesi, mi limiterò a duplicare l'interfaccia utente di Windows ea gestire gli ACL da solo, ma sarà un problema ... –

6

Ecco una classe utilily che consente di avere solo il foglio delle proprietà di sicurezza (non tutti i fogli visualizzati dalla shell).

enter image description here

Si può chiamare come questo in una console app:

class Program 
{ 
    [STAThread] 
    static void Main(string[] args) 
    { 
     // NOTE: if the dialog looks old fashioned (for example if used in a console app), 
     // then add an app.manifest and uncomment the dependency section about Microsoft.Windows.Common-Controls 
     PermissionDialog.Show(IntPtr.Zero, @"d:\temp\killroy_was_here.png"); 
    } 
} 

o come questo in un app WinForm

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     PermissionDialog.Show(IntPtr.Zero, @"d:\temp\killroy_was_here.png"); 
    } 
} 

E questa è la classe principale. In pratica usa la stessa cosa della shell, ma nella sua scheda delle proprietà.

public static class PermissionDialog 
{ 
    public static bool Show(IntPtr hwndParent, string path) 
    { 
     if (path == null) 
      throw new ArgumentNullException("path"); 

     SafePidlHandle folderPidl; 
     int hr; 
     hr = SHILCreateFromPath(Path.GetDirectoryName(path), out folderPidl, IntPtr.Zero); 
     if (hr != 0) 
      throw new Win32Exception(hr); 

     SafePidlHandle filePidl; 
     hr = SHILCreateFromPath(path, out filePidl, IntPtr.Zero); 
     if (hr != 0) 
      throw new Win32Exception(hr); 

     IntPtr file = ILFindLastID(filePidl); 

     System.Runtime.InteropServices.ComTypes.IDataObject ido; 
     hr = SHCreateDataObject(folderPidl, 1, new IntPtr[] { file }, null, typeof(System.Runtime.InteropServices.ComTypes.IDataObject).GUID, out ido); 
     if (hr != 0) 
      throw new Win32Exception(hr); 

     // if you get a 'no such interface' error here, make sure the running thread is STA 
     IShellExtInit sei = (IShellExtInit)new SecPropSheetExt(); 
     sei.Initialize(IntPtr.Zero, ido, IntPtr.Zero); 

     IShellPropSheetExt spse = (IShellPropSheetExt)sei; 
     IntPtr securityPage = IntPtr.Zero; 
     spse.AddPages((p, lp) => 
     { 
      securityPage = p; 
      return true; 
     }, IntPtr.Zero); 

     PROPSHEETHEADER psh = new PROPSHEETHEADER(); 
     psh.dwSize = Marshal.SizeOf(psh); 
     psh.hwndParent = hwndParent; 
     psh.nPages = 1; 
     psh.phpage = Marshal.AllocHGlobal(IntPtr.Size); 
     Marshal.WriteIntPtr(psh.phpage, securityPage); 

     // TODO: adjust title & icon here, also check out the available flags 
     psh.pszCaption = "Permissions for '" + path + "'"; 

     IntPtr res; 
     try 
     { 
      res = PropertySheet(ref psh); 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(psh.phpage); 
     } 
     return res == IntPtr.Zero; 
    } 

    private class SafePidlHandle : SafeHandle 
    { 
     public SafePidlHandle() 
      : base(IntPtr.Zero, true) 
     { 
     } 

     public override bool IsInvalid 
     { 
      get { return handle == IntPtr.Zero; } 
     } 

     protected override bool ReleaseHandle() 
     { 
      if (IsInvalid) 
       return false; 

      Marshal.FreeCoTaskMem(handle); 
      return true; 
     } 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    private struct PROPSHEETHEADER 
    { 
     public int dwSize; 
     public int dwFlags; 
     public IntPtr hwndParent; 
     public IntPtr hInstance; 
     public IntPtr hIcon; 
     public string pszCaption; 
     public int nPages; 
     public IntPtr nStartPage; 
     public IntPtr phpage; 
     public IntPtr pfnCallback; 
    } 

    [DllImport("shell32.dll")] 
    private static extern IntPtr ILFindLastID(SafePidlHandle pidl); 

    [DllImport("shell32.dll", CharSet = CharSet.Unicode)] 
    private static extern int SHILCreateFromPath(string pszPath, out SafePidlHandle ppidl, IntPtr rgflnOut); 

    [DllImport("shell32.dll")] 
    private static extern int SHCreateDataObject(SafePidlHandle pidlFolder, int cidl, IntPtr[] apidl, System.Runtime.InteropServices.ComTypes.IDataObject pdtInner, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out System.Runtime.InteropServices.ComTypes.IDataObject ppv); 

    [DllImport("comctl32.dll", CharSet = CharSet.Unicode)] 
    private static extern IntPtr PropertySheet(ref PROPSHEETHEADER lppsph); 

    private delegate bool AddPropSheetPage(IntPtr page, IntPtr lParam); 

    [ComImport] 
    [Guid("1f2e5c40-9550-11ce-99d2-00aa006e086c")] // this GUID points to the property sheet handler for permissions 
    private class SecPropSheetExt 
    { 
    } 

    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [Guid("000214E8-0000-0000-C000-000000000046")] 
    private interface IShellExtInit 
    { 
     void Initialize(IntPtr pidlFolder, System.Runtime.InteropServices.ComTypes.IDataObject pdtobj, IntPtr hkeyProgID); 
    } 

    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [Guid("000214E9-0000-0000-C000-000000000046")] 
    private interface IShellPropSheetExt 
    { 
     void AddPages([MarshalAs(UnmanagedType.FunctionPtr)] AddPropSheetPage pfnAddPage, IntPtr lParam); 
     void ReplacePage(); // not fully defined, we don't use it 
    } 
}