You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何扩展Windows 11搜索能力以调用自定义API并返回搜索结果

自定义Windows 11搜索协议处理器不生效的解决方案

核心问题诊断

你的实现存在以下关键问题,导致搜索结果无法正常显示:

  1. ISearchProtocol接口定义不符合官方规范:Windows Search要求的协议处理器接口包含特定方法签名,你当前的定义缺少必要方法与参数,无法被系统正确调用。
  2. 未获取实际搜索查询:代码硬编码了查询字符串,无法响应用户输入的关键词。
  3. 异步处理逻辑错误:同步方法中使用Task.Wait()可能引发死锁,导致处理器无法正常返回结果。
  4. COM注册不完整:.NET 8类库的COM注册需使用官方工具,手动修改注册表可能遗漏关键配置项。
  5. 搜索结果格式不兼容:返回的自定义JSON结构不符合Windows Search解析要求,系统无法识别展示。

修复步骤

1. 修正ISearchProtocol接口定义

按照Windows Search官方规范重新定义接口及回调:

using System.Runtime.InteropServices;

namespace MySearchHandler;

[ComVisible(true)]
[Guid("3958f382-369b-4d2f-809c-3bab43e5bf54")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISearchProtocol
{
    void Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszProtocol);
    void SetSite([MarshalAs(UnmanagedType.IUnknown)] object pUnkSite);
    void GetSite(ref Guid riid, out IntPtr ppvSite);
    void StartQuery([MarshalAs(UnmanagedType.LPWStr)] string pszQuery, 
                    [MarshalAs(UnmanagedType.Interface)] ISearchProtocolCB pProtocolCB);
    void CancelQuery();
    void Shutdown();
}

[ComVisible(true)]
[Guid("12345678-ABCD-EFGH-IJKL-1234567890AB")] // 替换为专属GUID
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISearchProtocolCB
{
    void ReportResult([MarshalAs(UnmanagedType.LPWStr)] string pszURL, 
                      [MarshalAs(UnmanagedType.LPWStr)] string pszTitle, 
                      [MarshalAs(UnmanagedType.LPWStr)] string pszDescription, 
                      ref PROPVARIANT[] pProps, 
                      int dwFlags);
}

[StructLayout(LayoutKind.Sequential)]
public struct PROPVARIANT
{
    public ushort vt;
    public ushort wReserved1;
    public ushort wReserved2;
    public ushort wReserved3;
    public IntPtr pVal;
}

2. 重写SearchHandler实现

修改处理器类,正确获取用户查询并返回系统兼容的结果:

using System.Runtime.InteropServices;

namespace MySearchHandler;

[ComVisible(true)]
[Guid("37561b26-cd9f-4afe-9e36-00558430fde7")]
[ClassInterface(ClassInterfaceType.None)]
public class SearchHandler : ISearchProtocol
{
    private ISearchProtocolCB _callback;
    private string _currentQuery;

    public void Initialize(string pszProtocol)
    {
        // 协议初始化逻辑
    }

    public void SetSite(object pUnkSite)
    {
        // 设置站点上下文
    }

    public void GetSite(ref Guid riid, out IntPtr ppvSite)
    {
        ppvSite = IntPtr.Zero;
    }

    public void StartQuery(string pszQuery, ISearchProtocolCB pProtocolCB)
    {
        _currentQuery = pszQuery;
        _callback = pProtocolCB;
        
        // 异步处理查询,避免阻塞系统线程
        _ = ProcessQueryAsync();
    }

    private async Task ProcessQueryAsync()
    {
        try
        {
            // 调用API获取结果(替换为你的实际API逻辑)
            var results = await FetchResultsFromApi(_currentQuery);
            
            foreach (var result in results)
            {
                var emptyProps = new PROPVARIANT[0];
                // 向系统报告单条结果
                _callback.ReportResult(
                    result.Url,
                    result.Title,
                    result.Snippet,
                    ref emptyProps,
                    0
                );
            }
        }
        catch (Exception)
        {
            // 异常处理逻辑
        }
        finally
        {
            // 报告查询完成(SP_REPORT_DONE标识)
            _callback.ReportResult(null, null, null, null, 1);
        }
    }

    private async Task<List<SearchResult>> FetchResultsFromApi(string query)
    {
        // 模拟API调用延迟
        await Task.Delay(100);
        
        // 根据用户关键词过滤结果
        return new List<SearchResult>
        {
            new SearchResult { Title = "First Result", Url = "http://example.com/first", Snippet = "This is the first result." },
            new SearchResult { Title = "Second Result", Url = "http://example.com/second", Snippet = "This is the second result." }
        }.Where(r => r.Title.Contains(query, StringComparison.OrdinalIgnoreCase)).ToList();
    }

    public void CancelQuery()
    {
        // 查询取消逻辑
    }

    public void Shutdown()
    {
        // 资源清理逻辑
    }
}

public class SearchResult
{
    public string Title { get; set; }
    public string Url { get; set; }
    public string Snippet { get; set; }
}

3. 更新.csproj配置

启用COM互操作并生成类型库:

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

  <PropertyGroup>
    <TargetFramework>net8.0-windows</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <ComVisible>true</ComVisible>
    <AssemblyName>MySearchHandler</AssemblyName>
    <OutputType>Library</OutputType>
    <RegisterForComInterop>true</RegisterForComInterop>
    <GenerateTypeLib>true</GenerateTypeLib>
  </PropertyGroup>

</Project>

4. 正确注册COM组件

以管理员身份运行PowerShell,执行以下命令:

# 替换为你的DLL实际路径
$dllPath = "C:\Users\<userName>\source\repos\MySearchHandler\bin\Release\net8.0-windows\MySearchHandler.dll"
regasm.exe $dllPath /codebase /tlb

5. 创建搜索连接器(.osdx文件)

新建MySearchConnector.osdx文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>My Custom Search</ShortName>
  <Description>Search results from my API</Description>
  <InputEncoding>UTF-8</InputEncoding>
  <Url type="application/x-suggestions+json" template="mysearchhandler://{searchTerms}"/>
  <Url type="text/html" template="mysearchhandler://{searchTerms}"/>
</OpenSearchDescription>

双击该文件,将自定义搜索添加到Windows搜索列表。

6. 重启Windows Search服务

Restart-Service WSearch

验证步骤

  1. 在Windows搜索框输入first,检查是否显示自定义结果。
  2. 若仍无结果,打开事件查看器,查看Applications and Services Logs > Microsoft > Windows > Search下的错误日志定位问题。

内容的提问来源于stack exchange,提问作者Ved Singhal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:59:48