.NET Shell Extensions - Shell Preview Handlers (预览处理程序)
快速使用 .NET 为 Windows 或 Outlook 创建 Shell 预览处理程序!
引言
Shell 预览处理程序是可以在系统中注册的 DLL,它们允许你在 Windows 资源管理器中直接创建项目丰富的视觉预览。它们也可以在 Outlook 中使用。在本文中,我将向你展示如何使用 .NET 和一个名为 SharpShell 的库来创建一个预览处理程序扩展。我们将创建一个预览处理程序,当选中一个图标文件时,它会向用户显示该图标文件包含的所有不同图标图像,如下图所示。
系列文章
本文是 '.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 (属性表处理程序)
预览处理程序的工作原理
预览处理程序非常棒。自从为我的 SharpShell
库添加支持以来,我一直保持着预览窗格打开,并且惊叹于它们有多么有用。本质上,当你在资源管理器中选择一个文件并打开预览处理程序时,系统会执行以下操作:
- 检查注册表,查看该文件类型是否有预览处理程序。
- 如果有,则创建一个
prevhost
进程的实例,并将预览处理程序 DLL 加载到其中。 - 实例化实现了
IPreviewHandler
接口的对象。 - 告知该对象父窗口是什么,它的尺寸是多少等。
- 告知该对象渲染预览,并提供文件详细信息(路径、文件流或
IShellItem
)。
这是一个很容易接入的过程,预览处理程序有很好的文档。然而,编写所有的 COM 粘合代码需要大量的 P/Invoke 工作,即使是最微小的错误也会导致 explorer 崩溃并通常带来麻烦。所以使用 SharpShell
,这些粘合代码已经为你处理好了,只剩下你来创建你想要的 UI 和逻辑。
让我们开始创建图标预览处理程序。
步骤 1:创建项目
首先,创建一个新的 C# 类库项目。
提示:您可以使用 Visual Basic 而不是 C# - 在本文中,源代码是 C#,但创建 Visual Basic Shell Extension 的方法是一样的。
在此示例中,我们将项目命名为 'IconPreviewHandler
'。将 'Class1.cs' 文件重命名为 'IconPreviewHandler.cs'。
现在添加以下引用
System.Windows.Forms
System.Drawing
这些引用包含了 SharpShell
库的其他部分所需的各种有用的小部件,例如图标和上下文菜单。
提示:如果你使用 Nuget 安装
SharpShell
(参见“步骤 2”),则无需添加这些引用 - 它们会自动添加。
步骤 2:引用 SharpShell
现在我们需要添加对核心 SharpShell
库的引用。你可以通过几种不同的方式做到这一点:
添加引用
下载文章顶部的“SharpShell Core Library”zip 文件,并添加对 SharpShell.dll 文件的引用。
提示:本文档中的下载在撰写时是正确的 - 如果你需要最新版本,请使用 Nuget(如下所述)或从 sharpshell.codeplex.com 获取该库。
使用 Nuget
如果你安装了 Nuget,只需快速搜索 SharpShell
并直接安装即可 - 或在 https://nuget.net.cn/packages/SharpShell 获取包详细信息。
步骤 3:从 SharpPreviewHandler 派生
既然我们已经设置好了项目,就可以让 IconPreviewHandler
类从 SharpPreviewHandler
派生。SharpPreviewHandler
是预览处理程序 Shell 扩展的基类。
public class IconPreviewHandler : SharpPreviewHandler
{
}
对于预览处理程序,基类中有一个我们必须在派生类中实现的抽象函数。
DoPreview
protected abstract PreviewHandlerControl DoPreview();
DoPreview
在类必须创建预览的用户界面时被调用。它返回一个 PreviewHandlerControl
,它只是一个 UserControl
,带有一些额外的虚拟函数。通常,会发生以下情况:
- 派生类将创建一个用户控件的实例。
- 用户控件将根据
SelectedFilePath
属性中的内容进行填充。 - 用户控件将被返回。
实际上,这就是你需要做的全部!
所以对于这个项目,添加一个新的 User Control 并将其命名为 IconHandlerPreviewControl
。将其基类更改为 'PreviewHandlerControl
',并在你的 IconPreviewHandler
类中添加 'DoPreview
' 函数。
/// <summary>
/// DoPreview must create the preview handler user interface and initialize it with data
/// provided by the shell.
/// </summary>
/// <returns>
/// The preview handler user interface
/// </returns>
protected override PreviewHandlerControl DoPreview()
{
// Create the handler control
var handler = new IconPreviewHandlerControl();
// Do we have a file path? If so, we can do a preview
if(!string.IsNullOrEmpty(SelectedFilePath))
handler.DoPreview(SelectedFilePath);
// Return the handler control
return handler;
}
在这里,我们按照描述进行操作。我们实际上调用了 IconHandlerPreviewControl
的 'DoPreview
' 函数,该函数尚未编写。如果你需要详细信息,可以从文章顶部获取源代码,但实际上代码足够简单,可以直接在此处插入。
public void DoPreview(string selectedFilePath)
{
// Load the icons
try
{
var multiIcon = new MultiIcon();
multiIcon.Load(selectedFilePath);
// Add the icon images
foreach (var iconImage in multiIcon.SelectMany(singleIcon => singleIcon))
iconImages.Add(iconImage);
// Add the icons to the control
AddIconsToControl();
}
catch
{
// Maybe we could show something to the user in the preview
// window, but for now we'll just ignore any exceptions.
}
}
在这里,我们使用了出色的 IconLib 库来加载图标,然后存储每个图像。然后我们调用 AddIconsToControl
来实际将它们添加到 UI 中。
private void AddIconsToControl()
{
// Go through each icon, keep track of y pos
int yPos = 12;
foreach (var iconImage in iconImages)
{
// Create the description
var descriptionLabel = new Label
{
Location = new Point(12, yPos),
Text = string.Format("{0}x{1} - {2}",
iconImage.Size.Width, iconImage.Size.Height, iconImage.PixelFormat),
AutoSize = true,
BackColor = Color.White
};
yPos += 20;
// Create the picture box
var pictureBox = new PictureBox
{
Location = new Point(12, yPos),
Image = iconImage.Icon.ToBitmap(),
Width = iconImage.Size.Width,
Height = iconImage.Size.Height
};
yPos += iconImage.Size.Height + 20;
panelImages.Controls.Add(descriptionLabel);
panelImages.Controls.Add(pictureBox);
// Keep track of generated labels
generatedLabels.Add(descriptionLabel);
}
}
有一些成员变量我不会在此处描述,但这是功能的核心 - 遍历每个图标图像,创建一个描述它的标签和一个包含该图像的 PictureBox。
步骤 4:处理 COM 注册
只剩下几件事情要做。首先,我们必须为我们的类添加 ComVisible
属性。这是因为我们的类是一个 COM 服务器,必须对尝试使用它的其他代码可见。
[ComVisible(true)]
public class IconPreviewHandler : SharpPreviewHandler
接下来,我们必须给程序集一个强名称。有绕过此要求的方法,但通常这是最好的方法。要做到这一点,右键单击项目并选择“属性”。然后转到“签名”。选择“签名程序集”,为密钥指定“新建”,然后选择一个密钥名称。如果你愿意,可以为密钥设置项目密码,但这并非必需。
最后,我们需要将我们的扩展与我们想要使用的某些类型的 Shell 项关联起来。我们可以使用 COMServerAssociation
属性来实现这一点。
[COMServerAssociation(AssociationType.ClassOfExtension, ".ico")]
[DisplayName("Icon Preview Handler")]
public class IconPreviewHandler : SharpPreviewHandler
那么我们在这里做了什么?我们告诉 SharpShell
,在注册服务器时,我们希望将其与系统中的 icofile
类相关联。
你可以关联文件、文件夹、类、驱动器等等 - 关于使用关联属性的完整文档可在 CodePlex 网站上的 COM Server Associations 中找到。
我们还设置了 DisplayName
属性。DisplayName
用于注册表,也用于处理程序失败时(此时在预览窗格中会显示一条消息,例如“图标预览处理程序加载失败”)。
我们完成了!构建项目会创建一个 IconPreviewHandler
程序集,该程序集可以注册为 COM 服务器,将扩展添加到系统中,从而让你快速查看 ico 文件中包含哪些图像。
高级功能
PreviewHandlerControl
类具有以下 virtual
函数:
/// <summary>
/// Sets the color of the background, if possible, to coordinate with the windows
/// color scheme.
/// </summary>
/// <param name="color">The color.</param>
protected virtual void SetVisualsBackgroundColor(Color color){}
/// <summary>
/// Sets the color of the text, if possible, to coordinate with the windows
/// color scheme.
/// </summary>
/// <param name="color">The color.</param>
protected virtual void SetVisualsTextColor(Color color){}
/// <summary>
/// Sets the font, if possible, to coordinate with the windows
/// color scheme.
/// </summary>
/// <param name="font">The font.</param>
protected virtual void SetVisualsFont(Font font){}
你可以重写这些函数,以更改 UI 的颜色和字体,使其与当前系统主题中定义的样式匹配。
调试 Shell Extension
如果你看过我关于 .NET Shell 扩展的其他文章,你可能会认出“Server Manager”工具。这是 SharpShell
源代码中的一个工具,可用于帮助调试 Shell 扩展。
提示:如果你想要最新版本的工具,它们可以从 CodePlex 网站预先构建好。
打开 Server Manager 工具,使用文件 > 加载服务器加载 IconPreviewHandler.dll 文件。你也可以将服务器拖到主窗口中。选择服务器将显示一些关于它的详细信息。选择服务器。
现在选择“在测试 Shell 中测试服务器”。这会打开测试 Shell 窗口。与服务器关联的任何文件都会以粗体突出显示。你可以单击其中一个文件,然后在右侧选择“预览处理程序” - 这将显示预览处理程序,并允许你对其进行调试。
提示:你无需安装或注册服务器即可在测试 Shell 中进行测试。
如果你想在更现实的场景中进行调试,可以安装并注册服务器(使用“服务器”菜单),然后打开测试 Shell,接着选择“打开 Shell 对话框”。这将创建一个文件打开对话框,你可以使用它来调用预览处理程序功能。请记住,如果你想调试预览处理程序,必须附加到 'prevhost.exe' 进程,而不是 'explorer.exe' 进程。
安装和注册 Shell Extension
你可以在 .NET Shell 扩展 - Shell 上下文菜单的“安装和注册 Shell 扩展”部分中查看有关如何安装和注册这些扩展的详细信息 - 该过程是相同的。
有用资源
- 构建预览处理程序:MSDN 上关于预览处理程序的有用文档来源。
历史
- 2014 年 5 月 20 日:初始版本