跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++大前端

通过 URI Scheme 从 Web 页面启动本地 C++ 应用

本文介绍如何通过 URI Scheme 技术,在 Web 页面中触发并启动本地 C++ 客户端程序。核心在于将自定义协议注册到 Windows 注册表,使浏览器识别特定链接格式后调用本地可执行文件。文章涵盖需求分析、注册表结构配置、C++ 代码实现及命令行参数传递方案,并讨论了单实例运行、进程间通信等实际场景中的细节处理。

ApiHolic发布于 2026/4/5更新于 2026/6/916 浏览
通过 URI Scheme 从 Web 页面启动本地 C++ 应用

通过 URI Scheme 从 Web 页面启动本地 C++ 应用

需求背景

近期收到多个第三方厂商的需求,希望在不进行复杂 SDK 二次开发的前提下,直接从 Web 页面启动本地的 C++ 客户端软件。这类需求通常分为三类:仅启动程序;启动并自动登录;启动并执行特定业务操作(如加入会议)。本质上,这要求 Web 端能向本地程序传递命令行参数,由程序解析并执行相应逻辑。

以常见的腾讯会议为例,点击 IM 软件中的会议链接,浏览器会询问是否打开本地客户端。确认后,本地程序启动并自动加入指定会议。这种体验的核心技术就是 URI Scheme。

什么是 URI Scheme

URI(Uniform Resource Identifier)是统一资源标识符。URI Scheme 是一种技术规范,允许通过特定的 URL 前缀(如 qqgame://)来触发本地应用程序。

要实现 Web 页面启动本地程序,必须先在系统中注册该 Scheme。具体做法是在 Windows 注册表的 HKEY_CLASSES_ROOT 下创建自定义节点,关联目标应用程序的路径和启动命令。当浏览器遇到匹配的链接时,会读取注册表信息并调用对应的可执行文件。

注册表配置与 C++ 实现

我们需要编写 C++ 代码将 Scheme 信息写入注册表。以下是关键步骤的实现逻辑:

首先,在 HKEY_CLASSES_ROOT 下创建根节点,例如 XyzlinkProtocol。设置默认值为协议名称,并添加 URL Protocol 键值指向可执行文件路径。

接着,创建 DefaultIcon 节点,设置图标路径。

最后,构建 shell\open\command 层级。这是最关键的一步,command 节点的默认值决定了程序如何被启动。为了支持参数传递,我们通常使用 %1 占位符。

下面是完整的注册表写入函数示例:

BOOL WriteURISchemaReg() {
    // 获取当前安装路径
    CString strExePath = m_strInstallPath + _T("xyzlink.exe");
    CString strProtocolName = _T("XyzlinkProtocol");
    HKEY hRootKey = NULL;
    DWORD dwKeyValue = 0;
    DWORD dwDisposition = 0;
    UCHAR szBuf[MAX_PATH] = { 0 };

    // 1. 创建根节点 RootNode
    long lRet = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, strProtocolName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRootKey, &dwDisposition);
    if (lRet != ERROR_SUCCESS) return FALSE;

    // 设置协议名称
    lRet = ::RegSetValueEx(hRootKey, , , REG_SZ, (LPBYTE)(LPCTSTR)strProtocolName, strProtocolName.() * (TCHAR));
     (lRet != ERROR_SUCCESS) { (hRootKey);  FALSE; }

    
    CString strKey = _T();
    lRet = (hRootKey, strKey.(), , REG_SZ, (LPBYTE)(LPCTSTR)strExePath, strExePath.() * (TCHAR));
     (lRet != ERROR_SUCCESS) { (hRootKey);  FALSE; }

    
    strKey = _T();
    HKEY hDefaultIconKey = ;
    lRet = (hRootKey, strKey, , , , KEY_ALL_ACCESS, , &hDefaultIconKey, &dwDisposition);
     (lRet != ERROR_SUCCESS) { (hRootKey);  FALSE; }

    CString strExePathPlus = strExePath + _T();
    lRet = (hDefaultIconKey, , , REG_SZ, (LPBYTE)(LPCTSTR)strExePathPlus, strExePathPlus.() * (TCHAR));
     (lRet != ERROR_SUCCESS) { (hDefaultIconKey); (hRootKey);  FALSE; }

    
    strKey = _T();
    HKEY hShellKey = ;
    lRet = (hDefaultIconKey, strKey, , , , KEY_ALL_ACCESS, , &hShellKey, &dwDisposition);
     (lRet != ERROR_SUCCESS) { (hDefaultIconKey); (hRootKey);  FALSE; }

    strKey = _T();
    HKEY hOpenKey = ;
    lRet = (hShellKey, strKey, , , , KEY_ALL_ACCESS, , &hOpenKey, &dwDisposition);
     (lRet != ERROR_SUCCESS) { (hDefaultIconKey); (hRootKey); (hShellKey);  FALSE; }

    strKey = _T();
    HKEY hCommandKey = ;
    lRet = (hOpenKey, strKey, , , , KEY_ALL_ACCESS, , &hCommandKey, &dwDisposition);
     (lRet != ERROR_SUCCESS) { (hOpenKey); (hDefaultIconKey); (hRootKey); (hShellKey);  FALSE; }

    
    CString strCmdParam;
    strCmdParam.(_T(), strExePath);
    lRet = (hCommandKey, , , REG_SZ, (LPBYTE)(LPCTSTR)strCmdParam, strCmdParam.() * (TCHAR));
     (lRet != ERROR_SUCCESS) {
        (hCommandKey); (hOpenKey); (hDefaultIconKey); (hRootKey); (hShellKey);
         FALSE;
    }

    (hCommandKey); (hOpenKey); (hDefaultIconKey); (hRootKey); (hShellKey);
     TRUE;
}
NULL
0
GetLength
sizeof
if
RegCloseKey
return
// 设置 URL Protocol 键值
"URL Protocol"
RegSetValueEx
GetBuffer
0
0
GetLength
sizeof
if
RegCloseKey
return
// 2. 创建 DefaultIcon 节点
"DefaultIcon"
NULL
RegCreateKeyEx
0
NULL
0
NULL
if
RegCloseKey
return
",1"
RegSetValueEx
NULL
0
GetLength
sizeof
if
RegCloseKey
RegCloseKey
return
// 3. 创建 shell\open\command 层级
"shell"
NULL
RegCreateKeyEx
0
NULL
0
NULL
if
RegCloseKey
RegCloseKey
return
"open"
NULL
RegCreateKeyEx
0
NULL
0
NULL
if
RegCloseKey
RegCloseKey
RegCloseKey
return
"command"
NULL
RegCreateKeyEx
0
NULL
0
NULL
if
RegCloseKey
RegCloseKey
RegCloseKey
RegCloseKey
return
// 设置启动命令,包含 %1 参数占位符
Format
"\"%s\" \"%%1\""
RegSetValueEx
NULL
0
GetLength
sizeof
if
RegCloseKey
RegCloseKey
RegCloseKey
RegCloseKey
RegCloseKey
return
RegCloseKey
RegCloseKey
RegCloseKey
RegCloseKey
RegCloseKey
return

Web 端调用方式

注册完成后,在 HTML 页面中只需使用标准链接即可触发。保存为 .html 文件并在浏览器打开测试:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Start exe demo</title>
</head>
<body>
    <a href="XyzlinkProtocol://">打开目标程序</a>
</body>
</html>

如果需要在启动时传递参数,链接格式应为 XyzlinkProtocol://参数内容。注意,如果注册表中设置了 %1,则 URL 必须带参数,否则可能无法启动。

进阶场景处理

在实际项目中,还需要考虑以下细节:

  1. 未安装检测:如果用户未安装客户端,点击链接应提示跳转至下载页。
  2. 单实例运行:若程序已启动,需将现有窗口置顶,而不是重复启动新进程。
  3. 参数传递与状态同步:如果程序已登录但需要执行新操作(如加入新会议),需通过 IPC 机制将参数发送给已运行的进程,而非重新启动。

对于参数传递,建议定义统一的协议头,例如 launchtype=noparam 表示纯启动,autologin 表示自动登录。程序启动后解析这些标识,决定后续行为。

微软官方文档提供了更详细的注册表规范说明,建议参考 Registering an Application to a URI Scheme。

目录

  1. 通过 URI Scheme 从 Web 页面启动本地 C++ 应用
  2. 需求背景
  3. 什么是 URI Scheme
  4. 注册表配置与 C++ 实现
  5. Web 端调用方式
  6. 进阶场景处理
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Web 到小程序跨平台迁移:PixiJS 高性能渲染方案
  • 利用 AI 智能体快速完成 C 语言及前端实训项目
  • Vue.js 核心语法与原理详解
  • FPGA 实现 CAN 总线接口与数据帧解析
  • AI Agent 中的 Skills:概念与核心作用
  • Python 数据分析学习路线总结
  • OpenClaw 启动后 Web 控制面板返回 Not Found 错误排查
  • Spring Bean 作用域、生命周期与自动装配源码解析
  • OpenClaw 与企业即时通讯平台集成架构研究
  • Python 开发 MongoDB 数据库 MCP Server 实战指南
  • Trae 集成 Figma MCP 实现前端代码自动生成
  • 通过仓库互动学习 Git 和 GitHub 协作
  • 算法基础:一维前缀和与最大子段和实战
  • VSCode 远程 SSH 连接下 Copilot Claude Agent 异常修复
  • Copilot Chat 接入第三方 OpenAI 接口配置技巧
  • LLaMA 模型动态库加载失败排查与修复指南
  • AWVS Web 安全漏洞扫描工具安装与使用指南
  • Python 数据分析核心技术指南:流程、工具与实战
  • 本地电脑搭建 PyTorch 深度学习环境指南
  • iRobotCAM 机器人离线编程软件在激光加工中的高精度应用解析

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online