【问题标题】:Windows Explorer & custom shortcut file typesWindows 资源管理器和自定义快捷方式文件类型
【发布时间】:2016-12-24 11:05:20
【问题描述】:

Windows 在文件注册中有一个名为“IsShortcut”的标志。设置此标志后,文件会自动获得快捷方式图标覆盖,并在其他方式中被视为快捷方式(例如,当您右键单击并选择“创建快捷方式”时,它只是复制文件而不是生成 .lnk文件)。 Microsoft 将此功能用于 ClickOnce 应用程序引用(扩展名 .appref-ms)。

我们将此功能用于我们自己的软件的自定义快捷方式文件类型,我们发现自 Windows 10(或可能是 Windows 8)以来,我们的自定义快捷方式不会出现在“开始”菜单中。开始菜单当然列出了.lnk 文件,它确实 也包括.appref-ms 文件,但我们自己的文件格式,其注册似乎与.appref-ms 文件没有本质区别,被排除在外从开始菜单。快捷方式文件实际存在于“开始”菜单文件夹结构 (%APPDATA%\Microsoft\Windows\Start Menu\Programs) 中,但会被 Windows 资源管理器忽略。会显示同一目录中的其他快捷方式类型(.lnk.appref-ms)。

我正在寻找有关 Windows 资源管理器如何确定它将包含在“开始”菜单中的文件格式的一些指示,以便在开发自定义格式时,可以以相同的方式指示它。我们的自定义格式在 Windows XP、Windows Vista 和 Windows 7 中运行良好,但由于某种原因,较新的开始菜单设计排除了我们的文件格式,即使它以与 .appref-ms 文件相同的方式标记为 IsShortcut

这可能吗? :-)

【问题讨论】:

  • 您是否实现了与您的文件扩展名关联的 IShellLink shell 扩展名?
  • 我们没有。 IShellLink 的大多数成员无法使用我们的快捷方式实现。例如,我们的快捷方式存储一个或多个应用程序名称值,然后将其传递给启动器。程序文件的确切路径未知,即使是,也可能不止一个。这使得无法正确实现GetPath/SetPath。但是,这不能是资源管理器确定要显示哪些快捷方式的方式,否则它必须加载和测试每个快捷方式文件才能显示给定文件夹的列表。那效果会很差。
  • 虽然...我想它确实会加载并测试它实际显示的每个快捷方式,否则图标处理程序将无法工作。我猜不排除 Explorer 可能会使用IShellLink 作为信号量来决定是否显示给定的快捷方式...
  • 如果不能正确实现GetPath/SetPath,可以尝试返回E_NOTIMPL。从 8.1 开始,链接也实现了 IPropertyStore。 shell 请求一些属性,如颜色、文本等。并且可能(我不确定只是假设)shell 请求 PKEY_CanShowInStartMenu 之类的东西。
  • 我想这值得调查。 :-)

标签: windows explorer file-type startmenu


【解决方案1】:

要在 Windows 10 开始菜单中显示链接,必须实现 IPropertyStore.GetValue 并为 PKEY_AppUserModel_ID 属性返回一些唯一字符串。

要在 Windows 10 开始菜单中显示图标,必须实现 IExtractIconW.GetIconLocation 并且具有 CLSID 类的注册表项的所有者(即 HKEY_CLASSES_ROOT\CLSID{42465C3A-83D3-4310-B27D-F271DE372764})必须是“NT Service\受信任的安装程序”

这里是示例实现(增强的 Jonathan Gilbert 代码): https://github.com/publee/CustomShortcutFileType

【讨论】:

  • 天哪!实际上,我为此联系了 Microsoft 开发人员支持,并被告知 Windows 10 只是有一个硬编码的文件类型列表,它将显示。我迫不及待地想尝试一下——如果它有效,它将恢复我们应用程序多年来缺失的一项功能,因为微软表示不再可能。非常感谢!
  • 这行得通!非常感谢!我只遇到了一个绊脚石。我的实际文件类型不使用在注册表中使用 RUNDLL32 定义的简单动词,它使用 IContextMenuHandler 实现,然后调用 CreateProcess。这确实有效,因为它会启动应用程序,但“开始”菜单不会关闭。可以连续点击多个快捷键。不知道如何告诉开始菜单它应该关闭。我在一个单独的问题中问过这个问题:stackoverflow.com/questions/59050061/…
  • 奇怪的是,我根据你的建议让它工作了,然后通过一些重构,它突然停止工作,我不知道为什么。但是,一直困扰我的一件事是 Windows SDK 提供的 IDL 似乎省略了IExtractIconW,所以我的 IDL 无法表明它已实现。在没有其他事情要做后,我在 IDL 中合成了 IExtractIconW 的定义,将其添加到我的 coclass 中的已实现列表中,突然图标又开始出现在“开始”菜单中。
【解决方案2】:

(这不是答案,但可能对您的调查有所帮助。)

我创建并注册了自己的 shell 链接扩展。 Explorer 重新启动后,它使用我的扩展并通过 IPropertyStore 接口询问不同的属性。完整日志:

TMyLinkExtension.07BA12F0 is created
  TMyLinkExtension.07BA12F0.QueryInterface IID_IShellLinkW out Result=S_OK
  TMyLinkExtension.07BA12F0.QueryInterface IID_IInitializeWithFile out Result=S_OK
  TMyLinkExtension.07BA12F0.IInitializeWithFile.Initialize started
    TMyLinkExtension.07BA12F0.IInitializeWithFile.Initialize in AFileName=C:\Users\Dec\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Total Commander\1.mylnk
    TMyLinkExtension.07BA12F0.IInitializeWithFile.Initialize in AOpenMode=STGM_READ
    TMyLinkExtension.07BA12F0.IInitializeWithFile.Initialize out Result=S_OK
  TMyLinkExtension.07BA12F0.IInitializeWithFile.Initialize finished
  TMyLinkExtension.07BA12F0.QueryInterface IID_IShellLinkW out Result=S_OK
  TMyLinkExtension.07BA12F0.QueryInterface IID_IShellLinkDataList out Result=S_OK
  TMyLinkExtension.07BA12F0.IShellLinkDataList.GetFlags started
    TMyLinkExtension.07BA12F0.IShellLinkDataList.GetFlags out Result=E_NOTIMPL
  TMyLinkExtension.07BA12F0.IShellLinkDataList.GetFlags finished
  TMyLinkExtension.07BA12F0.IShellLinkW.GetPath started
    TMyLinkExtension.07BA12F0.IShellLinkW.GetPath in AFileName=0C1FF058
    TMyLinkExtension.07BA12F0.IShellLinkW.GetPath in AFileNameLength=260
    TMyLinkExtension.07BA12F0.IShellLinkW.GetPath in @AFindData=0C1FEE08
    TMyLinkExtension.07BA12F0.IShellLinkW.GetPath in AFlags=SLGP_RAWPATH
    TMyLinkExtension.07BA12F0.IShellLinkW.GetPath out Result=E_NOTIMPL
  TMyLinkExtension.07BA12F0.IShellLinkW.GetPath finished
  TMyLinkExtension.07BA12F0.QueryInterface IID_IPropertyStore out Result=S_OK
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey=PKEY_AppUserModel_ID (Caption: AppUserModelId, CanonicalName: System.AppUserModel.ID, Type: VT_LPWSTR)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=E_INVALIDARG
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey=PKEY_AppUserModel_PreventPinning (Caption: Prevent pinning, CanonicalName: System.AppUserModel.PreventPinning, Type: VT_BOOL)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out AData.vt=VT_BOOL
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out AData=0
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=S_OK
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey={9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 23 (Caption: System.AppUserModel.ExcludedFromLauncher, CanonicalName: System.AppUserModel.ExcludedFromLauncher, Type: VT_BOOL)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out AData.vt=VT_BOOL
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out AData=0
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=S_OK
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey={9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 14 (Caption: Host environment, CanonicalName: System.AppUserModel.HostEnvironment, Type: VT_UI4)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=E_INVALIDARG
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey=PKEY_AppUserModel_StartPinOption (Caption: Start pin option, CanonicalName: System.AppUserModel.StartPinOption, Type: VT_UI4)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=E_INVALIDARG
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey={9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 18 (Caption: Installed by, CanonicalName: System.AppUserModel.InstalledBy, Type: VT_UI4)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=E_INVALIDARG
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey=PKEY_AppUserModel_IsDualMode (Caption: Is dual mode, CanonicalName: System.AppUserModel.IsDualMode, Type: VT_BOOL)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=E_INVALIDARG
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue started
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue in AKey=PKEY_Link_Arguments (Caption: Arguments, CanonicalName: System.Link.Arguments, Type: VT_LPWSTR)
    TMyLinkExtension.07BA12F0.IPropertyStore.GetValue out Result=E_INVALIDARG
  TMyLinkExtension.07BA12F0.IPropertyStore.GetValue finished
TMyLinkExtension.07BA12F0 is destroyed

我尝试使用不同的值,但仍然找不到在开始菜单中显示我的 1.mylnk 文件的方法,但也许此日志会对您有所帮助。

【讨论】:

  • 那么这个日志是打开开始菜单生成的?它正在收集有关您的快捷方式的详细信息,但最终决定不显示它?
  • 是的。是的。也许我必须在我的示例中处理更多的 PropertyKeys(全部?)以强制 Explorer 显示我的链接..
  • 因此,我为此致电 Microsoft 客户支持,经过数月的审议(字面意思),他们终于回电告诉我这超出了范围。他们建议在客户支持论坛上发帖,所以我这样做了:social.msdn.microsoft.com/Forums/windowsdesktop/en-US/… 最新信息表明这实际上是 Windows 资源管理器中的一个错误。查找两个最近的 cmets,其文本为“一个随手评论”和“另一种非常简洁的方法来重现此问题。”
  • 我不知道 Stack Overflow 是否会通知您其他人的答案或他们的 cmets。如果没有,并且如果您有兴趣,我正在写此评论以将您的注意力吸引回这篇文章,以便您可以看到 user234878 的答案,这似乎已经全面解决了问题。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多