I want to add my own new menu to Chromium, but I’m having a problem

I am new to Chromium development.
Add a new parent menu to the top right menu of Chromium, create a submenu called Help and Settings, for example, and click the internal URL (ex: test://settings or test://help custom) when you click on each submenu. If one scheme is difficult, I would like to open the HTML I wrote through chrome://test-settings or chrome://help. But I’ve been trying for two weeks and I keep getting stuck.

With the code I’ve modified so far, I can see the submenu in the menu and click on it, but it doesn’t show up in the console:

[2558072:2558072:0710/121539.983950:INFO:chrome_web_ui_controller_factory.cc(414)] Debug LHS: URL spec is securitynet://help/
[2558072:2558072:0710/121539.983991:INFO:chrome_web_ui_controller_factory.cc(415)] Debug LHS: URL scheme is securitynet
[2558072:2558072:0710/121539.984023:INFO:chrome_web_ui_controller_factory.cc(416)] Debug LHS: URL host is help
[2558072:2558072:0710/121539.984054:INFO:chrome_web_ui_controller_factory.cc(417)] Debug LHS: URL host_piece is help
[2558072:2558072:0710/121539.984083:INFO:chrome_web_ui_controller_factory.cc(418)] Debug LHS: URL path is /
[2558072:2558072:0710/121539.984116:INFO:chrome_web_ui_controller_factory.cc(422)] Processing LHS1 SecurityNet VPN URL: securitynet://help/
[2558072:2558072:0710/121539.984147:INFO:chrome_web_ui_controller_factory.cc(423)] Processing URL host is help
[2558072:2558072:0710/121539.984181:INFO:chrome_web_ui_controller_factory.cc(425)] Creating SecurityNetVpnHelpUI
[2558072:2558072:0710/121539.984216:INFO:securitynet_vpn_ui.cc(16)] lhs SecurityNetVpnHelpUI called
[2558072:2558072:0710/121539.984294:INFO:securitynet_vpn_ui.cc(21)] AddResourcePath securityNetVpnHelpUI called
[2558072:2558072:0710/121539.984338:INFO:securitynet_vpn_ui.cc(23)] SetDefaultResource securityNetVpnHelpUI called
[2558072:2558072:0710/121539.984369:INFO:securitynet_vpn_ui.cc(25)] Current WebUI Bindings: 3
[2558072:2558072:0710/121540.000615:INFO:chrome_web_ui_controller_factory.cc(414)] Debug LHS: URL spec is securitynet://help/
[2558072:2558072:0710/121540.000696:INFO:chrome_web_ui_controller_factory.cc(415)] Debug LHS: URL scheme is securitynet
[2558072:2558072:0710/121540.000735:INFO:chrome_web_ui_controller_factory.cc(416)] Debug LHS: URL host is help
[2558072:2558072:0710/121540.000767:INFO:chrome_web_ui_controller_factory.cc(417)] Debug LHS: URL host_piece is help
[2558072:2558072:0710/121540.000798:INFO:chrome_web_ui_controller_factory.cc(418)] Debug LHS: URL path is /
[2558072:2558072:0710/121540.000832:INFO:chrome_web_ui_controller_factory.cc(422)] Processing LHS1 SecurityNet VPN URL: securitynet://help/
[2558072:2558072:0710/121540.000863:INFO:chrome_web_ui_controller_factory.cc(423)] Processing URL host is help
[2558072:2558072:0710/121540.000910:INFO:chrome_web_ui_controller_factory.cc(425)] Creating SecurityNetVpnHelpUI
[2558072:2558072:0710/121540.001025:FATAL:render_frame_host_impl.cc(6596)] Check failed: false. Calling AllowBindings for a process not locked to WebUI:{ securitynet://help/ }

It logs and just quits.

I am attaching code that I modified or added arbitrarily. Please advise if you can.

generated_resources.grd

  <message name="IDS_SECURITYNET_VPN_MENU" desc="The label of the SecuritynetVPN menu item">
      SecuritynetVPN
    </message>
    <message name="IDS_SECURITYNET_VPN_HELP" desc="The label of the SecuritynetVPN Help submenu item">
      SecuritynetVPN Help
    </message>
    <message name="IDS_SECURITYNET_VPN_SETTINGS" desc="The label of the SecuritynetVPN Settings submenu item">
      SecuritynetVPN Settings
    </message>
  </messages>
  <includes>
    <include name="IDR_SECURITYNET_VPN_HELP_HTML" file="../browser/resources/securitynet/help.html" type="BINDATA" />
    <include name="IDR_SECURITYNET_VPN_SETTINGS_HTML" file="../browser/resources/securitynet/settings.html" type="BINDATA" />
  </includes>

chrome_web_ui_controller_factory.cc

//securitynet
template <>
WebUIController* NewWebUI<SecurityNetVpnHelpUI>(WebUI* web_ui, const GURL& url) {
  return new SecurityNetVpnHelpUI(web_ui);
}

template <>
WebUIController* NewWebUI<SecurityNetVpnSettingsUI>(WebUI* web_ui, const GURL& url) {
  return new SecurityNetVpnSettingsUI(web_ui);
}

WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
                                             Profile* profile,
                                             const GURL& url) {

  LOG(INFO) << "Debug LHS: URL spec is " << url.spec();
  LOG(INFO) << "Debug LHS: URL scheme is " << url.scheme();
  LOG(INFO) << "Debug LHS: URL host is " << url.host();
  LOG(INFO) << "Debug LHS: URL host_piece is " << url.host_piece();
  LOG(INFO) << "Debug LHS: URL path is " << url.path();

//securitynet
if (url.SchemeIs(chrome::kSecuritynetVPNScheme)) {
  LOG(INFO) << "Processing LHS1 SecurityNet VPN URL: " << url.spec();
  LOG(INFO) << "Processing URL host is " << url.host();
  if (url.host() == "help") {
    LOG(INFO) << "Creating SecurityNetVpnHelpUI";
    return &NewWebUI<SecurityNetVpnHelpUI>;
  } else if (url.host() == "settings") {
    LOG(INFO) << "Creating SecurityNetVpnSettingsUI";
    return &NewWebUI<SecurityNetVpnSettingsUI>;
  }
  LOG(WARNING) << "Unknown SecurityNet VPN URL: " << url.spec();
}

app_menu_model.cc

void AppMenuModel::Build() {
  // Build (and, by extension, Init) should only be called once.
  DCHECK_EQ(0u, GetItemCount());

  // securitynet:SecuritynetVPN 메뉴 추가
  auto securitynet_vpn_sub_menu = std::make_unique<ui::SimpleMenuModel>(this);
  securitynet_vpn_sub_menu->AddItemWithStringId(IDC_SECURITYNET_VPN_HELP, IDS_SECURITYNET_VPN_HELP);
  securitynet_vpn_sub_menu->AddItemWithStringId(IDC_SECURITYNET_VPN_SETTINGS, IDS_SECURITYNET_VPN_SETTINGS);

  AddSubMenuWithStringIdAndVectorIcon(this, IDC_SECURITYNET_VPN_MENU, IDS_SECURITYNET_VPN_MENU, securitynet_vpn_sub_menu.get(), kNewWindowIcon);

  sub_menus_.push_back(std::move(securitynet_vpn_sub_menu));

void AppMenuModel::ExecuteCommand(int command_id, int event_flags) {

  switch (command_id) {
    // ... (기존 case 문들)
    case IDC_SECURITYNET_VPN_HELP:
      chrome::OpenSecuritynetVPNHelp(browser_);
      break;
    case IDC_SECURITYNET_VPN_SETTINGS:
      chrome::OpenSecuritynetVPNSettings(browser_);
      break;
    default:
      break;
    // ... (기존 default case)
  }

chrome_content_client.cc

void ChromeContentClient::AddAdditionalSchemes(Schemes* schemes) {
  for (auto* standard_scheme : kChromeStandardURLSchemes)
    schemes->standard_schemes.push_back(standard_scheme);
  // SecurityNet VPN 스키마 추가
  
  schemes->standard_schemes.push_back(chrome::kSecuritynetVPNScheme);
  schemes->secure_schemes.push_back(chrome::kSecuritynetVPNScheme);
  schemes->cors_enabled_schemes.push_back(chrome::kSecuritynetVPNScheme);
  schemes->csp_bypassing_schemes.push_back(chrome::kSecuritynetVPNScheme);
  schemes->local_schemes.push_back(chrome::kSecuritynetVPNScheme);
  schemes->no_access_schemes.push_back(chrome::kSecuritynetVPNScheme);
  schemes->service_worker_schemes.push_back(chrome::kSecuritynetVPNScheme);
  LOG(INFO) << "SecurityNet VPN scheme added to additional schemes";

securitynet_vpn_ui.cc

#include "chrome/browser/ui/webui/securitynet_vpn_ui.h"

#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "base/logging.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/bindings_policy.h"

SecurityNetVpnHelpUI::SecurityNetVpnHelpUI(content::WebUI* web_ui)
    : TopChromeWebUIController(web_ui, /*enable_chrome_send=*/true) {
    LOG(INFO) << "lhs SecurityNetVpnHelpUI called";

    web_ui->SetBindings(content::BINDINGS_POLICY_WEB_UI);
    LOG(INFO) << "Current WebUI Bindings: " << web_ui->GetBindings();

    content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
        web_ui->GetWebContents()->GetBrowserContext(),
        chrome::kSecuritynetVPNScheme);
    source->AddResourcePath("help.html", IDR_SECURITYNET_VPN_HELP_HTML);
    LOG(INFO) << "AddResourcePath securityNetVpnHelpUI called";
    source->SetDefaultResource(IDR_SECURITYNET_VPN_HELP_HTML);
    LOG(INFO) << "SetDefaultResource securityNetVpnHelpUI called";

    content::RenderFrameHost* frame_host = web_ui->GetWebContents()->GetPrimaryMainFrame();
    frame_host->AllowBindings(content::BINDINGS_POLICY_WEB_UI);
    LOG(INFO) << "Frame Host Bindings After: " << frame_host->GetEnabledBindings();
}

SecurityNetVpnHelpUI::~SecurityNetVpnHelpUI() = default;

SecurityNetVpnSettingsUI::SecurityNetVpnSettingsUI(content::WebUI* web_ui)
    : TopChromeWebUIController(web_ui, /*enable_chrome_send=*/true) {
    LOG(INFO) << "lhs SecurityNetVpnSettingsUI called";

    web_ui->SetBindings(content::BINDINGS_POLICY_WEB_UI);
    LOG(INFO) << "Current WebUI Bindings: " << web_ui->GetBindings();

    content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
        web_ui->GetWebContents()->GetBrowserContext(),
        chrome::kSecuritynetVPNScheme);
    source->AddResourcePath("settings.html", IDR_SECURITYNET_VPN_SETTINGS_HTML);
    LOG(INFO) << "AddResourcePath SecurityNetVpnSettingsUI called";
    source->SetDefaultResource(IDR_SECURITYNET_VPN_SETTINGS_HTML);
    LOG(INFO) << "SetDefaultResource SecurityNetVpnSettingsUI called";

    content::RenderFrameHost* frame_host = web_ui->GetWebContents()->GetPrimaryMainFrame();
    frame_host->AllowBindings(content::BINDINGS_POLICY_WEB_UI);
    LOG(INFO) << "Frame Host Bindings After: " << frame_host->GetEnabledBindings();
}

SecurityNetVpnSettingsUI::~SecurityNetVpnSettingsUI() = default;

securitynet_vpn_ui.h

#ifndef CHROME_BROWSER_UI_WEBUI_SECURITYNET_VPN_SECURITYNET_VPN_UI_H_
#define CHROME_BROWSER_UI_WEBUI_SECURITYNET_VPN_SECURITYNET_VPN_UI_H_

#include "chrome/browser/ui/webui/top_chrome/top_chrome_web_ui_controller.h"

class SecurityNetVpnHelpUI : public TopChromeWebUIController {
 public:
  explicit SecurityNetVpnHelpUI(content::WebUI* web_ui);
  ~SecurityNetVpnHelpUI() override;

  SecurityNetVpnHelpUI(const SecurityNetVpnHelpUI&) = delete;
  SecurityNetVpnHelpUI& operator=(const SecurityNetVpnHelpUI&) = delete;
};

class SecurityNetVpnSettingsUI : public TopChromeWebUIController {
 public:
  explicit SecurityNetVpnSettingsUI(content::WebUI* web_ui);
  ~SecurityNetVpnSettingsUI() override;

  SecurityNetVpnSettingsUI(const SecurityNetVpnSettingsUI&) = delete;
  SecurityNetVpnSettingsUI& operator=(const SecurityNetVpnSettingsUI&) = delete;
};

#endif  // CHROME_BROWSER_UI_WEBUI_SECURITYNET_VPN_SECURITYNET_VPN_UI_H_

chrome/common/webui_url_constants.cc


namespace chrome {

const char kSecuritynetVPNScheme[] = "securitynet";
const char kSecuritynetVPNHelpHost[] = "help";
const char kSecuritynetVPNSettingsHost[] = "settings";

When you click on the submenu of the menu, it moves to securitynet://help in the address bar and loads help.html.

New contributor

heeseok lee is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật