65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Shell Extensions - Shell Preview Handlers (预览处理程序)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (23投票s)

2013年1月26日

MIT

8分钟阅读

viewsIcon

151364

downloadIcon

6306

快速使用 .NET 为 Windows 或 Outlook 创建 Shell 预览处理程序!

引言

Shell 预览处理程序是可以在系统中注册的 DLL,它们允许你在 Windows 资源管理器中直接创建项目丰富的视觉预览。它们也可以在 Outlook 中使用。在本文中,我将向你展示如何使用 .NET 和一个名为 SharpShell 的库来创建一个预览处理程序扩展。我们将创建一个预览处理程序,当选中一个图标文件时,它会向用户显示该图标文件包含的所有不同图标图像,如下图所示。

上图:我电脑上的一个图标文件夹。当选中一个图标并打开预览窗格时,图标预览处理程序扩展会显示文件中每个不同的图标图像。

系列文章

本文是 '.NET Shell Extensions' 系列的一部分,该系列包括

  1. .NET Shell Extensions - Shell Context Menus (右键菜单扩展)
  2. .NET Shell Extensions - Shell Icon Handlers (图标处理程序)
  3. .NET Shell Extensions - Shell Info Tip Handlers (信息提示处理程序)
  4. .NET Shell Extensions - Shell Drop Handlers (拖放处理程序)
  5. .NET Shell Extensions - Shell Preview Handlers (预览处理程序)
  6. .NET Shell Extensions - Shell Icon Overlay Handlers (图标叠加处理程序)
  7. .NET Shell Extensions - Shell Thumbnail Handlers (缩略图处理程序)
  8. .NET Shell Extensions - Shell Property Sheets (属性表处理程序)

预览处理程序的工作原理

预览处理程序非常棒。自从为我的 SharpShell 库添加支持以来,我一直保持着预览窗格打开,并且惊叹于它们有多么有用。本质上,当你在资源管理器中选择一个文件并打开预览处理程序时,系统会执行以下操作:

  1. 检查注册表,查看该文件类型是否有预览处理程序。
  2. 如果有,则创建一个 prevhost 进程的实例,并将预览处理程序 DLL 加载到其中。
  3. 实例化实现了 IPreviewHandler 接口的对象。
  4. 告知该对象父窗口是什么,它的尺寸是多少等。
  5. 告知该对象渲染预览,并提供文件详细信息(路径、文件流或 IShellItem)。

这是一个很容易接入的过程,预览处理程序有很好的文档。然而,编写所有的 COM 粘合代码需要大量的 P/Invoke 工作,即使是最微小的错误也会导致 explorer 崩溃并通常带来麻烦。所以使用 SharpShell,这些粘合代码已经为你处理好了,只剩下你来创建你想要的 UI 和逻辑。

让我们开始创建图标预览处理程序。

步骤 1:创建项目

首先,创建一个新的 C# 类库项目。

提示:您可以使用 Visual Basic 而不是 C# - 在本文中,源代码是 C#,但创建 Visual Basic Shell Extension 的方法是一样的。

在此示例中,我们将项目命名为 'IconPreviewHandler'。将 'Class1.cs' 文件重命名为 'IconPreviewHandler.cs'。

现在添加以下引用

  1. System.Windows.Forms
  2. 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,带有一些额外的虚拟函数。通常,会发生以下情况:

  1. 派生类将创建一个用户控件的实例。
  2. 用户控件将根据 SelectedFilePath 属性中的内容进行填充。
  3. 用户控件将被返回。

实际上,这就是你需要做的全部!

所以对于这个项目,添加一个新的 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 扩展”部分中查看有关如何安装和注册这些扩展的详细信息 - 该过程是相同的。

有用资源

历史

  • 2014 年 5 月 20 日:初始版本
© . All rights reserved.