简介:本资源是面向Delphi中高级开发者的技术组件源码包,聚焦于EmbeddedWB嵌入式Web浏览器控件在Delphi 12.3环境下的深度适配与定制开发需求。它完整提供D5至XE12全版本兼容的源代码实现,涵盖核心功能封装、IE内核交互逻辑、网页事件响应机制及RichEdit混合渲染等关键模块,助力开发者突破官方控件限制,实现网页内容精准控制、下载拦截、DOM操作与跨页面通信等高阶功能。压缩包共226个文件,含65个Pascal源码(.pas)、126个编译单元(.dcu)、22个包工程(.dpk)及配套资源与构建脚本,总大小仅2.44MB,结构清晰、模块解耦,便于学习调试与二次开发。已有81人下载学习,适合需深入理解WebBrowser底层机制、定制企业级桌面应用内嵌浏览器或迁移老旧Delphi项目的开发者。
1. 项目概述:一个Delphi老兵的“浏览器”控件探索
如果你是一个在Windows桌面应用开发领域摸爬滚打多年的Delphi开发者,看到“EmbeddedWB-D5-XE12-SRC.7z”这个文件名,大概率会会心一笑。这不仅仅是一个压缩包,它背后承载的是一段横跨近二十年Delphi版本变迁的技术史,以及一个在特定历史时期解决关键需求的经典方案——在Delphi应用程序中嵌入一个功能完整的网页浏览器。
EmbeddedWB,全称Embedded Web Browser,顾名思义,它的核心使命就是将微软的Internet Explorer(IE)浏览器内核,无缝地嵌入到你的Delphi VCL窗体中。从文件名中的“D5-XE12”就能看出,这个控件包试图覆盖从经典的Delphi 5到相对现代的Delphi XE12(即RAD Studio 12)的漫长版本区间。对于许多维护着历史遗留项目,或者需要与特定ActiveX/COM组件交互的开发者来说,它至今仍是一个绕不开的话题。这个压缩包里通常包含了完整的源代码(SRC),意味着你可以根据自己使用的Delphi版本进行编译和调试,赋予了项目极大的灵活性和掌控力。
那么,谁需要关注它呢?首先是那些需要在自己的Delphi软件中展示网页内容、实现HTML报表预览、甚至构建混合式桌面应用(内嵌Web界面)的开发者。其次,是那些项目严重依赖IE特定功能(如古老的ActiveX控件、VBScript、或特定版本的Trident引擎渲染)的团队。最后,也包括像我这样,有时需要快速搭建一个用于网页抓取、自动化测试或模拟用户操作的内部工具的程序员。虽然现代开发更推崇基于Chromium的嵌入式方案(如CEF4Delphi、TEdgeBrowser),但在某些“历史包袱”沉重或环境受限的场景下,EmbeddedWB依然是那个最直接、最“原生”的选择。
2. 核心需求与场景深度解析
为什么在WebView2(基于Chromium Edge)和CEF已经如此成熟的今天,我们还要讨论一个基于IE内核的“老古董”?这恰恰是理解EmbeddedWB价值的关键。它的存在不是为了追赶潮流,而是为了解决那些由历史、兼容性和特定技术栈所决定的“刚性”需求。
2.1 不可替代的遗留系统集成场景
在许多工业控制、企业ERP、金融交易等传统领域,存在大量基于IE浏览器和ActiveX技术构建的业务系统。这些ActiveX控件可能负责硬件通信、安全加密、数字签名或渲染特定的专业图表。它们往往只兼容IE的Trident内核,无法在Chrome或新Edge中运行。当你的Delphi桌面应用需要与这些系统进行深度集成,例如,在应用内嵌一个页面来完成在线签约、报表查询或数据填报时,EmbeddedWB几乎是唯一能保证所有功能正常工作的桥梁。我曾参与过一个医保结算项目,核心的银联支付控件就是一个只支持IE的ActiveX,使用EmbeddedWB嵌入支付页面是当时最稳定、成本最低的解决方案。
2.2 对轻量级与免部署的极致追求
相较于需要额外分发几十甚至上百兆运行时库的CEF或WebView2,EmbeddedWB的最大优势在于“零依赖”——只要目标Windows系统装有IE(在Win10/11中,它以“Internet Explorer模式”或相关组件形式存在),你的程序就能直接运行。这对于需要通过网络分发、安装包体积敏感、或运行在封闭内网环境(无法随意安装新组件)的应用程序来说,是一个巨大的优势。你只需要在Installer里确保IE功能被启用,而无需打包庞大的Chromium框架。
2.3 完全的掌控与深度定制需求
EmbeddedWB提供了对底层IE COM接口极其细致的封装和访问能力。你可以拦截并修改几乎所有的HTTP请求和响应、操纵DOM元素、执行JavaScript并获取返回值、模拟用户点击和表单提交、甚至处理各种浏览器事件(如新窗口打开、下载提示等)。这种深度控制能力,对于开发网页自动化工具、爬虫客户端、或需要与网页内容进行复杂交互的辅助软件,是其他更高层封装的浏览器控件难以比拟的。源代码的开放更是允许你在遇到诡异问题时,能够深入内核进行调试和打补丁。
2.4 版本兼容性带来的长期维护挑战
从文件名“D5-XE12”也能看出,维护这样一个跨越多代IDE和编译器版本的控件,本身就是一项艰巨的任务。Delphi每个大版本在RTL、VCL和编译器特性上都有变化,这使得同一份源代码需要在不同版本下进行条件编译和适配。网络热词中提到的“delphi 控件版本问题 导致 每次进入ide都丢失控件”,就是这类跨版本控件包常见的“顽疾”之一,其根源往往在于设计期包(.dpk)的安装路径、注册信息或与IDE版本的兼容性没有处理好。使用这类源码包,意味着你需要具备一定的排错和适配能力。
3. 从源码到可用:完整部署与编译实战
拿到“EmbeddedWB-D5-XE12-SRC.7z”这样的源码包,第一步不是急着安装,而是有条不紊地准备环境、理清结构、解决依赖,最后才是编译和安装。下面是我根据多年经验总结的标准操作流程。
3.1 解压与目录结构分析
首先,将压缩包解压到一个路径不含中文和空格的目录,例如D:\Dev\Components\EmbeddedWB。这是避免后续一系列诡异编译错误的首要原则。解压后,你通常会看到类似如下的目录结构:
\Source:核心的Pascal单元文件(.pas)和资源文件。\Demos:各种功能演示程序,这是最好的学习资料。\Packages:针对不同Delphi版本的安装包项目文件(.dpk, .dproj)。\Docs或\Help:可能存在的帮助文档(通常比较简略)。\ThirdParty:可能依赖的第三方单元,如一些辅助函数库。
你的首要任务是找到与你当前Delphi版本最匹配的Packages目录。例如,如果你用的是RAD Studio 10.4 Sydney,就去找类似Packages\D104这样的文件夹。
3.2 解决编译依赖与路径设置
进入对应版本的Packages目录,打开主要的安装包文件(例如EmbeddedWB_RunTime.dpk和EmbeddedWB_DesignTime.dpk)。在编译之前,必须确保Delphi的库路径(Library Path)包含了源码所在的Source目录。
- 在Delphi IDE中,点击
Tools -> Options -> Language -> Delphi Options -> Library。 - 在
Library path中,添加你解压的Source目录的完整路径,例如D:\Dev\Components\EmbeddedWB\Source。 - 同样地,如果存在
ThirdParty目录且里面有必要的.pas文件,也需要将其路径加入。
注意:很多编译错误“Fatal: File not found ‘xxx.pas’”都是因为库路径设置不正确导致的。务必确保路径准确无误。
3.3 分步编译与安装
控件的安装通常分为运行时包和设计时包两步,务必按顺序操作。
第一步:编译运行时包(Runtime Package)打开EmbeddedWB_RunTime.dpk,右键点击项目,选择Compile。如果编译成功,你会在输出目录(通常是项目同级的Win32\Debug或Win64\Release)看到生成的.bpl文件。这一步只是将控件代码编译成二进制包,尚未在IDE中注册。
第二步:安装设计时包(DesignTime Package)打开EmbeddedWB_DesignTime.dpk。在安装之前,强烈建议先检查其依赖。右键项目 ->Project -> Options -> Packages,查看它是否正确地引用了刚才编译的运行时包。确认无误后,右键项目选择Install。如果安装成功,IDE会提示“Package xxxx has been installed”,并且在组件面板(通常是在“Internet”或“Win32”页签下)会出现TEmbeddedWB等组件图标。
3.4 处理常见的安装故障
安装过程中,你可能会遇到以下典型问题,这里提供排查思路:
“Class TEmbeddedWB already exists” 或类似重复类错误: 这通常是因为系统中残留了旧版本控件的DCU文件或BPL文件。解决方法是彻底清理。关闭所有Delphi IDE,搜索硬盘上的
EmbeddedWB*.dcu,EmbeddedWB*.bpl,EmbeddedWB*.dcp文件,特别是Delphi的公共库路径(如C:\Users\Public\Documents\Embarcadero\Studio\XX.0\Bpl和C:\Program Files (x86)\Embarcadero\Studio\XX.0\lib下的对应平台目录),将找到的旧文件全部删除或移走,然后重新执行编译安装步骤。编译时提示缺少第三方单元(如“OleCtrls, OleServer”等): 这些通常是Delphi自带的VCL单元,提示找不到可能是因为项目搜索路径不完整。确保你的项目或全局库路径包含了Delphi的VCL源码目录(例如
C:\Program Files (x86)\Embarcadero\Studio\XX.0\source\...)。有时,EmbeddedWB的旧版本项目文件可能需要手动添加这些路径。安装成功后,控件在组件面板上显示为灰色或不可用: 这通常是设计时包没有正确链接到运行时包。你需要手动将编译好的运行时包(.bpl)添加到IDE的运行时包列表中。在IDE中打开
Project -> Options -> Packages,在右侧的“Runtime Packages”列表中,点击“Add…”,找到并添加你编译好的EmbeddedWB_RunTime.bpl文件,然后重启IDE。
4. TEmbeddedWB核心功能与高级应用详解
成功安装后,你就可以在窗体上拖放一个TEmbeddedWB组件了。它继承自TWebBrowser,但功能强大得多。下面我们深入其核心功能与实战代码。
4.1 基础导航与页面交互
最基本的操作是加载一个URL或本地HTML文件。
// 加载网页 EmbeddedWB1.Navigate('https://www.example.com'); // 加载本地文件,注意文件路径格式 EmbeddedWB1.Navigate('file:///D:/report.html'); // 在加载完成后执行操作,通常需要配合OnDocumentComplete事件 procedure TForm1.EmbeddedWB1DocumentComplete(ASender: TObject; const pDisp: IDispatch; const URL: OleVariant); begin if EmbeddedWB1.ReadyState = READYSTATE_COMPLETE then begin // 页面加载完成,可以安全地操作DOM或执行脚本了 Caption := '页面加载完成: ' + EmbeddedWB1.LocationURL; end; end;实操心得:
OnDocumentComplete事件可能会被触发多次(例如,页面中有iframe)。一个稳健的做法是检查pDisp参数是否等于EmbeddedWB1.DefaultInterface(即顶级文档对象),或者使用EmbeddedWB1.ReadyState属性来确保是整个页面完全加载完毕。
4.2 强大的脚本调用与数据交换
这是EmbeddedWB的精华所在。你可以轻松地在Delphi和页面JavaScript之间传递数据。
// 1. 执行JavaScript代码并获取返回值 var jsResult: OleVariant; begin jsResult := EmbeddedWB1.ExecuteScript('document.title'); ShowMessage('页面标题是:' + VarToStr(jsResult)); // 调用页面中的JavaScript函数 EmbeddedWB1.ExecuteScript('window.myJsFunction("参数来自Delphi")'); end; // 2. 将Delphi对象暴露给JavaScript(实现回调) // 首先,定义一个实现了IDispatch的接口的类 type TDelphiCallback = class(TInterfacedObject, IDispatch) public function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; end; // 在Invoke方法中处理来自JS的调用 // 然后,将其设置为WebBrowser的外部对象 procedure TForm1.SetExternalObject; var Doc: IHTMLDocument2; begin Doc := EmbeddedWB1.Document as IHTMLDocument2; (Doc.parentWindow as IHTMLWindow2).execScript('window.external = new ActiveXObject("你的ProgID或CLSID");', 'JavaScript'); // 更现代和推荐的方式是使用EmbeddedWB提供的接口或属性来注册外部对象 end;更实用的例子:自动填写表单并提交假设页面有一个登录表单,id分别为username和password。
procedure TForm1.AutoLogin(const AUrl, AUser, APass: string); begin EmbeddedWB1.Navigate(AUrl); // 等待页面加载完成(在实际应用中应使用更健壮的状态机或等待函数) // 这里为演示,假设在OnDocumentComplete事件中 if EmbeddedWB1.ReadyState = READYSTATE_COMPLETE then begin // 使用JavaScript填充表单 EmbeddedWB1.ExecuteScript(Format('document.getElementById("username").value = "%s";', [AUser])); EmbeddedWB1.ExecuteScript(Format('document.getElementById("password").value = "%s";', [APass])); // 提交表单 EmbeddedWB1.ExecuteScript('document.forms[0].submit();'); end; end;4.3 请求拦截与修改(实现自定义协议或数据过滤)
通过OnBeforeNavigate2,OnNavigateComplete2等事件,以及IInternetProtocol等接口的深度支持,EmbeddedWB可以拦截HTTP/HTTPS请求。这是一个高级功能,常用于实现本地资源映射、内容过滤或自定义缓存策略。
procedure TForm1.EmbeddedWB1BeforeNavigate2(ASender: TObject; const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool); var sUrl: string; begin sUrl := URL; // 拦截特定URL,例如将所有对“myapp://”协议的请求重定向到本地资源 if Pos('myapp://', sUrl) > 0 then begin Cancel := True; // 取消原始导航 // 解析myapp协议,并加载本地对应的HTML或数据 HandleCustomProtocol(sUrl); end; // 过滤广告URL if Pos('doubleclick.net', sUrl) > 0 then begin Cancel := True; StatusBar1.Panels[0].Text := '已拦截广告请求: ' + sUrl; end; end;实现完整的自定义协议处理器需要注册一个自定义的IInternetProtocol工厂,这涉及更多的COM编程知识,是EmbeddedWB发挥其底层控制力的体现。
4.4 打印与静默打印控制
EmbeddedWB提供了比标准TWebBrowser更精细的打印控制。
// 显示打印预览 EmbeddedWB1.PrintPreview; // 静默打印(不显示对话框,直接输出到默认打印机) // 注意:这需要适当的权限,并且可能被浏览器安全设置阻止 procedure TForm1.PrintSilently; begin EmbeddedWB1.PrintOptions.HidePrintDialog := True; EmbeddedWB1.PrintOptions.HideProgressDialog := True; EmbeddedWB1.PrintOptions.Active := True; EmbeddedWB1.Print; end; // 设置打印页眉页脚 EmbeddedWB1.PrintOptions.Header := '第&p页/共&P页'; // &p 当前页, &P 总页数 EmbeddedWB1.PrintOptions.Footer := '打印日期: &D';5. 疑难杂症排查与版本兼容性实战
使用EmbeddedWB,尤其是跨多个Delphi版本时,会遇到各种“坑”。下面是我总结的常见问题与解决方案速查表。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 设计期控件丢失 每次打开IDE或项目,之前放置的TEmbeddedWB控件变红叉或消失。 | 1. 设计时包(.bpl)未正确注册或路径失效。 2. 多个Delphi版本冲突,BPL路径混乱。 3. 控件源码路径被移动或删除。 | 1. 关闭所有IDE,删除$(BDS)\Bin目录下的*.drc,*.local文件。2. 检查 $(BDS)\Bin目录下的bds.exe.config或注册表HKCU\Software\Embarcadero\BDS\XX.0\Known Packages,确保设计时包路径正确且唯一。3. 重新执行一遍安装流程,确保编译输出的.bpl文件在IDE的搜索路径中。 |
| 运行时错误“EOleSysError”或“接口不支持” | 1. 目标系统IE核心组件损坏或版本过低。 2. 没有正确初始化COM库(在控制台程序或DLL中常见)。 3. 跨线程调用WebBrowser控件。 | 1. 运行iexplore.exe看IE是否能正常启动。可尝试系统修复命令:sfc /scannow。2. 在主程序初始化部分(如.dpr文件)确保调用了 Application.Initialize;之前或之后调用CoInitialize(nil);(或OleInitialize)。对于GUI程序,通常VCL已处理。3.WebBrowser及其相关接口是Apartment线程模型,绝对禁止跨线程直接访问其方法和属性。必须使用 TThread.Synchronize或TThread.Queue将调用封送到主线程。 |
| JavaScript调用失败或返回空值 | 1. 页面尚未加载完成就调用。 2. 安全限制(跨域、标记为不安全的内容)。 3. JavaScript本身执行错误。 | 1.务必在OnDocumentComplete事件中,并确认是顶级文档加载完毕后再执行脚本。可使用if (pDisp = EmbeddedWB1.DefaultInterface) then判断。2. 尝试调整 EmbeddedWB1.Security.SetSecuritySite相关属性,或在受限环境下,考虑降级IE的 security zone 设置(不推荐用于生产环境)。3. 在 ExecuteScript外包裹 try..except,并使用EmbeddedWB1.OnScriptError事件捕获错误信息。 |
| 高DPI下显示模糊或布局错乱 | IE内核对高DPI缩放支持不佳,EmbeddedWB作为宿主控件需要手动处理DPI感知。 | 1. 在项目主文件中添加{$HIGHDPIAWARE ON}指令。2. 在窗体创建时,手动缩放EmbeddedWB控件的大小和位置: EmbeddedWB1.ScaleForPPI(Screen.PixelsPerInch);(需根据Delphi版本调整方法)。3. 更根本的解决方案是:在应用程序清单文件(.manifest)中声明DPI感知,并让系统进行缩放,但这可能导致内容本身被拉伸模糊。 |
| 内存泄漏或进程不退出 | WebBrowser控件持有的COM接口未正确释放,或存在循环引用。 | 1. 确保在窗体关闭或控件销毁时,调用EmbeddedWB1.Navigate('about:blank');并等待其完成,以清空文档。2. 在 FormClose或FormDestroy事件中,手动释放接口变量:Doc := nil;(如果之前赋值了Doc := EmbeddedWB1.Document)。3. 使用 EmbeddedWB1.Free;前,可以尝试EmbeddedWB1.Stop;和EmbeddedWB1.Quit;(如果控件提供了此方法)。 |
关于版本兼容性的特别提醒:对于“D5-XE12”这样的大跨度源码包,直接在现代Delphi(如10.4+)上编译早期(如D5)的源代码,几乎一定会遇到编译错误。常见问题包括:
- 字符串类型:早期使用
AnsiString,现代默认UnicodeString。需要检查所有PChar、字符串函数调用。 - 组件注册函数:旧版使用
Register过程,新版可能需要条件编译以支持package单元。 - 过时的API:一些Windows API或COM接口可能已弃用或改变。
最务实的做法是:寻找专门针对你当前Delphi版本分支的EmbeddedWB源码,或者以源码包中与你版本最接近的目录(如针对XE8的包)为基础,手动将其移植到新版本。移植时,重点关注编译器提示的不兼容处,并参考新版本VCL的写法进行修改。
6. 现代替代方案评估与迁移考量
尽管EmbeddedWB在特定场景下不可替代,但对于新项目或允许技术栈升级的老项目,评估现代方案是必要的。
1. TEdgeBrowser (Microsoft WebView2)这是Embarcadero官方推荐的现代替代品,从RAD Studio 11 Alexandria开始内置。它基于Chromium的Edge WebView2运行时,性能、安全性、对现代Web标准(HTML5, CSS3, ES2022+)的支持远超IE内核。
- 优点:官方支持,更新及时,与Windows系统Edge浏览器共享运行时,安装包体积小,性能好。
- 缺点:需要目标系统安装WebView2运行时(Win11已内置,Win10可通过安装包或系统更新获取)。对IE独有的ActiveX等完全不兼容。
- 迁移评估:如果你的应用只需要显示现代网页,无遗留ActiveX依赖,应优先选择TEdgeBrowser。迁移工作量主要是API的替换,两者在基础导航、脚本调用等概念上相似,但具体接口不同。
2. CEF4Delphi (Chromium Embedded Framework)这是一个将完整Chromium引擎嵌入Delphi应用的第三方开源项目,功能极其强大。
- 优点:完全独立,不依赖系统浏览器,版本可控,功能最全面(包括DevTools、自定义协议、低级网络拦截等)。
- 缺点:应用程序体积会显著增大(需要分发Chromium库文件),进程模型相对复杂(多进程架构),内存占用较高。
- 迁移评估:适用于需要最高程度控制、自定义、且不介意应用体积的复杂桌面应用(如内嵌一个完整的Chrome)。从EmbeddedWB迁移过来相当于重写浏览器交互层,但能获得一个现代、强大的浏览器内核。
决策建议:
- 坚守EmbeddedWB:你的应用核心功能依赖仅支持IE的ActiveX控件;应用部署环境封闭且无法安装新运行时;项目处于维护末期,无大改计划。
- 迁移到TEdgeBrowser:你使用的是较新版本的Delphi(11+);应用主要展示现代网页内容;你可以控制或要求用户环境安装WebView2运行时。
- 迁移到CEF4Delphi:你需要一个功能全、版本固定的独立浏览器内核;需要进行深度的网络拦截、自定义渲染等高级操作;应用体积不是首要考虑因素。
在我个人的经验里,处理一个需要与银行古老网银插件交互的项目时,我们不得不坚守EmbeddedWB。而在另一个需要内嵌展示数据可视化报表(基于ECharts)的新项目中,果断选择了TEdgeBrowser,开发体验和最终效果都提升了一个世代。技术选型没有绝对的好坏,只有是否适合当下的约束条件和未来的发展路径。理解EmbeddedWB的“为什么”和“怎么用”,能让你在面对这些选择时,做出更清醒、更务实的判断。
本文还有配套的精品资源,点击获取