Skip to content

Instantly share code, notes, and snippets.

@vbfox
Created August 26, 2010 15:33
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vbfox/551626 to your computer and use it in GitHub Desktop.
Save vbfox/551626 to your computer and use it in GitHub Desktop.
Sample code for SHOpenFolderAndSelectItems in C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace SHOpenFolderAndSelectItems
{
static class ShowSelectedInExplorer
{
[Flags]
internal enum SHCONT : ushort
{
SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
SHCONTF_FOLDERS = 0x0020,
SHCONTF_NONFOLDERS = 0x0040,
SHCONTF_INCLUDEHIDDEN = 0x0080,
SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
SHCONTF_NETPRINTERSRCH = 0x0200,
SHCONTF_SHAREABLE = 0x0400,
SHCONTF_STORAGE = 0x0800,
SHCONTF_NAVIGATION_ENUM = 0x1000,
SHCONTF_FASTITEMS = 0x2000,
SHCONTF_FLATLIST = 0x4000,
SHCONTF_ENABLE_ASYNC = 0x8000
}
[ComImport,
Guid("000214E6-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComConversionLoss]
internal interface IShellFolder
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAttributes);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int EnumObjects([In] IntPtr hwnd, [In] SHCONT grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenumIDList);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int BindToObject([In] IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void BindToStorage([In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CompareIDs([In] IntPtr lParam, [In] ref IntPtr pidl1, [In] ref IntPtr pidl2);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetAttributesOf([In] uint cidl, [In] IntPtr apidl, [In, Out] ref uint rgfInOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetUIObjectOf([In] IntPtr hwndOwner, [In] uint cidl, [In] IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDisplayNameOf([In] ref IntPtr pidl, [In] uint uFlags, out IntPtr pName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetNameOf([In] IntPtr hwnd, [In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, [In] uint uFlags, [Out] IntPtr ppidlOut);
}
[ComImport,
Guid("000214F2-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEnumIDList
{
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Next(uint celt, IntPtr rgelt, out uint pceltFetched);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Skip([In] uint celt);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Reset();
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Clone([MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum);
}
class NativeMethods
{
static readonly int pointerSize = Marshal.SizeOf(typeof(IntPtr));
[DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
public static extern int CreateBindCtx_(int reserved, out IBindCtx ppbc);
public static IBindCtx CreateBindCtx()
{
IBindCtx result;
Marshal.ThrowExceptionForHR(CreateBindCtx_(0, out result));
return result;
}
[DllImport("shell32.dll", EntryPoint = "SHGetDesktopFolder", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHGetDesktopFolder_([MarshalAs(UnmanagedType.Interface)] out IShellFolder ppshf);
public static IShellFolder SHGetDesktopFolder()
{
IShellFolder result;
Marshal.ThrowExceptionForHR(SHGetDesktopFolder_(out result));
return result;
}
[DllImport("shell32.dll", EntryPoint = "SHOpenFolderAndSelectItems")]
static extern int SHOpenFolderAndSelectItems_(
[In] IntPtr pidlFolder, uint cidl, [In, Optional] IntPtr apidl, int dwFlags
);
public static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, IntPtr apidl, int dwFlags)
{
var result = NativeMethods.SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags);
Marshal.ThrowExceptionForHR(result);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath);
[DllImport("shell32.dll")]
public static extern void ILFree([In] IntPtr pidl);
}
static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, ICollection<IntPtr> apidl, bool edit)
{
IntPtr array = IntPtr.Zero;
uint itemCount = 0;
try
{
if (apidl != null && apidl.Count > 0)
{
itemCount = (uint)apidl.Count;
array = Marshal.AllocHGlobal(pointerSize * apidl.Count);
var i = 0;
foreach (var filePIDL in apidl)
{
Marshal.WriteIntPtr(array, i * pointerSize, filePIDL);
i++;
}
}
NativeMethods.SHOpenFolderAndSelectItems(pidlFolder, itemCount, array, edit ? 1 : 0);
}
finally
{
Marshal.FreeHGlobal(array);
}
}
static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName)
{
var bindCtx = NativeMethods.CreateBindCtx();
uint pchEaten;
uint pdwAttributes = 0;
IntPtr ppidl;
parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAttributes);
return ppidl;
}
static IntPtr PathToAbsolutePIDL(string path)
{
var desktopFolder = NativeMethods.SHGetDesktopFolder();
return GetShellFolderChildrenRelativePIDL(desktopFolder, path);
}
static Guid IID_IShellFolder = typeof(IShellFolder).GUID;
static int pointerSize = Marshal.SizeOf(typeof(IntPtr));
static IShellFolder PIDLToShellFolder(IShellFolder parent, IntPtr pidl)
{
IShellFolder folder;
var result = parent.BindToObject(pidl, IntPtr.Zero, ref IID_IShellFolder, out folder);
Marshal.ThrowExceptionForHR((int)result);
return folder;
}
static IShellFolder PIDLToShellFolder(IntPtr pidl)
{
return PIDLToShellFolder(NativeMethods.SHGetDesktopFolder(), pidl);
}
public static void FileOrFolder(string path, bool edit = false)
{
if (path == null) throw new ArgumentNullException("path");
var pidl = PathToAbsolutePIDL(path);
try
{
SHOpenFolderAndSelectItems(pidl, null, edit);
}
finally
{
NativeMethods.ILFree(pidl);
}
}
static IEnumerable<FileSystemInfo> PathToFileSystemInfo(IEnumerable<string> paths)
{
foreach (var path in paths)
{
if (Directory.Exists(path)) yield return new DirectoryInfo(path);
else yield return new FileInfo(path);
}
}
public static void FilesOrFolders(string parentDirectory, ICollection<string> filenames)
{
if (filenames == null) throw new ArgumentNullException("filenames");
if (filenames.Count == 0) return;
var parentPidl = PathToAbsolutePIDL(parentDirectory);
try
{
var parent = PIDLToShellFolder(parentPidl);
List<IntPtr> filesPidl = new List<IntPtr>(filenames.Count);
foreach (var filename in filenames)
{
filesPidl.Add(GetShellFolderChildrenRelativePIDL(parent, filename));
}
try
{
SHOpenFolderAndSelectItems(parentPidl, filesPidl, false);
}
finally
{
foreach (var pidl in filesPidl)
{
NativeMethods.ILFree(pidl);
}
}
}
finally
{
NativeMethods.ILFree(parentPidl);
}
}
public static void FilesOrFolders(IEnumerable<string> paths, bool showOnDesktop = false)
{
FilesOrFolders(PathToFileSystemInfo(paths), showOnDesktop);
}
public static void FilesOrFolders(IEnumerable<FileSystemInfo> paths, bool showOnDesktop = false)
{
if (paths == null) throw new ArgumentNullException("paths");
if (paths.Count() == 0) return;
var parentDirectories = paths.Select(p => Path.GetDirectoryName(p.FullName));
var parentDirectory = parentDirectories.First();
var otherDirectories = parentDirectories.Skip(1);
if (otherDirectories.Any(p => p != parentDirectory))
{
throw new ArgumentException("At least one path is not in the same directory as the others", "paths");
}
FilesOrFolders(parentDirectory, paths.Select(fsi => fsi.Name).ToList());
}
}
class Program
{
static void Main(string[] args)
{
var test = 1;
switch (test)
{
case 0:
var mydocs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
ShowSelectedInExplorer.FileOrFolder(Path.Combine(mydocs, "Visual Studio 2010"), edit: true);
break;
case 1:
ShowSelectedInExplorer.FileOrFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
break;
case 2:
ShowSelectedInExplorer.FilesOrFolders(@"C:\Windows\", new[] { "Microsoft.NET", "System32", "Setup" });
break;
case 3:
ShowSelectedInExplorer.FilesOrFolders(new[] { @"C:\Windows\Microsoft.NET", @"C:\Windows\System32", @"C:\Windows\Setup" });
break;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment