SHOpenFolderAndSelectItems (shell32)
Last changed: Susko3-109.60.16.93

.
Summary
SHOpenFolderAndSelectItems - Opens a Windows Explorer window with specified items in a particular folder selected.

C# Signature:

[DllImport("shell32.dll", SetLastError=true)]
public static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, uint dwFlags);

VB Signature:

  <DllImport("shell32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
  Public Shared Function SHOpenFolderAndSelectItems(ByVal pidlFolder As IntPtr, ByVal cidl As UInteger, <MarshalAs(UnmanagedType.LPArray)> ByVal apidl() As IntPtr, ByVal dwFlags As UInteger) As Integer
  End Function

User-Defined Types:

None.

Alternative Managed API:

    Process.Start("explorer.exe", @"/select,C:\Program Files\Windows NT\Accessories\wordpad.exe");

Very similar to SHOpenFolderAndSelectItems, but doesn't reuse existing explorer windows and can only select one file.

Notes:

None.

Tips & Tricks:

Please add some!

C# Sample Code:

    [DllImport("shell32.dll", SetLastError = true)]
    public static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, uint dwFlags);

    [DllImport("shell32.dll", SetLastError = true)]
    public static extern void SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name, IntPtr bindingContext, [Out] out IntPtr pidl, uint sfgaoIn, [Out] out uint psfgaoOut);

    public static void OpenFolderAndSelectItem(string folderPath, string file)
    {
        IntPtr nativeFolder;
        uint psfgaoOut;
        SHParseDisplayName(folderPath, IntPtr.Zero, out nativeFolder, 0, out psfgaoOut);

        if (nativeFolder == IntPtr.Zero)
        {
            // Log error, can't find folder
            return;
        }

        IntPtr nativeFile;
        SHParseDisplayName(Path.Combine(folderPath, file), IntPtr.Zero, out nativeFile, 0, out psfgaoOut);

        IntPtr[] fileArray;
        if (nativeFile == IntPtr.Zero)
        {
            // Open the folder without the file selected if we can't find the file
            fileArray = new IntPtr[] { nativeFolder };
        }
        else
        {
            fileArray = new IntPtr[] { nativeFile };
        }

        SHOpenFolderAndSelectItems(nativeFolder, (uint)fileArray.Length, fileArray, 0);

        Marshal.FreeCoTaskMem(nativeFolder);
        if (nativeFile != IntPtr.Zero)
        {
            Marshal.FreeCoTaskMem(nativeFile);
        }
    }

VB Usage:

  If ExplorerSelectItems.SetFolder("c:\windows\system32\") Then
    ExplorerSelectItems.AddFile("calc.exe")
    ExplorerSelectItems.AddFile("cacls.exe")
    ExplorerSelectItems.AddFile("cabview.dll")
    ExplorerSelectItems.AddFile("cabinet.dll")
    ExplorerSelectItems.Commit()
  End If

VB Sample Code:

  Imports System.Runtime.InteropServices
  Imports System.Security.Permissions
  Imports System.IO

  Public NotInheritable Class ExplorerSelectItems

    Private Shared pidlList As New List(Of IntPtr)
    Private Shared pidlFolder As IntPtr = IntPtr.Zero
    Private Shared _folderPath As String = String.Empty

    Private Sub New()
    End Sub

    ''' <summary>
    ''' Sets the parent directory containing the files that will be selected.
    ''' </summary>
    <SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Public Shared Function SetFolder(ByVal folderPath As String) As Boolean
    FreeList()
    If SafeNativeMethods.SHParseDisplayName(folderPath, IntPtr.Zero, pidlFolder, 0, 0) = 0 Then
        _folderPath = folderPath
        Return True
    End If
    Return False
    End Function

    ''' <summary>
    ''' Adds a single file to be selected.
    ''' </summary>
    <SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Public Shared Sub AddFile(ByVal fileName As String)
    Dim pidl As IntPtr = IntPtr.Zero
    If pidlFolder = IntPtr.Zero Then
        Return
    End If
    If SafeNativeMethods.SHParseDisplayName(Path.Combine(_folderPath, fileName), IntPtr.Zero, pidl, 0, 0) = 0 Then
        pidlList.Add(pidl)
    End If
    End Sub

    ''' <summary>
    ''' Opens and selects all files. In addition releases all resources.
    ''' </summary>
    <SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Public Shared Sub Commit()
    Dim pidl() As IntPtr
    If pidlFolder = IntPtr.Zero Then
        Return
    End If
    pidl = pidlList.ToArray
    SafeNativeMethods.SHOpenFolderAndSelectItems(pidlFolder, pidl.Length, pidl, 0)
    FreeList()
    End Sub

    Private Shared Sub FreeList()
    If pidlFolder <> IntPtr.Zero Then
        Marshal.FreeCoTaskMem(pidlFolder)
        pidlFolder = IntPtr.Zero
    End If
    For Each pidl In pidlList
        Marshal.FreeCoTaskMem(pidl)
    Next
    pidlList.Clear()
    End Sub

  End Class

  Friend NotInheritable Class SafeNativeMethods
    <DllImport("shell32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Public Shared Function SHParseDisplayName(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, ByVal pbc As IntPtr, ByRef ppidl As IntPtr, ByVal sfgaoIn As UInteger, ByRef psfgaoOut As UInteger) As Integer
    End Function
    <DllImport("shell32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Public Shared Function SHOpenFolderAndSelectItems(ByVal pidlFolder As IntPtr, ByVal cidl As UInteger, <MarshalAs(UnmanagedType.LPArray)> ByVal apidl() As IntPtr, ByVal dwFlags As UInteger) As Integer
    End Function
  End Class

Documentation