.NET Shell Extensions - Shell Property Sheets (属性表处理程序)
使用 .NET 快速构建 Shell 属性表
引言
在本文中,我将向您展示如何使用 SharpShell 快速创建 Shell 属性表扩展。这些扩展为文件、网络共享、文件夹等 Shell 项的属性表添加额外的页面。这是我们在教程中将创建的内容的截图。
系列文章
本文是 '.NET Shell Extensions' 系列的一部分,该系列包括
- .NET Shell Extensions - Shell Context Menus (右键菜单扩展)
- .NET Shell Extensions - Shell Icon Handlers (图标处理程序)
- .NET Shell Extensions - Shell Info Tip Handlers (信息提示处理程序)
- .NET Shell Extensions - Shell Drop Handlers (拖放处理程序)
- .NET Shell Extensions - Shell Preview Handlers (预览处理程序)
- .NET Shell Extensions - Shell Icon Overlay Handlers (图标叠加处理程序)
- .NET Shell Extensions - Shell Thumbnail Handlers (缩略图处理程序)
- .NET Shell Extensions - Shell Property Sheets (属性表处理程序)
什么是 Shell 属性表扩展
从技术上讲,Shell 属性表扩展是一个 COM 服务器,它导出一个实现 IShellPropSheetExt 接口的对象。此扩展允许我们执行两项操作 - 向 Shell 属性表添加属性页,或替换它们。
现在,通常在托管环境中处理像这样的老式 API 会非常困难。您需要进行大量互操作,需要从 Win32 API 导入函数来创建属性页、创建消息循环等。我们将使用 SharpShell
库来处理所有底层工作,从而让我们轻松地创建属性页并将其添加到我们的扩展类中。
现在我们知道了什么是属性表扩展,就可以开始实现一个了。
步骤 1:创建项目
首先,创建一个新的 C# 类库项目。
提示:您可以使用 Visual Basic 而不是 C# - 在本文中,源代码是 C#,但创建 Visual Basic Shell 扩展的方法是相同的。
在此示例中,我们将项目命名为“FileTimesPropertySheet
”。
现在添加以下引用
System.Windows.Forms
System.Drawing
将“Class1.cs”重命名为“FileTimesPropertySheet.cs”。
步骤 2:引用 SharpShell
现在我们需要添加对核心 SharpShell
库的引用。你可以通过几种不同的方式做到这一点:
使用 Nuget
如果您安装了 Nuget,只需快速搜索 SharpShell 并直接安装它 - 或者在 https://nuget.net.cn/packages/SharpShell 获取包详细信息。这是最好的方法 - 您将始终获得最新版本的库,它会自动添加任何依赖项。
添加引用
在文章顶部下载“SharpShell Core Library”zip 文件,并引用下载的 SharpShell.dll 文件。
提示:本文的下载在撰写时是正确的 - 如果您需要最新版本,请使用 Nuget(如下所述)或从 sharpshell.codeplex.com 获取库。
使用 CodePlex
与从本页面获取可能不是最新版本的库不同,您始终可以从 CodePlex - SharpShell 主页 sharpshell.codeplex.com 获取最新版本的库。Nuget 将始终具有最新的稳定版本 - CodePlex 可能有可用的 Beta 版本,而 Code Project 文章将具有撰写时可用的版本。
步骤 3:继承自 SharpPropertySheet
我们必须有一个继承自 SharpPropertySheet 的类 - 这将是主扩展类。让我们采用我们命名的文件“FileTimesPropertySheet
”并立即继承自 SharpPropertySheet
public class FileTimesPropertySheet : SharpPropertySheet
现在我们将不得不创建两个抽象函数的实现
CanShowSheet
此函数返回一个 bool
。如果结果为 true
,那么我们将显示我们创建的属性表页面,否则我们将不显示它们。这是我们的实现
protected override bool CanShowSheet()
{
// We will only show the resources pages if we have ONE file selected
return SelectedItemPaths.Count() == 1;
}
因为我们继承自 SharpPropertySheet
,所以我们有一个名为“SelectedItemPaths
”的属性 - 这是一个 string
的可枚举集合,存储了用户在调用属性表时选择的路径。在我们的示例中,我们只会在只选择了一个文件的情况下显示页面。
CreatePages
此函数返回一组 SharpPropertyPage
对象 - 这些是我们即将添加到 Shell 属性表的实际属性页。
这是我们的实现将如何显示
protected override IEnumerable<SharpPropertyPage> CreatePages()
{
// Create the property sheet page
var page = new FileTimesPropertyPage();
// Return the pages we've created
return new[] {page};
}
在我们创建“FileTimesPropertyPage
”类之前,这不会起作用,我们很快就会做到这一点!
步骤 4:创建关联
我们需要定义此扩展将用于哪些 Shell 对象。这是通过使用 COMServerAssociation
属性来装饰扩展来完成的。以下是我们如何将此扩展应用于所有文件。
[COMServerAssociation(AssociationType.AllFiles)]
public class FileTimesPropertySheet : SharpPropertySheet
我们可以进行多种不同的关联 - 我们可以与文件、文件夹、具有特定扩展名的文件等进行关联。这里有一个更完整的指南,地址是 COM Server Associations 页面。
步骤 5:创建属性表页面
您可以根据需要多次执行此步骤 - 一个属性表扩展可以添加任意数量的页面。
首先,向您的类库添加一个 UserControl
,并将其命名为“FileTimesPropertyPage
”。现在打开该控件的代码隐藏文件,并将父类从“UserControl
”更改为“SharpPropertyPage
”。
这是我们可以做的第一件事 - 设置属性页的标题
/// <summary>
/// The FileTimesPropertyPage class
/// </summary>
public partial class FileTimesPropertyPage : SharpPropertyPage
{
/// <summary>
/// Initializes a new instance of the <see cref="FileTimesPropertyPage"/> class
/// </summary>
public FileTimesPropertyPage()
{
InitializeComponent();
// Set the page title
PageTitle = "File Times";
// Note: You can also set the icon to be used:
// PageIcon = Properties.Resources.SomeIcon;
}
我们通过设置 PageTitle
属性来设置页面的标题。我们还可以通过设置 PageIcon
属性来选择性地设置页面的图标。
现在 SharpPropertyPage
中有一系列虚拟函数,我们可以选择重写它们。在这里,我将介绍关键函数。
OnPropertyPageInitialised
当页面创建并即将显示给用户时,会调用此函数。如果显示了属性表,但用户没有点击此特定页面,则不会调用此函数。任何初始化都应在此处完成。在此函数中,您将获得父 SharpPropertySheet
对象,其中包含选定的文件路径。
private string filePath;
/// <summary>
/// Called when the page is initialized
/// </summary>
/// <param name="parent">The parent property sheet.</param>
protected override void OnPropertyPageInitialised(SharpPropertySheet parent)
{
// Store the file path
filePath = parent.SelectedItemPaths.First();
// Load the file times into the dialog
LoadFileTimes();
}
在我们的示例中,我们存储选定的文件路径,然后通过(LoadFileTimes
函数)从文件时间更新 UI。
我们还应该实现哪些其他函数?好吧,几乎总是,我们将希望处理“确定”和“应用”
OnPropertySheetOK 和 OnPropertySheetApply
/// <summary>
/// Called when apply is pressed on the property sheet, or the property
/// sheet is dismissed with the OK button
/// </summary>
protected override void OnPropertySheetApply()
{
// Save the changes
SaveFileTimes();
}
/// <summary>
/// Called when OK is pressed on the property sheet
/// </summary>
protected override void OnPropertySheetOK()
{
// Save the changes
SaveFileTimes();
}
这里没有什么太复杂的 - 在这个类中,我们只会保存用户所做的任何更改。
属性表页面快速参考
这是属性表页面的快速参考。
函数 | 用法 |
OnPropertyPageInitialised | 在页面必须初始化时调用。 |
OnPropertyPageSetActive | 当页面即将呈现给用户时调用。这总是在 OnPropertyPageInitialised 之后调用。 |
OnPropertyPageKillActive | 当页面即将被取消选择时调用。 |
OnPropertySheetApply | 按下“应用”按钮时调用。 |
OnPropertySheetOK | 按下“确定”按钮时调用。 |
OnPropertySheetCancel | 按下“取消”按钮时调用。 |
OnPropertySheetClose | 按下对话框右上角的“x”时调用。 |
SetPageDataChanged | 调用此函数以启用“应用”按钮。 |
步骤 6:暴露给 COM
现在我们需要做几件事来让 Shell 创建我们的类。
首先,我们必须将 COMVisible
属性添加到我们的类
[ComVisible(true)]
[COMServerAssociation(AssociationType.AllFiles)]
public class FileTimesPropertySheet : SharpPropertySheet
现在我们必须签名程序集。要做到这一点,右键单击项目并选择“属性”。然后转到“签名”。选择“签名程序集”,为密钥指定“新建”并选择一个密钥名称。如果您愿意,可以为密钥设置项目密码,但这不是必需的
调试 Shell Extension
Shell 扩展可以通过以下方式进行调试
- 从源代码运行“Server Manager”项目。
- 打开您构建的服务器,选择它,选择“安装”,然后选择适合您处理器架构的“注册”。
- 现在按“打开 Shell 对话框”按钮。
- 这将显示 Shell 打开对话框。如果您右键单击文件并选择属性,则会显示扩展,并且任何已启用的断点都将成功运行,因为 Shell 窗口位于我们附加了调试器的地址空间中。
- 调试完成后,您可以关闭 Shell 打开对话框并注销/卸载它。
安装和注册 Shell Extension
有关注册 SharpShell 扩展的指南,请参阅文章 Shell Context Menus。
历史
- 2013年4月8日:初始版本