WPF 開啟資源管理器且選中某個檔案

lindexi發表於2024-11-16

開啟資源管理器且選中某個檔案可以使用 cmd 呼叫 explorer 帶上 select 引數,如下面命令列所示

explorer.exe /select,"C:\Folder\file.txt"

但有很多情況下,使用者可能使用其他資源管理器,此時將會導致應用軟體開啟的是 explorer 而不是使用者預設的資源管理器

透過 shell32.dll 提供的 SHOpenFolderAndSelectItems 方法,可以直接使用函式呼叫的方式開啟資源管理器且選中某個檔案,且使用的是使用者設定的預設的資源管理器

以下是我建立的簡單的 WPF 例子程式的介面,可以看到介面非常簡單,就是輸入一個檔案,然後點選按鈕就可以開啟資源管理器選中輸入的檔案

    <Grid>
        <Grid VerticalAlignment="Center">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="檔案路徑:" Margin="50,0,0,0" VerticalAlignment="Center"/>
            <TextBox x:Name="InputTextBox"  Grid.Column="1" Margin="10,0,10,0" VerticalAlignment="Center"/>
            <Button Grid.Column="2" Content="開啟" Margin="10,0,50,0" VerticalAlignment="Center" Click="Button_OnClick"/>
        </Grid>
    </Grid>

按鈕的後臺程式碼將需要使用 PInvoke 呼叫 Win32 函式。對於 dotnet 7 以前的程式,可使用如下方式定義

    [DllImport("shell32.dll", ExactSpelling = true)]
    private static extern void ILFree(IntPtr pidlList);

    [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
    private static extern IntPtr ILCreateFromPathW(string pszPath);

    [DllImport("shell32.dll", ExactSpelling = true)]
    private static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);

對於 dotnet 7 以及更高版本的專案,可使用 LibraryImportAttribute 特性輔助定義。如以下 C# 程式碼所示

    [LibraryImport("shell32.dll")]
    private static partial void ILFree(IntPtr pidlList);

    [LibraryImport("shell32.dll", StringMarshalling = StringMarshalling.Utf16)]
    private static partial IntPtr ILCreateFromPathW(string pszPath);

    [LibraryImport("shell32.dll")]
    private static partial int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);

過程中別忘了在 csproj 專案檔案裡面開啟不安全程式碼,開啟之後的專案檔案程式碼大概如下

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net9.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
  </PropertyGroup>

</Project>

後臺 C# 程式碼的按鈕點選事件裡面將呼叫 SHOpenFolderAndSelectItems 方法開啟資源管理器選中輸入的檔案

    private void Button_OnClick(object sender, RoutedEventArgs e)
    {
        var filePath = InputTextBox.Text;
        filePath = System.IO.Path.GetFullPath(filePath);

        IntPtr pidlList = ILCreateFromPathW(filePath);
        if (pidlList != IntPtr.Zero)
        {
            try
            {
                Marshal.ThrowExceptionForHR(SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
            }
            finally
            {
                ILFree(pidlList);
            }
        }
    }

以上程式碼裡面的 ILCreateFromPathW 要求傳入絕對路徑,需要呼叫 System.IO.Path.GetFullPath 方法轉換傳入路徑為絕對路徑

如果不知道程式碼如何寫的話,可以拉取我的例子專案程式碼跑跑看

本文程式碼放在 githubgitee 上,可以使用如下命令列拉取程式碼。我整個程式碼倉庫比較龐大,使用以下命令列可以進行部分拉取,拉取速度比較快

先建立一個空資料夾,接著使用命令列 cd 命令進入此空資料夾,在命令列裡面輸入以下程式碼,即可獲取到本文的程式碼

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 6988631e41226832c3b83cf62529eb7d7892e0b2

以上使用的是國內的 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令列繼續輸入以下程式碼,將 gitee 源換成 github 源進行拉取程式碼。如果依然拉取不到程式碼,可以發郵件向我要程式碼

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 6988631e41226832c3b83cf62529eb7d7892e0b2

獲取程式碼之後,進入 WPFDemo/WilinojearcheWheyecearhire 資料夾,即可獲取到原始碼

更多 WPF 部落格,請參閱 部落格導航

參考文件

c# - How to open Explorer with a specific file selected? - Stack Overflow

file - C#: How to use SHOpenFolderAndSelectItems - Stack Overflow

c#: 開啟資料夾並選中檔案 - 楚人無衣 - 部落格園

SHOpenFolderAndSelectItems 函式 (shlobj_core.h) - Win32 apps - Microsoft Learn

【C#】在Windows資源管理器開啟資料夾,並選中指定的檔案或資料夾 - Tod's - 部落格園

相關文章