2015-01-19 7 views
5

Я пытаюсь написать диспетчер сертификатов, и я хочу управлять разрешениями над файлом сертификата. Я бы предпочел не изобретать колесо диалога разрешений Windows, поэтому в идеале была бы какая-то команда оболочки, чтобы я мог передать путь элемента, разрешения которого управляются. Затем я мог бы просто вызвать его и позволить оболочке заботиться об обновлении разрешений.Как программно вызывать диалоговое окно «Разрешения Windows»?

Я видел некоторые упоминания здесь и там функции оболочки SHObjectProperties, но ничего не известно о том, как ее использовать. Любая помощь будет оценена по достоинству.

+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

ответ

9

Вы можете отобразить диалог прав доступа к файлам Windows с помощью ShellExecuteEx (с помощью «свойств» глаголом и параметр «Безопасность»).

Это отобразит диалоговое окно, как следующее в вашем процессе, а также просмотр и редактирование прав доступа к файлам будет полностью функционален так же, как если бы вы получили этот диалог через Проводник Windows оболочки:

enter image description here

Ниже приведен пример с Windows Forms, в котором выбран файл, и затем отображаются свойства безопасности этого файла. Я использовал код P/Invoke для ShellExecuteEx от 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()); 
     } 
    } 
} 

Если вы надеялись получить диалог прав доступа к файлам на своем собственном, а не в качестве вкладки в диалоге общих свойств файла, что возможно с помощью aclui.dll, например, используя EditSecurity function, но это НЕ даст вам другое требование о том, чтобы обработка прав доступа к файлам позаботилась о вас, поскольку вам необходимо предоставить интерфейс, который обеспечивает получение и настройку свойств безопасности, если вы спуститесь по этому маршруту и это похоже на много кодирования.

0

Opps мой плохой атрибут, как это было раньше.

Что вы ищете, я полагаю, это «изменение дескрипторов безопасности в папках и файлах». Инструмент командной строки - cacls.

Пожалуйста, см: http://en.wikipedia.org/wiki/Cacls

+0

Да ... Я пытаюсь вызвать диалог Windows для его управления. Я пытаюсь избежать необходимости писать все управление ACL и код пользовательского интерфейса. В худшем случае я просто дублирую пользовательский интерфейс Windows и сам управляю ACL, но это будет боль ... –

6

Это полезный класс, который позволяет иметь только лист свойств безопасности (не все листы, отображаемые оболочкой).

enter image description here

Вы можете назвать это, как это в консольном приложении:

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"); 
    } 
} 

или как это в 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"); 
    } 
} 

И это является основным классом. В основном он использует ту же самую вещь, что и оболочка, но в ее собственной странице свойств.

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 
    } 
} 
Смежные вопросы