简介这是一份基于PowerBuilder 9开发的Web浏览器组件集成示例适用于需要在PB客户端中内嵌网页、实现导航或混合型应用开发的程序员。资源共88个文件压缩包仅358KB主要包含.pbl库文件、.pbt工程文件、html页面及配套的图片、脚本、样式表等其中.pbl中封装了窗口与控件代码html与js用于演示加载本地网页和交互效果。已有1368人学习。读者可从中了解在XP环境下通过WebBrowser/ActiveX控件实现Web导航的方法掌握PB库文件与项目团队文件的管理技巧并参考其目录结构快速迁移到自己的项目中适合维护旧系统或学习PB经典开发模式的工程师参考。 最近在维护一个老PB项目时客户提了个需求在系统首页嵌入一个网页用来展示趋势图和产品公告。需求方觉得“这不就是个控件的事嘛”实际上在PowerBuilder里如果你没碰过Web浏览器组件确实容易被卡住。我先后在项目里试过WebBrowser ActiveX、WebView2封装、CEF封装最后真正落地的还是老牌的WebBrowser控件配合注册表调整。这篇文章就把选型、嵌入、调接口、避坑的完整过程拆开讲适合正在维护PB系统、或者想在PB窗口里集成Web页面的开发者参考。1. 什么场景下PB项目需要往窗口里塞一个浏览器1.1 数据窗口很强但不是万能的PB最引以为傲的就是DataWindow绑定数据库、做汇总计算、分组合并、打印控制一套下来效率很高。但做久了PB维护的人都会碰到几类数据窗口搞不定的需求在线富文本公告客户要求通知带格式展示数据窗口只能用RichText兼容性和效果都一般。ECharts图表大屏折线图、地图、仪表盘这些是前端生态的强项数据窗口做出来效果差很远。业务流程内的第三方页面比如嵌入式报表服务、单点登录后的内部系统页面需要嵌在窗口内部而不是弹出外部浏览器。打印模板需要更自由的样式控制数据窗口有printpreview方法但做复杂套打不如HTML加CSS灵活。这些场景归纳起来就一句话业务系统正在向Web体验靠拢但骨干程序还是PB不想推翻重来只能在PB窗口里嵌入浏览器组件。1.2 直接调外部浏览器的问题也有同行会问既然要看网页干嘛不直接Run打开默认浏览器我也这么干过后来被客户吐槽了几次页面跳来跳去用户分不清哪些业务还在PB里处理外部浏览器和PB窗体之间没有联动选一条数据再打开网页参数传递只能拼URL交互很生硬内部地址留在浏览器历史记录里登录态也不好控制安全上不划算。所以最终还是要做窗口内嵌浏览器让网页看起来就是窗口的一部分。1.3 三种常见嵌入方式速览方式内核额外依赖嵌入难度适用场景WebBrowser ActiveXIE无低老项目维护、内部系统、快速交付WebView2Edge ChromiumWebView2 Runtime中高需封装成PB可调组件新项目、现代前端页面CEFChromiumCEF运行库约几十MB高音视频、地图等复杂页面这个表基本决定了后面所有的技术路线选择。2. 组件选型别一上来就追新先看清项目底子2.1 WebBrowser ActiveX为什么是老项目的首选在PB的窗口画板里插入OLE控件时列表里能看到“Microsoft Web Browser”它对应的ProgID是Shell.Explorer.2内核实为IE但不需要额外安装任何运行库Windows系统自带。对维护老PB项目的朋友来说这是能“今天写、明天上线”的路径。它的劣势也摆在明面上默认文档模式低CSS3和ES6支持不彻底现代前端框架跑起来吃力。可企业内部系统往往本来就按照兼容IE的标准做了降级WebBrowser反而不容易出大问题。很多客户机器还是Win7、Win10混用WebBrowser的兼容性反而成了优点。2.2 WebView2很现代但和PB之间隔了一层WebView2基于Edge Chromium内核渲染能力和Chrome基本对齐。要说推荐新项目我肯定会往WebView2方向走。但PB不能像C# WinForm一样直接拖一个WebView2控件它需要先用C或.NET封装成COM/ActiveX再通过PB的OLE方式调用。这一层封装要求团队有.NET或C能力还要部署WebView2 Runtime对多数纯PB项目来说有点重。2.3 CEF的情况CEF就是把Chromium核心打散成一批dll封装到程序里。它的好处是不依赖系统级WebView2 Runtime版本可以自己控制但dll多、封装工作量大、升级时需要注意版本一致。除非项目里有大量HTML5音视频播放、地图拖拽、WebRTC之类的需求否则PB项目里选CEF收益不高。2.4 我的选择逻辑项目要维护客户机器环境不可控就选WebBrowser。项目是全新改造团队能接受封装优先评估WebView2。需求里有视频监控、会议、大屏这种重度Web能力再评估CEF。下面进入正题完整走一遍WebBrowser的嵌入流程。3. 把网页真正嵌进PB窗口WebBrowser控件实操3.1 第一步往窗口里放OLE控件最省事的方法是在窗口画板里点OLE控件然后在“Insert Control”页签中找到“Microsoft Web Browser”。如果列表里没有这一项多半是系统组件受损先运行一下regsvr32 ieframe.dll这个命令会重新注册IE内核相关DLL对系统其它功能没有影响但要以管理员身份运行。插到窗口上之后把OLE控件的Name改成ole_web运行窗口你会看到一片空白区域那就是浏览器控件的地盘可以像普通控件一样摆位置、拉大小。3.2 第二步Navigate导航页面导航是WebBrowser最基本的动作ole_web.Object.Navigate(https://example.com/report)Navigate支持几个参数最常用的第一个参数就是URL。如果需要在页面间传递业务参数直接拼在URL后面string ls_url ls_url https://example.com/report?dept01date20240601token ls_token ole_web.Object.Navigate(ls_url)注意URL长度和中文编码中文参数最好先转码否则有些版本的IE内核会把参数原样传给服务端容易乱码。3.3 第三步读取页面状态和DOM页面加载完成后可以读取文档对象。比如取标题string ls_title ls_title ole_web.Object.Document.title取页面全部文本string ls_text ls_text ole_web.Object.Document.body.innerText给页面里的元素赋值ole_web.Object.Document.getElementById(username).value admin或者在PB这头执行页面里的JavaScriptole_web.Object.Document.parentWindow.execScript(showChart(emp);, javascript)这套接口和以前VB6里操作WebBrowser一模一样本质上就是COM的IDispatch接口暴露出来的能力PB通过OLEObject调用这些方法。3.4 第四步事件如何判断页面加载完成OLE控件有几个常用事件比如NavigateComplete2、DocumentComplete、TitleChange、DownloadComplete。最容易用错的是DocumentComplete——页面里如果有iframe主页面加载完成和iframe加载完成都会触发DocumentComplete如果一触发就去读DOM可能拿到的是半成品。我的经验是在DocumentComplete事件里判断URL// DocumentComplete事件 // 参数pDisp为浏览器对象url为当前完成文档的地址 if pos(lower(url), report) 0 then // 主导航页面已完成可以开始操作DOM ole_web.Object.Document.getElementById(status).innerText 加载完成 end if如果版本里取不到url参数常规做法是自己在Navigate时记录目标地址再在事件里对比页面的Title或LocationName。这个细节每次都会被问所以提前写出来。3.5 第五步PB数据交给页面的几种传球姿势Web页面光有外壳不够业务数据还是要从PB这边过去。我实际用过的有三种方式。方式ADataWindow导出HTML表格dw_1.SaveAs(c:\webcache\report.html, HTMLTable!, TRUE) ole_web.Object.Navigate(file:///c:/webcache/report.html)这个方式实现最快数据窗口什么样页面基本什么样。但有个坑SaveAs HTMLTable导出的HTML是传统Table布局页面很难再做美化而且中文编码有时会出问题。我会在导出后读取文件内容把charset手动改成UTF-8后再写回。方式B导出JSON页面自己去渲染如果你的PB版本支持JSON导出PB 2017及以上的版本基本都支持可以这样dw_1.SaveAs(c:\webcache\report.json, JSON!, TRUE)然后把JSON文件路径通过参数告诉页面页面用fetch或XMLHttpRequest读取后再渲染成ECharts、Element UI表格都行。这个方式对前端友好推荐新需求使用。注意PB导出JSON时列名最好提前在DataWindow的定义里命名规范一些不然页面上拿到的字段名可能是一堆dwcolumn_1这种可读性很差。方式C页面通过本地HTTP接口实时取数这个方式适合做复杂交互但需要PB侧实现一个小型HTTP服务我放到第5章细说。4. 生产环境实战注册表、位数、打印与弹窗的坑4.1 页面错乱先查FEATURE_BROWSER_EMULATIONWebBrowser控件在默认情况下可能以IE7模式渲染很多CSS3、Flex布局、圆角属性会失效页面看起来又老又歪。解决办法是注册表里的功能开关Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION] myapp.exedword:00002af8其中myapp.exe必须换成你PB编译出来的exe文件名比如hrms.exe、oa_client.exe。取值说明值文档模式110010x2AF9IE11 Edge模式推荐110000x2AF8IE11100010x2711IE1099990x270FIE9注意第一次改动后要完全退出客户端重新登录。另外如果你的PB应用是32位的而系统是64位注册表可能存在重定向问题设置不生效时可以检查HKCU\Software\WOW6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION下面是否也有同名设置必要时两边都写。注册表手工维护容易漏我的做法是打包安装程序时带一个.reg文件在安装结束静默导入。这个方案在多个客户环境验证过光这一步就能减少九成“为什么我开发环境正常客户机器白屏”的问题。4.2 大问题控件未注册或找不到组件有同事反馈客户机器上打开窗口提示“未注册的类”或者插入OLE控件时找不到Microsoft Web Browser。常见原因精简版系统把IE组件裁剪了或者某些安全软件把注册表项清掉了64位系统和32位PB混搭控件注册视角不对。处理顺序是这样先确认C:\Windows\SysWOW64和C:\Windows\System32下面都有ieframe.dll再用管理员命令行分别执行regsvr32 /i ieframe.dll regsvr32 /i C:\Windows\SysWOW64\ieframe.dll然后重启客户端。大多数情况下能解决。如果还不行检查“启用或关闭Windows功能”里的Internet Explorer 11是否被停用把它勾上再试。这里要特别提醒不要在客户机器上乱删注册表宁可多试几种无损手段也不要一时图快把系统搞瘫。4.3 弹窗、上传文件、右键菜单“失灵”WebBrowser ActiveX在PB里是一个比较“裸”的浏览器很多浏览器界面功能它不会自动弹出来。window.open经常没反应右键菜单时有时无input typefile上传文件时选择框一闪而过或直接消失。这些跟IE保护模式、ActiveX的权限设置都有关系。我比较务实的解决办法是页面内部禁止window.open统一用div模拟弹层避免依赖浏览器新窗口文件上传需求尽量放到一个独立页面或者把上传控件换成PB自己写的文件选择窗口右键菜单如果被禁用更推荐在页面里自己实现右键菜单体验反而统一。这些限制讲白了就是IE内核的天花板靠PB侧配置能缓和但不能根治。所以遇到对交互体验要求高的模块我会把需求拆开简单展示交给WebBrowser复杂交互再做独立Web功能模块不硬塞。4.4 DataWindow打印预览和Web页面打印怎么配合热搜里有“pb的数据窗口有printpreview()函数吗”这里顺手回答一下。PB的数据窗口确实有打印预览相关方法dw_1.PrintPreview(TRUE) // 进入打印预览 dw_1.PrintPreview(FALSE) // 退出打印预览也可以用属性方式dw_1.Object.DataWindow.Print.Preview TRUE两者效果差不多用方法更直观。如果你的页面内容是用WebBrowser显示HTML报表再走数据窗口的打印预览就不合适了。我一般分两种纯数据库报表还是用数据窗口自己打印因为分页、列宽、汇总都成熟需要精美套打的单据直接在HTML页面里排版页面内部用window.print或调用WebBrowser的ExecWBole_web.Object.ExecWB(6, 1) // 弹出打印对话框 ole_web.Object.ExecWB(6, 2) // 直接打印注意在IE11 Edge模式或某些系统上ExecWB的打印行为可能被拦截建议优先在页面里用window.print触发前端可控性更好。开发时把打印预览一起调省得客户事后说样式不对。5. 如果想更进一步本地HTTP服务加WebView2的架构思路5.1 为什么这个方向值得关注老PB项目一般直接连数据库数据访问逻辑全在PB层。WebBrowser展示静态页面还好一旦页面要实时查询、分页、提交表单靠拼URL和单向传参很难维护。一个更顺手的架构是PB客户端启动时起一个本地HTTP服务监听127.0.0.1的某个端口前端页面把请求通过fetch发给这个本地接口由PB侧处理数据访问、业务校验再把JSON结果返回给页面。这个方案的好处是PB保留数据访问和事务控制能力页面专心做展示和交互前后端分工清楚而且页面调试可以直接用浏览器打开本地地址不用每次启动客户端。所谓“调用pb模型”在这个架构里其实就是页面把请求发到PB服务PB调用自己积累下来的业务处理逻辑和数据层再把结果回传业务规则始终留着PB这一侧。5.2 落地时的注意事项端口要固定并做占用检测起不来时给出明确提示本地接口要做简单的token校验防止其它进程乱调用前端静态文件建议放在客户端安装目录下用file://或http://localhost访问如果走WebView2需要解决PB调用COM封装的问题相比WebBrowser前期投入更大但后续不会再吃IE的亏。这个架构其实已经偏向于把PB当作一个带界面的本地服务容器对于还在维护PB老项目、又不想放弃现代Web前端的团队是个可行的过渡方案。5.3 我的建议不要为了技术而技术。如果你的需求仅仅是显示个报表、公告、图表WebBrowser够用。如果你发现业务开始大量使用现代前端组件、交互复杂那说明系统改造的窗口期到了可以认真评估WebView2或独立的Web前端模块而不是继续在PB窗口里堆嵌入式浏览器。最后说点个人的体会。PB嵌入Web浏览器这块网上资料不算多而且版本差异大很多方案在开发机上一跑就对到客户环境就各种问题。我吃亏最多的就是注册表文档模式和32位/64位视角两个问题现在写代码的第一件事就是先把FEATURE_BROWSER_EMULATION确认掉再谈功能。如果你也正在维护PB项目建议先拿一个最小窗口把OLE控件、导航、DOM读取跑通再往上加业务这样排查问题会从容很多。真到了需要大规模上复杂前端页面的那天也别犹豫该换WebView2封装就换该拆独立模块就拆老项目最怕的不是技术旧而是不敢动。本文还有配套的精品资源点击获取