Here is a utilily class that allows you to have only the security property sheet (not all sheets the shell displays).
You can call it like this in a 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");
}
}
or like this in a winform app
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");
}
}
And this is the main class. It's basically using the same thing as the shell, but in its own property sheet.
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
}
}