简介PowerBuilder 11.5 安装文件面向需要搭建经典 C/S 开发环境、维护既有项目或开展课程实验的技术人员与学生核心作用是提供可本地部署的开发工具介质便于完成安装、旧工程打开、兼容性验证与基础功能练习。资源以 rar 压缩包形式分发整体约 729.75MB上游未提供可核对的文件总数与类型明细故不展开具体构成。已有 1346 人学习或下载说明该版本在遗留系统维护与教学场景中仍有持续需求。对于需要复现旧版环境、对照界面与编译行为或为老项目迁移做前置准备的读者这份安装包可作为环境搭建的基础材料帮助减少反复搜寻介质的时间并为后续配置、调试与验证提供统一起点。它适合个人开发者、企业运维及院校教学等场景尤其适合需要保留旧版工具链、降低环境差异排查成本的团队。1. PowerBuilder 11.5 是什么一份还在生产线上的老工具包第一次看到 pb11.5 这种命名不少人会以为它只是个过时的安装包。它实际是一套完整的快速应用开发环境核心是 DataWindow——把 SQL、显示格式、编辑规则、更新逻辑打包进一个对象里的数据控件界面画完业务逻辑基本就写完一半。它长期服务于 C/S 架构的企业管理系统11.5 这一代又补上了 .NET 目标编译能力能把已有的窗口和数据窗口生成为 WinForm 或 WebForm 程序集。谁还在用它维护十多年前进销存、车间管理、仓储系统的人以及接手一堆 .pbl 库却联系不上原开发者的人。这份资源解决的是环境搭不起来、代码跑不通这两件事。2. 装起来32 位运行时的硬约束与首次启动的四个检查点动手之前先明确一件事这个环境的失败八成不是安装包坏了而是位数、路径、客户端版本三件事没对齐。下面按装前盘点 → 装 → 启动验证 → 建工作区的顺序走每一步都给出可检查的判据而不是装完能打开就行。2.1 位数对齐32 位运行时是所有问题的源头PowerBuilder 11.5 的 IDE 和运行时都是 32 位的没有 64 位版本。这一条决定了后面所有环节数据库客户端必须装 32 位ODBC 数据源必须在 32 位管理器里注册调用外部 DLL 必须是 32 位连 Office 互操作也要看好位数。在 64 位 Windows 上直接打开ODBC 数据源管理器看到的是 64 位那一份里面永远不会出现你刚装的 32 位驱动这就是最常见的驱动装了但找不到。32 位的 ODBC 管理器入口在系统盘的SysWOW64目录下文件名同样是odbcad32.exe别被名字误导# 64 位系统上打开 32 位 ODBC 管理器才能看到 32 位驱动 C:\Windows\SysWOW64\odbcad32.exe # 对比默认路径打开的是 64 位管理器 C:\Windows\System32\odbcad32.exe判断标准很直接在 32 位管理器里能新建数据源并且在驱动程序页签里能看到目标数据库的驱动名才算过关。如果驱动列表是空的说明装的是 64 位客户端卸掉重装。数据库客户端的位数同样要对齐。以 Oracle 为例32 位客户端通常装在product\11.x\client_1这类目录装完要在环境变量里配ORACLE_HOME和NLS_LANG。NLS_LANG尤其关键写成SIMPLIFIED CHINESE_CHINA.ZHS16GBK还是AMERICAN_AMERICA.AL32UTF8直接决定数据窗口里中文是正常显示还是一排问号。这个坑后面第 5 章还会展开。2.2 安装顺序与路径规则顺序错了会互相覆盖。我一般按这个次序先装 IDE 本体再装数据库客户端最后打补丁或运行时组件。中间不要重装客户端去修一下因为某些客户端安装会重写PATH把 IDE 依赖的运行时 DLL 挤到后面导致启动时报找不到组件。路径规则三条不含中文、不含空格、不含括号。D:\PB115这类纯英文短路径最稳。含空格的路径在编译 .NET 目标、调用外部工具、生成 PBD 时都可能出问题而且报错信息往往指向别处排查起来特别费时间。安装完成后确认三件事安装目录下有pb.ini或类似配置文件、Shared目录下的运行时 DLL 齐全、开始菜单能拉起 IDE。缺 DLL 的情况多见于把 IDE 目录整个拷贝到另一台机器——这种绿色化用法在纯客户端部署时偶尔可行但 IDE 本身依赖注册表项拷过去大概率起不来。2.3 首次启动后的连通性验证启动 IDE 只是第一步真正要验的是能不能连库、能不能检索。最省事的做法是新建一个应用在 Application 的 Open 事件里写一段最小连接代码把 SQLCA 配好连上之后立刻断看返回值。// Application 的 Open 事件最小连通性验证 SQLCA.DBMS ORA // 数据库接口按实际替换 SQLCA.LogId app_user // 账号 SQLCA.LogPass ****** // 口令 SQLCA.ServerName orcl // 服务名 / 实例名 SQLCA.AutoCommit False // 必须关自动提交否则事务控制失效 SQLCA.DBParm // 连接参数按驱动要求填写 CONNECT USING SQLCA; IF SQLCA.SQLCode 0 THEN MessageBox(连接失败, SQLCA.SQLErrText) HALT CLOSE ELSE MessageBox(连接成功, 数据库接口可用) DISCONNECT USING SQLCA; HALT CLOSE END IFAutoCommit False这一行不要省。开着自动提交后面 DataWindow 的Update()加COMMIT的事务语义就乱了某些行会被单独提交掉回滚不回来属于典型的数据莫名其妙进库了。DBParm留空在多数驱动下能连通但如果客户端装了多套可能要显式指定ConnectString里的完整连接串。报错信息要会读。SQLCode为 -1 时看SQLErrText提示找不到接口通常是DBMS值写错或驱动 DLL 缺失提示ORA-12154之类是网络服务名解析问题跟 PB 无关去查客户端的tnsnames.ora。2.4 建立工作区、目标与库连通之后建工程骨架Workspace → Target → Library.pbl。一个工作区可以挂多个目标一个目标下可以有多个 pbl。我的习惯是按层次拆库app.pbl放应用对象和全局函数win.pbl放窗口dw.pbl放数据窗口对象nvo.pbl放非可视对象。这样十几年后别人接手还能一眼看出东西在哪。新建 Application 目标时向导会生成应用对象和应用级脚本别急着在这一步写业务。先把目标属性里的库搜索路径LibList配好把公共 pbl 加进去再开始写代码。搜索路径没配全编译时满屏函数未定义的报错都是这个原因。最后做一次编译验证点全量重建Full Build看输出窗口有没有 Error。Warning 可以暂时放过Error 必须清零。这一步不做等到后面生成 .NET 目标时会一次性爆出来定位成本翻好几倍。3. DataWindow 是灵魂从 SQLCA 连接到事务提交的完整链路PowerBuilder 的代码量大部分花在数据窗口上而数据窗口的坑集中在三处事务对象怎么给、检索出来怎么改、改完怎么提交。这一章把这条链路拆成四段每段给一段可抄的代码并说明参数改动的影响。3.1 SetTransObject 与 SetTrans 的区别数据窗口拿到事务对象有两种方式SetTransObject(SQLCA)和SetTrans()。前者把外部事务对象借给数据窗口用连接、提交、回滚都由你控制性能好是唯一推荐的用法后者让数据窗口自己内部建一个事务对象、自己连、自己断每次检索都重新建立连接性能差一个数量级而且事务边界不可控。常见误用是图省事用SetTrans()单机测试看不出问题一上多用户就出现连接数暴涨、锁等待。判断当前代码用的哪种搜一下SetTrans就知道。// 推荐写法显式绑定外部事务对象 dw_1.SetTransObject(SQLCA) long ll_rows ll_rows dw_1.Retrieve(ls_dept_id) // 参数对应数据窗口 SQL 里的检索参数 IF ll_rows 0 THEN MessageBox(检索失败, SQLCA.SQLErrText) END IFRetrieve()的返回值是检索到的行数返回 -1 表示出错。这个返回值一定要判不判的话出错时界面就是一片空白用户以为没数据实际是 SQL 报错了。3.2 检索、修改、提交的四步节奏数据窗口的保存不是一句Update()就完事正确节奏是四步先把编辑框里的内容推进缓冲区AcceptText、再执行更新Update、然后提交事务COMMIT、失败则回滚ROLLBACK。// 标准保存流程 IF dw_1.AcceptText() 1 THEN MessageBox(提示, 当前行输入不合法请检查) RETURN -1 END IF IF dw_1.Update() 1 THEN IF SQLCA.SQLCode 0 THEN COMMIT USING SQLCA; IF SQLCA.SQLCode 0 THEN ROLLBACK USING SQLCA; RETURN -1 END IF // 提交成功后复位更新标志否则下次保存会重复更新已提交的行 dw_1.ResetUpdate() ELSE ROLLBACK USING SQLCA; RETURN -1 END IF ELSE ROLLBACK USING SQLCA; MessageBox(保存失败, SQLCA.SQLErrText) RETURN -1 END IF RETURN 1AcceptText()的返回值判断不能省略。用户正在编辑某一行没按回车就点保存编辑框里的值还没进缓冲区这时直接Update()会漏掉那一行的修改。ResetUpdate()是最容易被忘的一步不调用它数据窗口会认为那些行仍然是已修改状态下一次Update()会把它们再发一遍 UPDATE 语句运气不好就撞上并发冲突或者触发器重复执行。Update()返回 1 表示所有更新都成功发出但这不等于数据库已提交。SQLCode才是数据库层面的结果。这两层判断都做才能保证不出现提示保存成功但数据没进库。3.3 缓冲区状态判断哪一行该发什么语句数据窗口内部按行维护状态分 Primary!当前显示、Filter!被过滤、Delete!已删除三个缓冲区每行又有 New!、NewModified!、DataModified!、NotModified! 四种状态。Update()就是根据这些状态决定发 INSERT、UPDATE 还是 DELETE。要手动干预用GetItemStatus()查状态用SetItemStatus()改状态。典型场景是业务上不允许某类行被更新但用户改了需要在提交前把它标回未修改。// 遍历主缓冲区统计各类状态的行数 long ll_i, ll_new, ll_mod, ll_del FOR ll_i 1 TO dw_1.RowCount() CHOOSE CASE dw_1.GetItemStatus(ll_i, 0, Primary!) CASE New! ll_new 1 CASE NewModified! ll_new 1 CASE DataModified! ll_mod 1 END CHOOSE NEXT // 已标记删除的行在 Delete! 缓冲区里单独统计 ll_del dw_1.DeletedCount() MessageBox(变更统计, 新增 String(ll_new) 行修改 String(ll_mod) 行删除 String(ll_del) 行)第二个参数传 0 表示整行状态传具体列号则查该列的状态。这个技巧在做保存前确认对话框时特别好用比自己去比对原始值可靠得多。3.4 一个通用的保存函数项目里每个窗口都写一遍保存逻辑迟早写岔。我一般封一个全局函数gf_save_dw(dw, ref string)接收数据窗口引用和错误信息输出参数返回 1 成功、-1 校验失败、-2 数据库错误。// 全局函数 gf_save_dw(as_dw, ref ls_err) returns integer // 参数as_dw 数据窗口控件引用ls_err 出错时回传错误描述 IF IsNull(as_dw) OR NOT IsValid(as_dw) THEN ls_err 数据窗口无效 RETURN -1 END IF IF as_dw.AcceptText() 1 THEN ls_err 存在不合法的输入项 RETURN -1 END IF IF as_dw.Update() 1 AND SQLCA.SQLCode 0 THEN COMMIT USING SQLCA; IF SQLCA.SQLCode 0 THEN as_dw.ResetUpdate() RETURN 1 END IF END IF ROLLBACK USING SQLCA; ls_err SQLCA.SQLErrText RETURN -2参数上有个细节传数据窗口用引用而不是值避免整对象拷贝。返回值设计成三态而不是布尔是因为校验失败和数据库失败要给用户完全不同的提示前者让他改输入后者要记日志找 DBA。4. 生成 .NET 目标WinForm 与 WebForm 的编译与发布11.5 这一代最有价值的增量是把 PB 代码编译成 .NET 程序集。它不能让老代码变成现代架构但能让一套跑在胖客户端上的系统以较低成本搬到浏览器或者托管到新的部署环境里。前提是你清楚哪些特性编不过去。4.1 目标类型怎么选新建目标时有三条路传统 Win32 应用、.NET WinForm、.NET WebForm。差别不只是界面形态编译产物、部署方式、支持的特性集都不一样。目标类型产物形态部署位置适用场景Win32 应用EXE PBD/DLL客户端本机内网胖客户端改动最小.NET WinForm程序集 .NET 运行时客户端本机需要与 .NET 组件互操作.NET WebForm程序集 Web 服务器IIS 等 Web 容器浏览器访问免客户端安装选型的判据不是哪个先进而是哪些代码能过编译。WebForm 对界面事件的语义和 Win32 差异最大DataWindow 的某些交互行为在浏览器里表现不一样改造量往往超出预期。如果只是想让老系统能调 .NET 写的加解密组件选 WinForm 目标最省事。4.2 编译过程与常见报错编译 .NET 目标在 IDE 里点Deploy或Build即可输出目录里会生成程序集和配套的清单文件。编译前必须全量重建一次把 PB 层的 Error 清干净因为它不会替你做语法检查。// 编译前建议跑一遍的兼容性筛查找出明显不被 .NET 目标支持的外部函数调用 // 在应用对象的适当位置调用把可疑调用打印到调试窗口 string ls_libs[], ls_funcs[] long ll_i, ll_j // 列出需要人工复核的外部函数声明逐一确认是否有 .NET 版本真正会卡住的通常是这几类直接调用 Windows API 的外部函数声明、依赖 16 位或特定硬件驱动的调用、某些 OLE 控件、以及带图形句柄操作的打印逻辑。这类代码不会全部报错有些是运行时才炸所以编译通过不等于能跑。我一般会先拿一个功能最少的窗口做试点编译跑通打开 → 检索 → 保存 → 关闭这条闭环再逐窗口往上加。一把梭全量编译报错列表几百条根本看不出因果。4.3 部署依赖清单生成程序集不等于能跑。目标机器上需要 .NET 运行时PB 11.5 这一代对应的是 2.0 时代的框架版本还需要 PB 的运行时 DLL 一起分发。缺一个启动就报无法加载文件或程序集。依赖类别典型文件放置位置PB 虚拟机运行时虚拟机与对象管理相关 DLL与主程序同目录数据窗口引擎数据窗口渲染与计算相关 DLL与主程序同目录数据库接口对应 DBMS 的接口 DLL与主程序同目录或系统路径字符集/国际化支持多语言与编码相关 DLL与主程序同目录.NET 运行时目标框架运行时系统级安装WebForm 部署在 IIS 下时还要注意应用池的位数设置——32 位运行时必须配 32 位应用池否则一样加载失败。这一条在 64 位服务器上是必踩项配置界面里启用 32 位应用程序那个开关就是干这个的。5. 避坑与排查五个高频翻车点下面这五条是我见过出现频率最高、且报错信息最容易误导人的问题每条按现象 → 原因 → 解决写方便对着排查。5.1 数据窗口里中文全变问号现象检索出来的中文字段在某些行显示为???另一些行正常。原因客户端字符集与数据库字符集不一致或者NLS_LANG配错。PB 通过客户端接口取数字符集转换在客户端完成配错了就是单向丢失。解决先确认数据库的实际字符集再把NLS_LANG改成匹配的值GBK 库配ZHS16GBKUTF-8 库配AL32UTF8重启 IDE 生效。改完仍有问题检查数据窗口里该列的显示格式有没有设定特殊字体。另外注意已经写成问号的数据是回不来的转换只在读取链路上生效。5.2 保存提示成功但库里没有数据现象点保存弹保存成功关掉窗口重开数据没了。原因调用了Update()但没COMMIT或者AutoCommit开着导致部分提交后再回滚。也有一种情况是开发时连的是测试库程序启动时连接串被硬编码指向了另一个库。解决按 3.2 的四步节奏重写保存逻辑确认COMMIT USING SQLCA真的执行到把AutoCommit统一设为 False连接串从配置文件或注册表读别硬编码。排查阶段可以打开数据库端的会话监控看有没有对应的 UPDATE 语句到达。5.3 编译 .NET 目标时报不支持的特性现象Win32 目标编译正常切到 .NET 目标后大量报错集中在外呼函数和控件上。原因.NET 目标运行在托管环境里无法直接承载部分原生调用和旧式控件。解决把不受支持的调用隔离到独立的非可视对象里为 .NET 目标提供一份替代实现控件类问题用等价的 .NET 控件或自绘替代。策略上先做能编过的最小集合再逐个功能补齐别指望一次全量迁移。5.4 客户端启动报找不到 XXX.dll现象开发机正常拷到用户机器上一启动就报缺 DLL且提示的文件名每次不一样。原因部署时只拷了主程序和 PBD没带运行时 DLL或者带了但位数不对32 位进程加载 64 位 DLL 会直接失败。解决按 4.3 的清单逐项核对用依赖查看工具列出实际加载的模块把缺失项补齐。位数问题用进程管理器确认目标进程是 32 位还是 64 位再对号入座。别靠多拷几个 DLL 试试那只会把问题藏得更深。5.5 更新返回 0 行没有任何报错现象Update()返回 1SQLCode为 0但数据库里对应行没有变化。原因数据窗口的 Update 属性里没勾选允许更新或者 WHERE 子句用的主键列不全导致更新条件匹配不上也有一种情况是行状态没变用户其实没改Update()自然不会对它发语句。解决打开数据窗口的 Update Properties确认目标表、可更新列、主键列三项都对把 WHERE 子句改成键列 原始值的组合避免并发覆盖调试时用GetItemStatus()确认行状态确实是DataModified!或NewModified!。6. 迁移与验证把老代码盘活的三个具体动作接手一套遗留系统最忌讳上来就重构。我的做法是先做三件低成本、高回报的事做完之后代码的可维护性和可迁移性会有明显改善。6.1 用数据窗口属性做静态体检不要靠翻代码找问题直接遍历 pbl 里的数据窗口对象把关键属性导出来看。更新属性缺失、检索 SQL 里带SELECT *、WHERE 条件用函数包住索引列这三类问题占了性能与数据一致性问题的一大半。// 遍历当前库中的数据窗口对象输出更新属性摘要 // 用法在调试环境执行一次结果写到文本文件人工复核 string ls_objects[], ls_name long ll_i, ll_count // 取库中对象列表后逐个 Describe 关键属性 // 关注点UpdateTable、UpdateWhere、KeyColumns 是否为空判断标准很简单UpdateTable为空说明这个数据窗口是只读的如果业务上需要它可写就是漏配UpdateWhere用的是键列还是全部列决定了并发场景下会不会互相覆盖KeyColumns不全更新条件必然匹配不上。把这三项导成一张表比读几千行代码快得多。6.2 用数据库端会话观察替代日志猜测PB 的报错信息粒度粗很多时候要靠数据库那边看。在测试环境开一个会话监控把应用跑一遍完整业务流程看实际发出的 SQL 长什么样、执行计划走没走索引、有没有隐式转换。常见发现是数据窗口检索条件传进来的参数类型和列类型不一致数据库做了隐式转换索引直接失效数据量一大就慢得离谱。修法很朴素把检索参数的类型和列类型对齐把 WHERE 里包在列上的函数挪到等号右边把SELECT *换成明确列。这三条改完多数越用越慢的问题能压下去一大截。提示改检索 SQL 后一定要重新检索验证行数是否一致条件变严会导致数据变少而界面不报错。6.3 验证方式跑通一条完整闭环再谈迁移迁移前我强制自己走一遍这套验证用同一份测试数据在旧环境和新环境各跑一次新增 → 修改 → 删除 → 查询比对结果表的每一列、每一行、每个字段的长度和精度。数值精度尤其容易被忽略PB 的 decimal 和数据库的 numeric 在位数上不一致时会悄无声息地做四舍五入等到财务对账才发现对不上。这套比对我一般做成两个导出文本再 diff几分钟就能看完比肉眼点界面可靠。有一次就是因为跳过了这一步上线后才发现金额字段少了一位小数返工的成本远高于当初多花的那半小时。从那以后我每次碰这类老项目都强制走一遍位数核对 → 最小闭环 → 全量比对这三步哪怕需求催得再急也不省。希望帮到你。包里的东西按第 2 章的顺序装、按第 3 章的链路跑大部分卡点都能自己趟过去。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?