简介:PowerBuilder 11.5 的完整安装包,面向仍在维护经典 PowerBuilder 项目、需要搭建兼容开发环境的程序员与技术支持人员,也适合高校软件教学实验、旧系统迁移及课程案例复现等场景。压缩包为 rar 格式,体积约 729.75MB;上游未提供文件总数与主要类型明细,具体组成需以实际解压结果为准,不宜凭空推断。已有 1349 人学习下载,说明该版本在遗留系统维护和课程教学中仍有稳定需求。对于需要复现旧版 IDE 行为、排查 PB11.5 兼容性问题、准备实验机,或对照旧工程验证数据窗口、数据库连接、编译调试与可执行文件生成等环节的读者,这份安装文件可作为基础环境素材,帮助快速建立可运行的开发与调试起点。版本较老,安装前宜做好系统备份并在隔离环境验证,以兼顾项目维护、教学演示与运行稳定性。
1. PowerBuilder 11.5 到底能解决什么问题:三类人的三种用法
接手一套跑了七八年的客户端程序,源码只有一堆 .pbl,开发机上还留着当年装的 PowerBuilder 11.5(圈里一般直接叫 pb11.5)——这种场面在制造业、电力、医疗信息化的老项目里不算稀奇。PowerBuilder115.rar 这个包解出来,就是一套带 .NET 编译目标的经典 C/S 快速开发环境,核心价值有三个:DataWindow 的可视化数据绑定、PowerScript 的事件驱动写法、以及把存量 Win32 程序重新编译成 .NET 程序集或 ASP.NET WebForm 的能力。适合三类人:要维护老系统的、要把 C/S 往 B/S 上挪一步的、以及单纯想读懂 DataWindow 这套设计思路的。下面按“装得上、连得通、改得动、部得起来”的顺序拆。
2. 从解压到第一条数据:把连接闭环跑通再谈别的
很多人拿到这个包,第一步就卡在安装向导,第二步卡在 SQLCA 连不上库,第三步发现 DataWindow 检索回来全是空行。这三步其实是一个闭环,任何一环断了,后面看什么都是黑匣子。这一章把安装顺序、事务对象字段、最小验证窗口串起来,跑通之后你才有资格去动业务代码。
2.1 安装介质的目录结构,决定你该先点哪个 setup
完整介质里通常不是一个孤零零的 setup.exe,而是分成几块:根目录的启动器、Shared 共享组件目录、IDE 主程序目录、以及按数据库厂商分开的驱动目录。最容易翻车的做法是直接双击 IDE 目录里那个 setup,跳过共享组件——装完能打开,但一建 DataWindow 就报引擎加载失败。
正确顺序是先装 Shared 下的共享运行库,再装 IDE。装之前把安装包整个解压到本地磁盘,不要在压缩软件挂载的虚拟目录里跑,那条路径常常是只读的,安装程序写到一半就静默退出。
我一般会把安装路径定成不带空格、不带中文的短路径,比如D:\PB115。老安装器对Program Files (x86)这种带括号的路径处理得不好,注册表里写进去的路径经常被截断。装之前顺手做两件事:把 setup.exe 的兼容性设成 Windows XP SP3,勾上“以管理员身份运行”;临时把 UAC 调到最低,装完再调回来。
装完先别急着开 IDE,核对一下三个运行库文件在不在:
# 在共享组件目录下核对核心运行库,Win32 目标部署时也要带走这三个 cd /d D:\PB115\Shared\PowerBuilder dir pbvm115.dll pbdwe115.dll pbodb115.dll这三个 DLL 分别对应 PowerScript 虚拟机、DataWindow 引擎、数据库接口层。后面你做 Win32 发布,客户端机器上缺任何一个,程序都会在启动瞬间报“无法定位程序输入点”。所以打包的时候别只拷 exe 和 pbd,把这三个一起带上,这是血泪经验。
安装完成后再看 IDE 根目录下的初始化文件,确认[Database]段里的接口列表和你实际要连的数据库对得上。这里面列的一串 DBMS 名称,就是待会儿写进 SQLCA.DBMS 的合法取值,写错了连接阶段直接返回 -1。
2.2 SQLCA 的字段填入:一个字符不对就全盘皆输
PowerBuilder 里所有数据库操作都挂在一个全局事务对象 SQLCA 上。它的字段不多,但每个都有坑:
| 字段 | 作用 | 常见填错点 |
|---|---|---|
| DBMS | 指定数据库接口名 | 写成产品名而不是接口名,比如写Oracle而不是O10 Oracle 10g |
| Database | 库名 | Oracle 下这里填服务名,容易和 ServerName 搞混 |
| ServerName | 主机或 TNS 别名 | 填了 IP 但没配监听 |
| LogId / LogPass | 数据库账号 | 和 UserID / DBPass 混用 |
| AutoCommit | 是否自动提交 | 设成 True 后 Update 行为完全变样 |
| DBParm | 接口专属参数 | 引号嵌套写错,整串被截断 |
LogId和UserID这两个字段是历史遗留,大多数接口只认其中一组。稳妥做法是两组都填成同一个账号,省得在切换接口时反复调试。AutoCommit我从来都设 False,DataWindow 的 Update 机制依赖事务边界,开了自动提交,后面提交、回滚中的坑会一个接一个。
// 连接商业关系库的最小配置,字段值按你手上的环境替换 SQLCA.DBMS = "MSSOLEDB" // 接口名,不是产品名 SQLCA.Database = "ERPDB" SQLCA.ServerName = "10.0.0.12" SQLCA.UserID = "pbuser" SQLCA.DBPass = "******" SQLCA.LogId = "pbuser" // 和 UserID 保持一致,省得踩接口差异 SQLCA.LogPass = "******" SQLCA.AutoCommit = False SQLCA.DBParm = "" CONNECT USING SQLCA; IF SQLCA.SQLCode <> 0 THEN MessageBox("连接失败", SQLCA.SQLErrText) HALT CLOSE END IFSQLCode的取值约定要记牢:0 成功,100 无数据,-1 出错。很多人只判断是否等于 0,结果把“查不到数据”当成故障弹框,用户体验很差。SQLErrText是接口层回传的原始错误串,调试阶段一定要弹出来看,上线前再换成友好提示。
另外,如果你连的是需要字符集的库,DBParm里要显式带上编码参数,比如DBParm = "Charset=UTF8"或者对应接口的等价写法。这一步漏了,中文列在 DataWindow 里会变成问号,而且不会报错,属于最难查的那类问题。
2.3 用一个最小窗口验证 Retrieve 和 Update 的完整回路
连接通了不代表 DataWindow 能用。我习惯建一个只有三样东西的测试窗口:一个 DataWindow 控件、一个检索按钮、一个保存按钮。DataWindow 对象本身用 Grid 呈现,选一张有主键的小表,字段控制在五个以内。
// 窗口 open 事件:绑定事务对象 dw_1.SetTransObject(SQLCA) dw_1.Retrieve() // “检索”按钮 clicked 事件 long ll_rows ll_rows = dw_1.Retrieve() IF ll_rows < 0 THEN MessageBox("检索失败", SQLCA.SQLErrText) ELSEIF ll_rows = 0 THEN MessageBox("提示", "没有满足条件的数据") END IF // “保存”按钮 clicked 事件 integer li_rc li_rc = dw_1.Update() IF li_rc = 1 THEN IF SQLCA.SQLNRows > 0 THEN COMMIT USING SQLCA; IF SQLCA.SQLCode <> 0 THEN ROLLBACK USING SQLCA; MessageBox("提交失败", SQLCA.SQLErrText) END IF ELSE MessageBox("提示", "没有任何行被修改") END IF ELSE ROLLBACK USING SQLCA; MessageBox("更新失败", SQLCA.SQLErrText) END IFUpdate()返回 1 只代表“语句发出去了”,不代表“数据库真的变了”。真正判断有没有影响行数,要看SQLCA.SQLNRows。这个区别我在早期项目里吃过亏:界面上提示保存成功,实际一行都没写进去,因为 DataWindow 的 Update 属性根本没配,语句压根没生成。
测试窗口跑通之后,把这个窗口留着,后面每次改数据源、换接口、升补丁,都先用它验一遍,比直接开业务窗口排查快得多。
3. DataWindow 的三种操作与提交:先想清楚谁负责写数据
DataWindow 是 PowerBuilder 最核心也最容易误用的部分。新手常把它当“高级表格控件”用,写一堆循环去逐行赋值、逐行执行 SQL;熟手的做法是让它自己管结果集,你只负责告诉它“哪张表、哪些列、按什么条件更新”。这个思维差异决定了后面是写两百行代码还是二十行。
3.1 Presentation Style 的选择,取决于谁来改数据
新建 DataWindow 时那个下拉框里的每一项,对应的是不同的交互模型:
| 呈现风格 | 适用场景 | 不该用的场景 |
|---|---|---|
| Grid | 列表浏览、批量录入 | 字段超过 12 个,横向滚动体验差 |
| Tabular | 表头自定义、打印对齐 | 需要复杂布局的表单 |
| FreeForm | 单条记录编辑、字段多 | 一次要看几十行 |
| Crosstab | 交叉汇总报表 | 需要回写数据 |
| Group | 按维度分组的报表 | 高频刷新的操作界面 |
| Composite | 多报表拼接打印 | 交互式编辑 |
判断标准其实就一句话:这份数据是“看”还是“改”。要改的,Grid 或 FreeForm;只看不改的,Tabular、Group、Crosstab 随便挑。Crosstab 尤其要注意,它的行列是运行时动态生成的,你没法像普通 DataWindow 那样按列名取值,得走Describe("evaluate(...)")那条路。
还有个隐藏选项叫“可更新”(Updateable),它不在呈现风格里,而在 DataWindow 画板的 Update Properties 里。很多人建完对象直接拿去改数据,发现保存没反应,就是这里没开。
3.2 行状态机:New! 和 DataModified! 决定了 Update 生成什么语句
DataWindow 内部给每一行维护了一个状态,取值有四种:NotModified!、DataModified!、New!、NewModified!。这个状态机是 Update 的决策依据——它只对DataModified!和NewModified!的行生成 UPDATE,对New!的行生成 INSERT,对删除缓冲区的行生成 DELETE。
理解这一点,很多“为什么没更新”的问题就自己解开了。比如你在代码里SetItem改了值,但行状态还是NotModified!,Update 就不会处理它。判断方法:
// 逐行检查状态,定位 Update 为什么漏行 long ll_row integer li_status string ls_desc FOR ll_row = 1 TO dw_1.RowCount() li_status = dw_1.GetItemStatus(ll_row, 0, Primary!) CHOOSE CASE li_status CASE NotModified! ls_desc = "未修改" CASE DataModified! ls_desc = "已修改" CASE New! ls_desc = "新增未改" CASE NewModified! ls_desc = "新增且已改" END CHOOSE // 调试期直接打到 trace 窗口或日志文件 TraceOutput(ls_desc + " 行号=" + String(ll_row)) NEXTGetItemStatus的第二个参数传 0 表示整行状态,传具体列号则是该列的状态。第三个参数是缓冲区,除了Primary!还有Filter!、Delete!,统计各项数量可以直接用ModifiedCount()、DeletedCount()、FilterCount()。
有一个反直觉的点:InsertRow(0)插入的新行状态是New!,此时如果立刻调Update(),会生成 INSERT 但可能因为主键为空而失败。所以新增行的标准写法是先InsertRow,再SetItem填值,填完之后状态才会变成NewModified!。
3.3 从数据库约束反推 Update Properties 的五个勾选项
DataWindow 的 Update Properties 面板看着简单,实际每个选项都对应数据库侧的一个约束。打开它的方式是右键 DataWindow 对象 → Update Properties,里面有五项要填:
第一项 Table to Update,选要更新的物理表。如果是视图或多表关联,这里默认是灰的,得手工指定主表。
第二项 Where Clause to Update,决定 UPDATE 语句的 WHERE 条件用哪些列。三个选项:Key Columns(只用主键)、Key and Updatable Columns(主键 + 所有可更新列)、Key and Modified Columns(主键 + 本次改动的列)。选第二个是最保守的做法,能防止并发覆盖,代价是语句长一点;选第三个性能好但要求数据库侧有乐观锁字段配合。
第三项 Updateable Columns,勾选哪些列允许回写。只读列一定不要勾,否则界面上看着是灰色的字段也会被写回去。
第四项 Key Modification,决定主键变更时怎么处理。默认是 Use Delete then Insert,即删旧行插新行;如果你的表有级联外键,这个选项会连带删掉子表记录,必须改成 Use Update。
第五项 Identity Column,标识自增列。填对了,新插入行的自增 ID 会自动回填到 DataWindow 里;填错了,新行会显示主键为空。
我的习惯是先看数据库侧的建表语句,把主键、唯一索引、自增列、时间戳列抄一遍,再回来对着勾。这一步花五分钟,能省掉后面两小时的“保存后数据错乱”排查。
至于到底哪些操作该走 DataWindow、哪些该手写 SQL,判断标准也很实在:单表增删改交给 DataWindow,跨表事务、批量更新、复杂校验就老老实实写EXECUTE IMMEDIATE或者存储过程调用,别硬凑。
4. 编译成 .NET 的四条路径:目标类型决定了后面所有的部署动作
PowerBuilder 11.5 相比早期版本,最大的增量就是 .NET 目标支持。它能把 PowerScript 对象翻译成 C# 源码再编译成程序集,产出 WinForm、WebForm、Web Service 或纯类库。这个能力听起来很美,但选错目标类型,后面部署会难受很久。
4.1 四种 target 的差别,用“谁来调用”来判断
建 Project 对象时的那四个选项,本质是回答一个问题:最终是谁在调用你的代码。
| 目标类型 | 产出物 | 谁在调用 |
|---|---|---|
| .NET Windows Forms | exe + 若干 dll | 桌面用户直接双击 |
| .NET Web Forms | .aspx + bin 下 dll | 浏览器经 IIS |
| .NET Web Services | .asmx + dll | 其他系统按接口调 |
| .NET Assembly | 纯 dll | 第三方 .NET 程序引用 |
存量 C/S 程序想最小代价搬到浏览器上,选 Web Forms,界面布局会由工具自动生成 .aspx,原来窗口上的控件映射成 Web 控件。但要注意,DataWindow 在 WebForm 下的交互能力和 WinForm 下差一大截,客户端脚本、右键菜单、拖拽这些基本没有。如果业务强依赖这些,老老实实做 WinForm 加远程部署,别硬上 B/S。
Web Services 适合把已有的业务逻辑暴露出去,比如原来窗口里那段计算逻辑,抽出来做成服务。Assembly 最干净,适合做公共组件库,被别的 .NET 项目引用。
我一般的选型判断是:如果这个系统未来三年还要大规模改界面,选 WinForm;如果只是要把查询报表搬到内网浏览器上,选 WebForm;如果是要跟别的系统对接,选 Web Services。三条路可以在同一个工程里并存,不需要一次定死。
4.2 生成目录里到底有什么,每个文件对应哪个环节
编译完成后,输出目录的结构基本固定。以 Web Forms 为例:
输出目录/ ├── 应用名.aspx # 每个窗口对应一个页面 ├── web.config # 运行时配置,连接串和编译参数在这 ├── bin/ │ ├── 应用名.dll # 编译后的主程序集 │ ├── 应用名.pbd 对应的 dll │ └── 若干第三方依赖 └── scripts/ # 工具生成的客户端脚本.aspx是壳,真正的逻辑全在bin下的 dll 里。web.config里有两处必须改:一是连接字符串,二是编译目标框架版本。工具默认写进去的是生成时的框架版本,换机器部署经常对不上。
WinForm 目标的输出更简单,一个 exe 加若干 dll,双击就能跑,但前提是目标机器装了对应版本的 .NET Framework 运行时。这一点很多人忽略,测试机装了开发环境所以能跑,客户机上没装就直接报错退出。
Assembly 目标只有 dll,没有入口,得由宿主程序加载。调试的时候不能直接运行,要在宿主里打断点,这点比较麻烦,建议先做成 WebForm 验证逻辑,稳定之后再改成 Assembly。
4.3 应用池的三个开关,配错一个页面就 500
WebForm 目标部署到 IIS,最容易出问题的是应用池配置。三个必须确认的开关:
第一,托管管道模式。11.5 生成的代码基于较早期的 ASP.NET 模型,Integrated 管道下部分事件绑定会失效,页面能打开但按钮点了没反应。改成 Classic 管道。
第二,运行时版本。应用池的 .NET CLR 版本要和生成时用的框架版本一致,通常是 v2.0。选成 v4.0 会出现程序集加载失败。
第三,32 位应用程序。这个开关在应用池的“高级设置”里,默认是 False。因为工具链本身是 32 位的,生成的程序集也按 32 位编译,应用池不开启 32 位支持,页面直接报“无法加载程序集”。
# 用 PowerShell 一次性把三个开关配好,比在图形界面里翻菜单快 Import-Module WebAdministration $pool = "PB115Pool" New-Item IIS:\AppPools\$pool -Force | Out-Null Set-ItemProperty IIS:\AppPools\$pool -Name managedRuntimeVersion -Value "v2.0" Set-ItemProperty IIS:\AppPools\$pool -Name managedPipelineMode -Value "Classic" Set-ItemProperty IIS:\AppPools\$pool -Name enable32BitAppOnWin64 -Value $true # 把站点指到输出目录 New-WebApplication -Site "Default Web Site" -Name "pbapp" ` -PhysicalPath "D:\deploy\pbapp" -ApplicationPool $pool配置完之后别忘了给输出目录加 IIS 用户的读取和执行权限,以及给bin目录加读取权限。Windows 上这类权限问题表现得很含蓄,往往是一个 500.19 错误,错误信息里只写“配置错误”,实际是文件读不了。
另外,部署到新机器前,先在该机器上注册 ASP.NET:
# 注册对应版本的 ASP.NET 处理程序,缺这一步 .aspx 会被当静态文件下载 cd /d C:\Windows\Microsoft.NET\Framework\v2.0.50727 aspnet_regiis.exe -i这条命令在较新的 Windows 上可能需要用管理员权限的 PowerShell 跑,跑完iisreset重启一次。我见过最离谱的一次是站点配好了、池也对了、权限也给了,页面还是 404,最后发现就是没注册 ASP.NET,IIS 把.aspx当成未知扩展名处理。
5. 避坑:PB 11.5 在现代环境里出问题的五种情况
这套工具链的年龄摆在那,跑在今天的操作系统和数据库上,必然会有一批“当年不是问题、现在全是问题”的点。下面五条是我在不同项目里反复遇到的,按出现频率排序。
5.1 安装向导走到一半静默退出
现象:双击 setup.exe,进度条走到“正在配置”就没了,任务管理器里进程也消失,没有任何错误提示,事件查看器里只有一条应用程序错误。
原因:老安装器调用的是一套已经不在新系统上默认启用的组件注册接口,加上安装包解压在压缩软件的虚拟盘里,写临时文件时权限被拒,异常被吞掉了。
解决:三步一起做。把安装包完整解压到本地磁盘的短路径;setup.exe 右键属性里兼容性设成 Windows XP SP3 并勾选管理员运行;安装期间临时关闭杀毒软件的实时防护和 UAC。做完这三步,绝大多数卡安装都能过去。如果还不行,看安装目录下有没有生成日志文件,里面通常有一行“Return value 3”,那才是真正的失败点。
5.2 中文列在 DataWindow 里变成问号
现象:数据库里明明是正常中文,DataWindow 检索出来显示成???,但用同一个连接在 SQL 工具里查又是好的。界面上的中文标签也正常,只有数据是问号。
原因:接口层没有指定字符集,驱动用了默认的本地编码去解析服务端返回的字节流,解码失败就落到替换字符上。这属于静默失败,不报错,最难发现。
解决:在 SQLCA.DBParm 里显式加字符集参数,同时检查 DataWindow 里各列的字体设置。有些模板把字体写死成了一种不支持中文的英文字体,即使数据解码正确也显示不出来。改完重新检索验证,别只改一半就以为好了。另外,如果列宽设得太窄,中文被截断后看起来也像乱码,先拉宽再判断。
5.3 编译时报找不到 .NET 框架
现象:Win32 目标编译一切正常,切到 .NET 目标就报错,提示找不到编译工具或者某个程序集,错误码指向路径不存在。
原因:.NET 目标的编译依赖对应版本的框架开发包,光装运行时是不够的。而且工具链对安装路径有硬编码假设,装在非默认盘符或者路径里有空格,都会导致它找不到编译器。
解决:确认目标机器装了完整的框架开发包而不只是运行时;检查环境变量里的框架路径是否指向实际安装位置;安装路径统一用C:\Windows\Microsoft.NET\Framework\v2.0.50727这个标准位置。如果多版本共存导致冲突,就在 Project 对象的编译设置里显式指定框架目录,不要依赖自动探测。
还有一个容易忽略的点:编译过程中会生成临时源码文件,如果输出目录被设成了网络路径或者只读目录,编译会在中途失败,报的却是“找不到类型定义”,非常具有迷惑性。
5.4 WinForm 程序在客户机上启动就退出
现象:开发机上双击正常,拷到客户机上一闪而过,事件日志里只有一条 .NET 运行时错误,没有具体堆栈。
原因:多数是缺运行库。WinForm 目标虽然编译成了 .NET 程序集,但 DataWindow 引擎和数据库接口层仍然是原生 DLL,这些文件没有随程序集一起打包,客户机上自然加载失败。
解决:把共享组件目录下的那三个核心 DLL 连同数据库接口 DLL 一起拷到程序目录,或者干脆装一遍共享组件。另外要注意位数匹配,程序是 32 位的,拷过去的 DLL 也必须是 32 位版本,混用会在加载瞬间崩溃,报的错跟“文件不存在”完全不像。
排查这类问题最快的办法是在客户机上用进程监视工具看它最后加载了哪个文件失败,比猜快得多。
5.5 改了 DataWindow 但页面上显示的还是老的
现象:改了 DataWindow 的列宽或者显示格式,重新编译部署,浏览器里刷新十几遍还是旧样子。清浏览器缓存也没用。
原因:三层缓存叠在一起。工具的增量编译只重编改动过的对象,生成的程序集时间戳可能没变;IIS 那边的应用程序池没有回收,旧的程序集还挂在内存里;ASP.NET 的临时编译目录里还留着上一版。
解决:按顺序清。先在 IDE 里做一次全量重建而不是增量编译;部署时把bin目录整个清空再拷新文件,不要覆盖;然后在 IIS 里回收应用程序池;最后清掉框架的临时目录。四步做完再刷新,基本不会再有“改了没生效”的情况。从那以后我每次部署都强制走一遍这四步,宁可多花两分钟,也不要在那里反复刷新怀疑人生。
6. 接手老工程:先摸清对象清单,再谈改一行代码
拿到一套只有 .pbl 没有文档的老系统,最忌讳上来就改。我一般的顺序是先导出对象清单,用脚本做一次无人值守构建,确认“原样能编出来”,再动业务逻辑。第一步是在 Library 画板里把每个 pbl 的对象列表导成文本,应用对象、窗口、DataWindow、函数、结构体分类统计,重点看有没有跨库引用和外部函数声明,这两类是后面迁移时最容易断的。
第二步是用 OrcaScript 写一个构建脚本,把“打开工作区、设置库列表、全量重建、输出可执行文件”这一串动作固化下来:
start session set verbose level 3 set liblist "D:\src\app.pbl";"D:\src\common.pbl" build library "D:\src\app.pbl" from pbl build executable "D:\build\app.exe" from "D:\src\app.pbl" end session命令名和参数在不同小版本间有小差异,骨架照抄、细节对着手上的帮助文档核对。好处是构建过程可重复,出问题能定位到具体是哪个库、哪个对象。
第三步是回归对比。我会列一张检查表,至少覆盖:登录与权限、每个主界面的检索耗时、DataWindow 的增删改提交、报表打印的边距、以及退出时的资源释放。改动前后各跑一遍,把差异记下来。老系统里那些“看起来没用到”的全局函数,往往在某个犄角旮旯的按钮里被调用,删之前先全局搜一遍引用。这套流程我坚持了很多年,每次接手新库都从头走一遍,确实慢,但比事后补漏快得多。希望帮到你。
本文还有配套的精品资源,点击获取