☰
Delphi 12.3 集成 EmbeddedWB 源码包:搞定老项目 IE 兼容难题
2026/10/29 9:07:00 网站建设 项目流程

简介:EmbeddedWB-D5-XE12-SRC.7z是为Delphi 12.3用户提供的EmbeddedWB控件源码包,面向需要内嵌网页浏览功能或希望深入控件底层机制的开发者。该组件基于WebBrowser技术,适合在桌面程序中集成网页展示、与页面交互等场景。压缩包共226个文件,体积仅2.44MB,包含126个dcu编译单元、65个pas源码文件、22个dpk工程文件,以及res资源、inc包含文件、dproj项目配置等,既有可直接使用的编译产物,也有完整源码便于学习和按需修改。目前已有87人学习下载。通过分析这些源码,开发者可以弄清EmbeddedWB的工作机制,掌握网页交互的封装思路,并能针对特定Delphi版本或业务需求进行定制优化,是控件应用与二次开发的高价值参考资料。

1. Delphi 12.3 还在用 IE 内核?EmbeddedWB 源码包到底解决了什么

也许你刚接手一个维护了五六年的老进销存项目,业务方天天抱怨内嵌的网页白屏、打印按钮失效,碰上只认 IE 的 OA 门户和网银页面,一到新系统就翻车。这个标题里的 EmbeddedWB-D5-XE12-SRC.7z,就是能在 Delphi 12.3 上继续使用的 EmbeddedWB 控件源码包。它本质上是把系统里的 IE WebBrowser ActiveX 封装了一层,帮你接管弹窗、下载、脚本错误、右键菜单和新窗口,老项目只要把它挂上去,很多 IE 兼容问题能在控件层兜住。这个包适合手上有 Delphi 5 到 XE12 之间历史代码、想往新 IDE 迁移、又不想把整套浏览器架构换成 CEF 或 WebView2 的团队。想清楚这个前提,后面每一步都是围绕“最小改动让老网页在新环境跑起来”来做的。

2. 拿到 EmbeddedWB-D5-XE12-SRC.7z 后先做三件事:解压、路径与 IDE 注册

解压这一步没什么好说的,但真正让人翻车的是第二步。很多人喜欢把 .pas 和 .dcu 随便塞到一个目录,然后在 IDE 里点 Install 装 Dpk,结果编译时报找不到某个单元。原因很简单:EmbeddedWB 源码包设计上就是让 D5 到 XE12 共用的,目录里按版本放了不少条件编译文件,你不先把源码路径喂给工具链,IDE 就不知道去检索 SRC 目录。我一般会在 D 盘建一个固定目录,比如D:\Components\EmbeddedWB-SRC,整个解压进去,然后按下面的顺序做三件事。

2.1 源码包的目录结构怎么看:别急着双击 Dpk

先给个提醒:别看到.dpk就双击,那是给设计时包用的,我们更常遇到的是运行时包和设计时包打在一起。解压后先看有没有.dpk文件、有没有.inc或.def这类配置文件。通常包会自带一个说明文本,里面写了支持范围 D5-XE12,但真到了 Delphi 12.3 时,IDE 的编译器版本变了,默认的签名和 IFDEF 分支可能走不到编译器新版本对应的路线。这时候你就要检查项目的 Delphi 版本宏,常见做法是打开.dpk文件源码,确认有没有把版本号常量映射到编译器的条件编译符上。

; 在 .dpr / .dpk 顶部检查或补上 {$I EmbeddedWB.inc}

看这个名字就知道,它把所有版本的差异都收进一个公共头文件。像 Delphi 12.3 这种新版本,靠的是编译器版本常量(比如VER360这类),如果.inc里没有对应分支,代码就容易编译成老的默认分支,轻则少功能,重则报错。所以第一步不是安装,而是确认 EmbeddedWB.inc 里是否有对应的版本判断。

这段代码的逻辑是:$I是 Delphi 的 include 指令,运行时把公共宏注入到各单元,避免每个文件都改一遍。参数说明:宏名和实际编译器常量以包内版本文件为准,如果你解压的版本比较旧,可以手动补一段{$IFDEF VER360},但更稳妥的是去找新版源码包,因为新版会对齐新系统 API。

2.2 在 Delphi 12.3 里加 Library Path:把源码交给 IDE 的必要步骤

Delphi 在编译组件时,除了当前打开的.dpr/.dpk,还要去全局 Library Path 找.pas。很多人只把路径加进当前工程,结果换一个项目又变成“找不到单元”。正确姿势是把源码目录加到 IDE 的全局库搜索路径中。

操作路径是Tools -> Options -> Language -> Delphi -> Library -> Library Path。点开编辑框,在末尾加一行D:\Components\EmbeddedWB-SRC,或者具体指向存放核心.pas的子目录。加之后点保存,IDE 会重新建立单元索引。接着做一次 Build,看看 Output 里还有没有声称找不到 EmbeddedWB 相关单元的提示。

注意,这里不要为了省事把整个包目录全加进去,包里有 Demo 等示例,那些不是库的一部分。加太宽反而会让同名单元冲突,这属于老 Delphi 用户“血泪经验”。另外,如果你用 Git 管理工程,库路径不要写死到工程文件里,放在全局 IDE 配置更利于团队成员各自适配。

2.3 编译安装 Dpk:从源码到控件面板

路径就绪后,第二步是打开设计时包.dpk文件,点右键菜单 Compile 或 Install。这里有个坑:当前机器如果有其他版本的 EmbeddedWB 或旧 WebBrowser 残留,IDE 会加载两个同名的包,导致控件面板上出现两个TEmbeddedWB。所以安装前建议先搜索系统里是否已有EmbeddedWB.dcu/bpl,如果有,先到 IDE 的 Packages 列表里移除旧的。

如果命令行操作,我一般这样打包:

:: 先编译运行时包 msbuild EmbeddedWB.dproj /t:Build /p:Config=Release /p:Platform=Win32 :: 再编译设计时包(需要管理员权限) msbuild DclEmbeddedWB.dproj /t:Build /p:Config=Release /p:Platform=Win32

逻辑说明:EmbeddedWB 的源码包一般分成 run-time package 和 design-time package 两个 dproj,运行时包是纯业务代码,设计时包负责往 IDE 组件面板注册。你不编译运行时包直接编译设计时包,IDE 会报“找不到 EmbeddedWB.dcu”。

参数说明:

  • /t:Build告诉 msbuild 执行 Build 目标;如果只用 IDE,可以直接右键 dproj 选择 Build。
  • /p:Config=Release指定 Release 版本,避免带调试信息的老 DCU 干扰。
  • /p:Platform=Win32在 Delphi 12.3 里 Win64 和 Win32 都建议各编译一次;如果只在 32 位工程里用,Win32 足够。

编译成功后,组件面板应该出现TEmbeddedWB、TEmbeddedWBPrint等条目。记住,这一步之后必须重启一下 IDE,不然新装的包有时不会刷新到组件面板。

3. EmbeddedWB 的核心属性与事件:把 IE 内核调教成自己人

装好只是开始,真正的难点在于让 IE 内核听话。EmbeddedWB 和原生TWebBrowser最大的区别就是暴露了大量接口属性,让你能控制浏览器的每一个动作。但属性多也意味着陷阱多,我见过同事把Silent设为 True 后,网页里的脚本错误确实没了,但所有 window.confirm 对话框也没了,业务操作直接被跳过。所以要用好这些属性,你得先理解它们的层次。

3.1 接管新建窗口与弹窗:Silent、NewWindow3

老网页最常见的需求是点击链接后window.open一个新窗口。原生 TWebBrowser 通常直接弹出一个 IE 窗口,这既难看又难控制。EmbeddedWB 提供了OnNewWindow3事件,比老旧的OnNewWindow2更可靠,能拿到发起窗口的 URL、特征字符串和请求结果。

procedure TForm1.EmbeddedWB1NewWindow3(Sender: TObject; var ppDisp: IDispatch; var Cancel: WordBool; const Flags: Cardinal; const URLContext, URL: WideString); begin // 用一个 TabSheet 里的另一个 EmbeddedWB 打开,而不是新开 IE if Assigned(SecondaryWB) then begin ppDisp := SecondaryWB.Application; SecondaryWB.Navigate(URL); Cancel := True; end; end;

逻辑说明:ppDisp是新的浏览器对象接口,你在事件里赋给另一个 EmbeddedWB 的Application属性,它就会接管新窗口内容,Cancel := True可以阻止 IE 再创建独立窗口。参数说明:Flags是浏览器新窗口的特征标志,来自 IE 的NEW_WINDOW_FLAGS,一般不用改;URLContext是发起者的页面地址,URL是目标地址,用来做弹窗拦截的过滤逻辑最方便。

Silent属性要谨慎。我一般只在无人值守的自动化抓取场景里开Silent := True,正常让用户操作页面时保持 False,否则像onbeforeunload这种确认提示也会被一起吞掉,用户关了页面直接无感操作,业务数据没保存都还不知道。

3.2 拦截下载与文件类型:OnDownload、OnBeforeNavigate2

做进销存系统的人最怕网页里放一个 Excel 导出按钮,点击后 IDE 没反应,其实文件已经被 IE 下载到临时目录了。EmbeddedWB 提供OnBeforeNavigate2事件,你可以在导航发生前判断 URL 后缀或 MIME 类型,决定是让页面跳转还是自己接管文件流。配合OnDownload事件,可以阻止用户把文件存到默认目录,转而弹出自定义的保存路径对话框。

procedure TForm1.EmbeddedWB1BeforeNavigate2(Sender: TObject; const pDisp: IDispatch; const URL, Headers: OleVariant; var Cancel: WordBool); begin if ExtractFileExt(URL) = '.xlsx' then begin // 自己处理下载保存 SaveFromURL(URL); Cancel := True; end; end;

逻辑说明:Cancel设为 True 后,IE 内核不会继续执行导航,页面不会跳转,适合拦截下载链接和外部协议。参数说明:Headers里常带着 Referer 和 Cookie,如果你要在服务器端做文件访问权限校验,务必把这个值转交给下载模块,否则会拿不到带鉴权的文件。

3.3 让嵌入的网页不白屏:RegisterAsBrowser、FeatureBrowsers

新版 Windows 对 IE 内核的兼容模式越来越严格,经常出现“网页空白但不报错”的怪事。EmbeddedWB 提供了RegisterAsBrowser := True和FeatureBrowsers属性,前者是告诉系统当前进程是浏览器进程,后者能禁用 IE 的某些新特性,比如FEATURE_BROWSER_EMULATION。

// 在 FormCreate 里,导航之前设置 EmbeddedWB1.FeatureBrowsers := [fbEmulateIE7, fbDisableScriptDebugger]; EmbeddedWB1.RegisterAsBrowser := True;

逻辑说明:FeatureBrowsers是一个集合,把 IE 内核的渲染模式限制在指定优先级,fbEmulateIE7会强制页面按 IE7 标准渲染,适合老 OA 系统。参数说明:如果你要做的页面是现代化 HTML5,不要开fbEmulateIE7,改成fbEmulateDefault或fbEmulateIE11,否则 CSS 全乱。RegisterAsBrowser这个属性在进程内部只能设置一次,一般放在主窗体创建的最前面,切换太晚会失效。

4. 在 Delphi 12.3 上让 EmbeddedWB 播放 PPT 与本地 HTML:三个必调项

网上搜“Delphi webbrowser 播放 PPT”会发现一堆人问为什么嵌入了空白。传统做法是在网页里嵌 Office Web Viewer,或者直接把 PPT 转成 HTML。但如果你必须面对一个老旧的内部课件系统,EmbeddedWB 这几个设置项能大幅提高成功率。本章给出一套我在实际项目里用过的配置,适用场景是本地或内网 HTML 文件、包含 Flash 或 Office 控件的老页面。

4.1 设置文档模式与使用环境:让 IE 不至于退回怪癖模式

现在的 Windows 对浏览器模式有默认值,但老页面经常依赖 IE8/IE9 的渲染逻辑。我一般会在导航前一锤定音:

EmbeddedWB1.ProfileName := 'MyAppProfile'; EmbeddedWB1.UseProfile := True; EmbeddedWB1.Silent := False; EmbeddedWB1.AllowActiveX := True; // 如果页面里使用 window.open 播放 Flash,这里必须开着 EmbeddedWB1.Allow downloads := True; EmbeddedWB1.Show3DBorder := False;

逻辑说明:UseProfile让嵌入式 WebBrowser 使用独立注册表配置区,避免污染全局 IE 设置。AllowActiveX是 IE 安装 ActiveX 插件的前提,很多播放 PPT 的控件依赖它。参数说明:Show3DBorder只是外观,关掉它能让控件融入面板,不影响功能。

4.2 关闭脚本错误提示:DebugScripting

老页面里经常有一两处无关紧要的 JS 错误,弹出来会挡住后续操作。嵌入式浏览器最直接的解法是禁用脚本调试器:

EmbeddedWB1.FeatureBrowsers := EmbeddedWB1.FeatureBrowsers + [fbDisableScriptDebugger]; EmbeddedWB1.Silent := True; // 但此时 confirm/alert 也会被吞

注意:Silent := True是双刃剑,播放 PPT 时如果页面需要用户点击“允许”或者确认弹窗,这个设置会把操作全部静默掉。所以更精细的做法是保留Silent := False,只在OnScriptError事件里返回 True:

procedure TForm1.EmbeddedWB1ScriptError(Sender: TObject; const ErrorLine, ErrorChar, ErrorCode, ErrorMsg: WideString; const Url: WideString); begin // 记录错误但不中断页面 ShowMessage(Format('脚本错误:%s 行 %s', [Url, ErrorLine])); // 返回 True 表示已经处理,IE 不再显示对话框 end;

逻辑说明:OnScriptError触发频率很高,如果你的页面本身没问题,建议只在调试阶段打开这个事件。参数说明:ErrorCode是错误编号,ErrorMsg是描述文本;生产环境不要弹窗,写日志就行。

4.3 带参数加载本地 HTML:解决相对路径与 flash 白名单

播放本地 PPT 时最常见的是 Flash 或第三方控件被“未签名 ActiveX”拦截。这时要检查AllowActiveX := True,并确保 URL 是file://或内网 HTTP,而不是直接传一个不带协议的本地路径。我通常会写一个工具函数:

procedure TForm1.LoadLocalHTML(const APath: string); var URL: string; begin URL := StringReplace(APath, '\', '/', [rfReplaceAll]); URL := 'file:///' + URL; EmbeddedWB1.Navigate(URL); end;

逻辑说明:将 Windows 路径转成file:///形式,IE 内核才能正确解析相对路径里的 css/js 文件。参数说明:如果页面引用了http://的外部脚本,内网环境最好提前下载到本地或部署到同源服务器,否则会出现部分功能可用、部分不可用的“薛定谔”状态。

这套配置组合,我在一个装订生产线上跑了一年多,最大的体会是:不要迷信某一个属性,要按页面实际请求去调。你可以在OnBeforeNavigate2里记录 URL,在OnDocumentComplete后再看页面渲染结果,逐项排查。

5. EmbeddedWB 的避坑指南:我踩过的 5 个坑

玩 EmbeddedWB 越久越明白,它就像一个黑匣子,很多问题不是代码逻辑问题,而是 IE 内核和 Windows 版本之间的兼容阴影。下面这 5 个坑是按出现频率排序的,每一条都按“现象 → 原因 → 解决”写,你可以直接对着排查。

5.1 控件面板上出现两个 TEmbeddedWB

现象:安装后组件面板里找到两个同名控件,拖一个出来,代码里有时绑定到旧版本。 原因:机器上残留了旧版 EmbeddedWB 的 BPL/DCU,IDE 同时加载了新老包。这种坑最常见于从 D5 时代就一直在用老控件的团队。 解决:到 IDE 的 Component > Install Packages 列表里逐个查找 EmbeddedWB 相关包,全部卸载;在源码目录里搜索所有*.bpl和*.dcu并删除;重新编译运行时包和设计时包,再安装。

5.2 页面显示正常,但鼠标滚轮失效

现象:嵌入的网页可以滚动,但鼠标滚轮滚不动页面,只有拖动滚动条才行。 原因:现代 Windows 的鼠标滚轮消息默认发给焦点窗口,EmbeddedWB 的文档窗口没有正确接收WM_MOUSEWHEEL,部分老版本源码在 Delphi 12.3 下没触发消息映射。 解决:在窗体的OnMouseWheel里手动把滚轮消息转发给 EmbeddedWB:

procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); begin if Assigned(EmbeddedWB1.Document) then begin EmbeddedWB1.Browser.SendMouseWheelEvent(WheelDelta); Handled := True; end; end;

逻辑说明:SendMouseWheelEvent是 EmbeddedWB 暴露给外部调用的辅助接口。参数说明:WheelDelta为正表示向上滚,为负表示向下滚;如果窗体上还有输入框,建议先判断鼠标位置是否在控件范围内,避免影响其他组件。

5.3 卸载窗体时崩溃 Access Violation

现象:关闭带 EmbeddedWB 的主窗体时随机崩溃,返回错误地址在OleUninitialize或FreeObject附近。 原因:浏览器对象是异步工作的,窗体销毁时 ActiveX 还在处理事件回调,先释放了窗体的内部对象,回调再访问就崩了。 解决:释放顺序必须反来,先在FormDestroy里停止控制:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin EmbeddedWB1.Stop; EmbeddedWB1.ExecWB(OLECMDID_STOP, OLECMDEXECOPT_DODEFAULT); // 断开事件接收器 EmbeddedWB1.SetFocus; // 然后交给窗体释放 end;

逻辑说明:先停止导航和一切活动脚本,再用SetFocus让 ActiveX 退出编辑状态,最后再释放窗体会稳定很多。参数说明:OLECMDID_STOP是 IE 命令集合里的停止导航,OLECMDEXECOPT_DODEFAULT表示按默认方式执行。

5.4 HTTPS 页面里的下载按钮点了没反应

现象:从https://页面下载附件,点击后没有任何提示,也没有文件生成。 原因:IE 内核默认对混合内容比较敏感,尤其是网页在 HTTPS 下加载了非安全域的下载链接,浏览器直接拦截。EmbeddedWB 的默认配置并没有把这种拦截完全关闭。 解决:在导航之前检查 URL,把 HTTPS 和 HTTP 混用情况单独处理:

if (pos('https://', URL) > 0) and (pos('http://', URL) > 0) then ShowMessage('页面同时引用 HTTP 和 HTTPS 资源,请确认安全设置') else EmbeddedWB1.Navigate(URL);

逻辑说明:这种拦截不是 EmbeddedWB 故意做死,而是 IE 自身的安全策略。参数说明:如果你的内网系统全部是 HTTPS,可以额外设置EmbeddedWB1.UseFeatureBrowserFolder、EmbeddedWB1.FeatureBrowsers来适配,但最省事的还是引导页面把所有资源切到 HTTPS。

5.5 源文件有 SRC 但编译出来的工具不干活

现象:代码里EmbeddedWB1.Src明明赋了值,但页面不显示。 原因:Src属性在早期版本里只是个描述符,必须在Navigate之后才能用,或者赋值时机不对。很多老代码把Src当成 URL 直接用,新版本里行为变了。 解决:使用SetUrl或Navigate明确加载:

EmbeddedWB1.Src := 'about:blank'; EmbeddedWB1.Navigate2('https://example.com/');

逻辑说明:先让浏览器进入一个干净的文档对象状态,再导航新地址,可以避开文档未就绪时赋值的问题。参数说明:Navigate2和Navigate的区别在于是否重新创建文档对象;如果你要加载的是动态生成的内存 HTML,建议用Write(html)而不是Src。

6. 从源码包到自用浏览器控件:验证安装与三个进阶技巧

装好控件、躲过坑之后,最后一步是花一个小时做验证,否则你不敢把它交到业务手里。我的验证方法是建一个空白工程,拖一个TEmbeddedWB和一个TButton,按钮事件里写EmbeddedWB1.Navigate('https://www.example.com/'),看页面是否正常加载,再右键页面查看属性,确认注册表和渲染模式生效。验证通过后,可以从三个方向往下压榨价值。

第一个进阶技巧是使用 Interposer 模式。把你自己的类挂在 VCL 的默认控件名上:

type TEmbeddedWB = class(EmbeddedWB.TEmbeddedWB) public procedure LoadFromStream(AStream: TMemoryStream); end;

这样老工程里已有的TEmbeddedWB自动升级成你的扩展版本,不需要改一个界面。第二个技巧是让一个窗口挂多个 EmbeddedWB,配合TabSheet实现多标签页,同时共享同一个 Cookie 目录。第三个技巧是如果你要嵌入的内容已经改成 HTML5,不要再让 EmbeddedWB 硬扛,它毕竟只是 IE 内核的安全壳,此时用 WebView2 做渐进替换更合适。我见过有人非要让 EmbeddedWB 跑现代前端项目,结果各种玄学崩溃,最后还得回头迁内核。

这里还要提醒一句:如果你在用 Delphi 12.3 的 FireMonkey 方式做跨平台界面,EmbeddedWB 是 VCL 控件,不能直接拖到 FMX 窗体里。常见的做法是 VCL 窗体里放一个嵌入的 TPanel,再Winapi.Windows做窗口句柄托管。用LoadLibrary加载 WebBrowser 对象的接口,但这套方案维护成本高,能不用就不用。

我自己的习惯是把 EmbeddedWB 的所有操作都包在一个独立业务类里,控件只负责显示,业务模块负责导航、下载、日志。这样即使那天要换 WebView2,业务代码也不用重写。希望这些踩坑记录能让你在 Delphi 12.3 里用这个 SRC 包时少走几趟夜路,也希望你手头的老项目能借着 EmbeddedWB 再稳稳跑上几年,然后从容地迁到新内核。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询