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

CefSharp无法打开特定应用程序链接问题求助

实现WinForm+CefSharp浏览器打开外部应用(如Roblox)

你当前的CefSharp浏览器默认不会处理roblox://这类自定义协议链接,要实现点击这类链接启动本地应用,需要拦截浏览器的请求并手动处理,具体步骤如下:

1. 自定义请求处理器(拦截自定义协议)

创建一个继承自IRequestHandler的类,用来拦截浏览器请求,判断是否是需要跳转的自定义协议:

using CefSharp;
using System.Diagnostics;

public class CustomRequestHandler : IRequestHandler
{
    // 可扩展需要支持的自定义协议前缀,比如Roblox的roblox://、Steam的steam://等
    private readonly List<string> _customProtocols = new List<string> { "roblox://", "steam://" };

    public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
    {
        var url = request.Url;
        // 判断当前请求URL是否属于自定义协议
        if (_customProtocols.Any(protocol => url.StartsWith(protocol, StringComparison.OrdinalIgnoreCase)))
        {
            try
            {
                // 启动外部应用,必须设置UseShellExecute=true让系统处理协议
                Process.Start(new ProcessStartInfo(url)
                {
                    UseShellExecute = true
                });
            }
            catch (Exception ex)
            {
                // 处理启动失败的情况,比如提示用户未安装对应应用
                MessageBox.Show($"无法启动应用:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            // 返回true取消浏览器的导航操作
            return true;
        }
        // 返回false让浏览器正常处理请求
        return false;
    }

    // 以下为IRequestHandler接口的默认实现,直接返回默认值即可
    public bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture) => false;
    public void OnRenderProcessTerminated(IWebBrowser chromiumWebBrowser, IBrowser browser, CefTerminationStatus status) { }
    public bool OnCertificateError(IWebBrowser chromiumWebBrowser, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback) { callback.Dispose(); return false; }
    public void OnPluginCrashed(IWebBrowser chromiumWebBrowser, IBrowser browser, string pluginPath) { }
    public CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback) { callback.Dispose(); return CefReturnValue.Continue; }
    public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) { callback.Dispose(); return false; }
    public bool OnQuotaRequest(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, long newSize, IRequestCallback callback) { callback.Dispose(); return false; }
    public void OnProtocolExecution(IWebBrowser chromiumWebBrowser, IBrowser browser, string url, out bool allowExecution) { allowExecution = false; }
    public void OnRenderViewReady(IWebBrowser chromiumWebBrowser, IBrowser browser) { }
    public void OnResourceRedirect(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl) { }
    public bool OnResourceResponse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response) => false;
    public IResponseFilter GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response) => null;
    public void OnResourceLoadComplete(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength) { }
    public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback) { }
    public void OnDownloadCompleted(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback) { }
    public bool OnProtocolDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string url, string title, string message, bool isAlert, IJsDialogCallback callback) { callback.Dispose(); return false; }
    public bool OnBeforeUnloadDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string messageText, bool isReload, IJsDialogCallback callback) { callback.Dispose(); return false; }
    public void OnResetDialogState(IWebBrowser chromiumWebBrowser, IBrowser browser) { }
    public void OnDialogClosed(IWebBrowser chromiumWebBrowser, IBrowser browser) { }
}

2. 给浏览器绑定自定义处理器

在FrmMain_Load方法中,初始化ChromiumWebBrowser后添加设置代码:

private void FrmMain_Load(object sender, EventArgs e)
{
    browser = new ChromiumWebBrowser(txtUrl.Text);
    browser.Dock = DockStyle.Fill;
    // 绑定自定义请求处理器
    browser.RequestHandler = new CustomRequestHandler();
    this.pContainer.Controls.Add(browser);
    browser.TitleChanged += Browser_TitleChanged;
}

3. 注意事项

  • 确保目标应用已安装,且系统已注册对应自定义协议(比如Roblox安装后会自动注册roblox://)
  • 可根据需求扩展_customProtocols列表,添加更多需要支持的协议

完整修改后的代码

using CefSharp;
using CefSharp.WinForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace Lunarium
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
        }

        private void txtUrl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
                browser.Load(txtUrl.Text);
        }

        ChromiumWebBrowser browser;
        private void btnGo_Click(object sender, EventArgs e)
        {
            browser.Load(txtUrl.Text);
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            browser = new ChromiumWebBrowser(txtUrl.Text);
            browser.Dock = DockStyle.Fill;
            // 绑定自定义请求处理器
            browser.RequestHandler = new CustomRequestHandler();
            this.pContainer.Controls.Add(browser);
            browser.TitleChanged += Browser_TitleChanged;
        }
        public void favicon()
        {
            Uri url = new Uri("https://" + new Uri(browser.Address).Host + "/favicon.ico");
            try
            {
                Icon img = new Icon(new System.IO.MemoryStream(new
                WebClient().DownloadData(url)));
                this.Icon = img;
            }
            catch (Exception)
            {
                this.Icon = Properties.Resources.tempIcon;
                // 替换tempIcon为你自己的.ico图标
            }
        }
        private void Browser_TitleChanged(object sender, TitleChangedEventArgs e)
        {
            this.Invoke(new MethodInvoker(() =>
            {
                Text = e.Title;
                favicon();
            }));
        }
    }

    public class CustomRequestHandler : IRequestHandler
    {
        // 支持的自定义协议列表
        private readonly List<string> _customProtocols = new List<string> { "roblox://", "steam://" };

        public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
        {
            var url = request.Url;
            // 判断是否为自定义协议
            if (_customProtocols.Any(protocol => url.StartsWith(protocol, StringComparison.OrdinalIgnoreCase)))
            {
                try
                {
                    // 启动外部应用
                    Process.Start(new ProcessStartInfo(url)
                    {
                        UseShellExecute = true
                    });
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"无法启动应用:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                // 取消浏览器导航
                return true;
            }
            // 正常处理请求
            return false;
        }

        // 以下为接口默认实现
        public bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture) => false;
        public void OnRenderProcessTerminated(IWebBrowser chromiumWebBrowser, IBrowser browser, CefTerminationStatus status) { }
        public bool OnCertificateError(IWebBrowser chromiumWebBrowser, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback) { callback.Dispose(); return false; }
        public void OnPluginCrashed(IWebBrowser chromiumWebBrowser, IBrowser browser, string pluginPath) { }
        public CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback) { callback.Dispose(); return CefReturnValue.Continue; }
        public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) { callback.Dispose(); return false; }
        public bool OnQuotaRequest(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, long newSize, IRequestCallback callback) { callback.Dispose(); return false; }
        public void OnProtocolExecution(IWebBrowser chromiumWebBrowser, IBrowser browser, string url, out bool allowExecution) { allowExecution = false; }
        public void OnRenderViewReady(IWebBrowser chromiumWebBrowser, IBrowser browser) { }
        public void OnResourceRedirect(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl) { }
        public bool OnResourceResponse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response) => false;
        public IResponseFilter GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response) => null;
        public void OnResourceLoadComplete(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength) { }
        public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback) { }
        public void OnDownloadCompleted(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback) { }
        public bool OnProtocolDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string url, string title, string message, bool isAlert, IJsDialogCallback callback) { callback.Dispose(); return false; }
        public bool OnBeforeUnloadDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string messageText, bool isReload, IJsDialogCallback callback) { callback.Dispose(); return false; }
        public void OnResetDialogState(IWebBrowser chromiumWebBrowser, IBrowser browser) { }
        public void OnDialogClosed(IWebBrowser chromiumWebBrowser, IBrowser browser) { }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 19:39:54