miniblink 本身是一个核心的浏览器渲染引擎,它不包含完整的用户界面(如右键菜单),这个功能需要你的应用程序来捕获右键事件,然后调用 miniblink 的接口获取源码,并最终展示给用户。

miniblink右键查看网页源码
(图片来源网络,侵删)

下面我将分步骤详细解释如何实现这个功能,并提供 C++ 和 Delphi 的示例代码。


实现原理

整个过程可以分为以下几个步骤:

  1. 创建浏览器窗口:在你的应用程序中创建一个窗口,并嵌入 miniblink 控件。
  2. 加载网页:使用 mbk_navigatembk_navigate2 等函数加载一个 URL。
  3. 捕获右键点击事件:在你的应用程序窗口的消息循环中,捕获 WM_CONTEXTMENU 消息(对应 Windows 的右键菜单事件)。
  4. 获取当前页面的源码:在捕获到右键事件后,通过 miniblink 的 API 获取当前活动页面的 HTML 源码。
  5. 展示源码:将获取到的源码显示在一个新的窗口(如一个只读的文本编辑框)或对话框中。

核心 API 函数

实现此功能主要用到以下几个 miniblink API:

  • mbk_get_webview_by_hwnd(HWND hwnd): 根据你的应用程序窗口句柄,获取对应的 mbkWebView 对象。
  • mbk_get_current_url(mbkWebView view, char* buffer, int buffer_size): 获取当前页面的 URL(可选,用于在标题栏显示)。
  • mbk_get_page_source(mbkWebView view, char* buffer, int buffer_size): 核心函数,获取当前页面的 HTML 源码,你需要提供一个足够大的缓冲区来存储源码。
  • mbk_get_page_source_length(mbkWebView view): 获取当前页面源码的长度,这对于预先分配缓冲区大小非常有用。

示例代码

示例 1: C++ 实现

这是一个完整的 C++ 示例,展示了如何在一个简单的 Win32 窗口中嵌入 miniblink 并实现右键查看源码功能。

miniblink右键查看网页源码
(图片来源网络,侵删)
#include <windows.h>
#include <tchar.h>
#include <mbk.h> // miniblink API 头文件
#pragma comment(lib, "mbk.lib") // 链接 miniblink 库
// 全局变量
HINSTANCE g_hInst = NULL;
HWND g_hwndBrowser = NULL; // miniblink 控件的窗口句柄
mbkWebView g_mbkView = NULL;
// 函数声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void ShowPageSource(mbkWebView view);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    g_hInst = hInstance;
    // 1. 初始化 miniblink
    mbk_initialize();
    // 2. 注册窗口类
    WNDCLASSEX wc = { 0 };
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = _T("MiniblinkWindow");
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClassEx(&wc);
    // 3. 创建主窗口
    HWND hwnd = CreateWindow(_T("MiniblinkWindow"), _T("Miniblink 右键查看源码示例"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
    if (!hwnd) {
        MessageBox(NULL, _T("窗口创建失败!"), _T("错误"), MB_ICONERROR);
        return -1;
    }
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    // 4. 创建 miniblink 控件并嵌入主窗口
    g_hwndBrowser = CreateWindowEx(0, L"miniblink", L"", WS_CHILD | WS_VISIBLE, 0, 0, 800, 600, hwnd, NULL, hInstance, NULL);
    if (g_hwndBrowser) {
        g_mbkView = mbk_get_webview_by_hwnd(g_hwndBrowser);
        if (g_mbkView) {
            // 加载一个示例网页
            mbk_navigate(g_mbkView, "https://www.baidu.com");
        }
    }
    // 5. 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    // 6. 清理
    if (g_mbkView) {
        mbk_release_webview(g_mbkView);
    }
    mbk_uninitialize();
    return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_SIZE:
        // 当窗口大小改变时,调整 miniblink 控件大小
        if (g_hwndBrowser) {
            SetWindowPos(g_hwndBrowser, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER);
        }
        break;
    case WM_CONTEXTMENU:
        // 捕获右键菜单事件
        if (g_mbkView) {
            ShowPageSource(g_mbkView);
        }
        return 0; // 阻止默认的右键菜单
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
// 显示页面源码的函数
void ShowPageSource(mbkWebView view) {
    // 1. 先获取源码长度
    int length = mbk_get_page_source_length(view);
    if (length <= 0) {
        MessageBox(NULL, _T("无法获取页面源码长度或页面为空!"), _T("错误"), MB_ICONERROR);
        return;
    }
    // 2. 分配缓冲区 (+1 用于字符串结束符 '\0')
    char* source = new (std::nothrow) char[length + 1];
    if (!source) {
        MessageBox(NULL, _T("内存分配失败!"), _T("错误"), MB_ICONERROR);
        return;
    }
    // 3. 获取源码
    if (mbk_get_page_source(view, source, length + 1) == 0) { // 返回0表示成功
        // 4. 显示源码
        // 这里用一个简单的消息框来展示,对于大页面不适用
        // 实际项目中应使用一个多行文本框的对话框
        // 示例:截取前 512 个字符显示
        char preview[513] = { 0 };
        strncpy_s(preview, source, 512);
        char title[256];
        mbk_get_current_url(view, title, sizeof(title));
        std::string msg = std::string("页面源码 (预览):\n\n") + preview + "\n\n... (源码过长,已截断)";
        MessageBoxA(NULL, msg.c_str(), title, MB_OK | MB_ICONINFORMATION);
    } else {
        MessageBox(NULL, _T("获取页面源码失败!"), _T("错误"), MB_ICONERROR);
    }
    // 5. 释放缓冲区
    delete[] source;
}

示例 2: Delphi (Pascal) 实现

在 Delphi 中,实现逻辑与 C++ 类似,但语法不同,你需要使用 TWinControl 来承载 miniblink

unit UnitMain;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
  TFormMain = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure WndMessage(var Message: TMessage); message WM_CONTEXTMENU;
  private
    { Private declarations }
    FBrowserHandle: HWND;
    FMbkView: mbkWebView; // 假设 mbkWebView 类型已定义
    procedure ShowPageSource;
  public
    { Public declarations }
  end;
var
  FormMain: TFormMain;
implementation
{$R *.dfm}
uses mbk; // 引入 miniblink 的头文件
procedure TFormMain.FormCreate(Sender: TObject);
begin
  // 1. 初始化 miniblink
  mbk_initialize;
  // 2. 创建一个 TWinControl 作为容器
  // 在实际 VCL 项目中,你可能直接使用 TWinControl 或其子类
  // 这里为了演示,我们动态创建一个
  // FBrowserHandle := CreateWindowEx(0, 'miniblink', '', WS_CHILD or WS_VISIBLE, 0, 0, ClientWidth, ClientHeight, Handle, 0, HInstance, nil);
  // 更简单的方式是使用一个 Panel
  Panel1.Align := alClient;
  FBrowserHandle := Panel1.Handle; // 假设你有一个名为 Panel1 的 TPanel
  if FBrowserHandle <> 0 then
  begin
    FMbkView := mbk_get_webview_by_hwnd(FBrowserHandle);
    if Assigned(FMbkView) then
    begin
      // 加载一个网页
      mbk_navigate(FMbkView, 'https://www.delphi.org');
    end;
  end;
end;
procedure TFormMain.FormDestroy(Sender: TObject);
begin
  if Assigned(FMbkView) then
  begin
    mbk_release_webview(FMbkView);
    FMbkView := nil;
  end;
  mbk_uninitialize;
end;
procedure TFormMain.FormResize(Sender: TObject);
begin
  // 窗口大小改变时,浏览器控件会自动调整大小,因为 Panel1.Align = alClient
end;
// 捕获 WM_CONTEXTMENU 消息
procedure TFormMain.WndMessage(var Message: TMessage);
begin
  if Message.Msg = WM_CONTEXTMENU then
  begin
    if Assigned(FMbkView) then
    begin
      ShowPageSource;
    end;
    Message.Result := 1; // 阻止默认的右键菜单
  end
  else
    inherited;
end;
// 显示页面源码
procedure TFormMain.ShowPageSource;
var
  Length: Integer;
  Source: PAnsiChar;
  URL: PAnsiChar;
  Memo: TForm;
  MemoEdit: TMemo;
begin
  Length := mbk_get_page_source_length(FMbkView);
  if Length <= 0 then
  begin
    ShowMessage('无法获取页面源码或页面为空!');
    Exit;
  end;
  GetMem(Source, Length + 1);
  try
    if mbk_get_page_source(FMbkView, Source, Length + 1) = 0 then
    begin
      // 创建一个新窗体来显示源码
      Memo := TForm.Create(Self);
      Memo.Caption := '页面源码';
      Memo.Width := 800;
      Memo.Height := 600;
      Memo.Position := poScreenCenter;
      MemoEdit := TMemo.Create(Memo);
      MemoEdit.Parent := Memo;
      MemoEdit.Align := alClient;
      MemoEdit.Lines.Text := string(Source); // PAnsiChar 转 String
      Memo.ShowModal;
    end
    else
    begin
      ShowMessage('获取页面源码失败!');
    end;
  finally
    FreeMem(Source);
  end;
end;
end.

重要注意事项

  1. API 版本:确保你使用的 miniblink 库(.lib.h 文件)与你项目中调用的函数版本一致,较新的版本可能 API 有所不同。
  2. 内存管理:使用 newGetMem 分配的内存,一定要记得用 deleteFreeMem 释放,避免内存泄漏。mbk_get_page_source_length 的存在就是为了方便你精确分配内存。
  3. 缓冲区大小:在调用 mbk_get_page_source 时,传入的缓冲区大小必须大于或等于 mbk_get_page_source_length 返回的值 + 1(为了存放空字符 \0)。
  4. 异步加载:网页是异步加载的,如果你在页面还没完全加载完成时就右键点击,mbk_get_page_source 可能获取到的是不完整的源码,你可能需要监听页面的 onload 事件,确保页面加载完成后再允许查看源码,这可以通过 mbk_on_document_loaded 等回调函数实现。
  5. 用户体验:对于非常大的网页(如现代单页应用),源码可能非常长,直接用 MessageBox 或简单的文本框显示会很卡,在实际应用中,应该使用性能更好的代码编辑器组件(如 SynEdit、Scintilla 等)来展示和浏览源码。
  6. 错误处理:代码中的错误处理(如内存分配失败、API 调用失败)是必要的,这能提高程序的稳定性。

通过以上步骤和代码,你就可以成功地在基于 miniblink 的应用程序中实现右键查看网页源码的功能了。

miniblink右键查看网页源码
(图片来源网络,侵删)