Database 版 (精华区)
发信人: wodeji (西西), 信区: Database
标 题: [转载] PowerBuilder 开 发 系 列 谈 (20)
发信站: 紫 丁 香 (Tue Sep 29 17:52:24 1998), 站内信件
【 以下文字转载自 Programming 讨论区 】
【 原文由 two 所发表 】
Email: sjhzyz@public.bta.net.cn
上 期 我 们 介 绍 了 调 用WindowsAPI 函 数 的 方 法, 本 期 我 们 继 续 介 绍 几 个 常
用 的API 函 数。
一 个 简 单 的 文 件 拷 贝 例 程
Windows 操 作 系 统 在 象 文 件 操 纵 一 类 的 低 级 函 数 调 用 方 面 是 相 当 灵 活
的。 而 在PowerBuilder 中 为 了 实 现 这 一 些 低 级 操 作, 开 发 者 们 必 须 用 第 三 方 开
发 库( 如:FUNCkyforPowerBuilder 库) 或 用C 语 言 之 类 的 语 言 开 发 自 己 的 库, 这
种 方 法 我 们 将 在 后 面 的 章 节 中 讨 论。 在 这 里, 我 们 首 先 展 示 如 何 通 过 调
用WindowsAPI 函 数 实 现 简 单 而 又 常 用 的 低 级 操 作: 文 件 拷 贝。
使 用WindowsAPI 而 不 用 第 三 方 开 发 库 的 主 要 好 处 是, 如 果 这 是 您 所 要 的
唯 一 的 低 级 操 作, 在 发 布 您 的 应 用 时 就 不 需 要 同 时 将 额 外 的 库 打 包 进 您 的
应 用 中。 但 如 果 您 还 需 使 用 了 第 三 方 开 发 库 提 供 的 其 它 服 务, 为 简 单 起
见, 您 使 用 第 三 方 开 发 库 所 提 供 的 例 程 可 能 要 更 方 便 些。
实 现: 首 先 声 明 下 列localexternal 函 数
Function long LZOpenFile(string FileName, REF ws_ofstruct FileStructure,
uint style) Library "lzexpand.dll"
Function long CopyLZFile(uint SourceHandle, uint DestHandle)
Library "lzexpand.dll"
Function long LZClose (uint FileHandle) Library "lzexpand.dll"
ws_ofstruct的窗口级结构如下:
Variable Name
Data Type
byte[1]
char
fixed_disk[1]
char
errorcode
uint
reserverd[4]
char
pathname[128]
char键入下面的一个窗口级函数:
wf_copy
// 返 回: boolean
// 参 数:
string as_source
string as_dest
long ll_SourceFileHandle, ll_DestFileHandle, ll_result
ws_ofstruct lstr_SourceFileStructure, lstr_DestFileStructure
// 打 开 源 文 件
ll_SourceFileHandle = LZOpenFile ( as_source, lstr_SourceFileStructure, 0 )
IF ll_SourceFileHandle = -1 THEN
MessageBox ( " 程 序 错 误", " 无 法 打 开 文 件: " + as_source )
Return FALSE
END IF
// 打 开 目 标 文 件
ll_DestFileHandle = LZOpenFile ( as_dest, lstr_DestFileStructure, 4096 )
IF ll_DestFileHandle = -1 THEN
MessageBox ( " 程 序 错 误", " 无 法 创 建 文 件: " + as_dest )
LZClose ( ll_SourceFileHandle )
Return FALSE
END IF
// 拷 贝
ll_result = CopyLZFile ( ll_SourceFileHandle, ll_DestFileHandle )
IF li_result < 0 THEN
MessageBox (" 程 序 错 误"," 无 法 拷 贝 文 件: " + as_source &
+ " to file: " + as_dest )
LZClose ( ll_SourceFileHandle )
LZClose ( ll_DestFileHandle )
Return FALSE
END IF
// 关 闭 文 件
LZClose ( ll_SourceFileHandle )
LZClose ( ll_DestFileHandle )
Return TRUE
工 作 原 理
Windows 所 带 的COMPRESS.EXE 是 一 个 处 理 采 用Lempel-ziv 算 法 压 缩 的 文 件 的
可 执 行 文 件。 此 外Windows 内 部 还 包 含 了 几 个 处 理 这 一 算 法 的 函 数, 其 中 之
一 是LzCopy 函 数, 该 函 数 可 以 用 来 生 成 解 压 缩 文 件。 同 时LzCopy 函 数 的 文 档
中 还 说 明 了:“ 如 果 原 文 件 未 被 压 缩, 该 函 数 复 制 原 文 件。” 于 是LzCopy 函
数 也 可 以 用 作 一 个 快 速 的 文 件 拷 贝 函 数。
LzCopy 函 数 有 两 个 参 数, 原 文 件 和 目 标 文 件 的 句 柄。 但 是 不 幸 的
是,PowerBuilder 提 供 的FileOpen 函 数 返 回 的 文 件 句 柄 并 不 是LzCopy 所 需 要 的 那
个 句 柄。 因 此, 如 果 调 用WindowsAPI 中 的LzCopy 函 数, 我 们 必 须 同 时 使
用LzOpenFile 和LzClose 函 数, 以 确 保 获 得 所 需 要 的 文 件 句 柄。
LzFileOpen 函 数 有 三 个 参 数。 第 一 个 参 数 是 将 要 打 开 的 文 件 名, 第 二 个 参
数 是 一 个 结 构, 这 个 结 构 将 在 函 数 调 用 时 填 入 有 关 这 个 文 件 的 信 息,
与PowerBuilder 的FileOpen 函 数 一 样,LzFileOpen 函 数 可 以 创 建 或 打 开 一 个 文 件。
该 函 数 的 第 三 个 参 数 指 明 该 函 数 是 被 用 来 以 只 读 方 式 打 开 文 件(0) 还 是 以
只 写 方 式 创 建 文 件(4096)。 当 我 们 打 开 了 源 文 件 和 目 标 文 件 后, 我 们 只 要 简
单 地 将 返 回 的 这 两 个 文 件 的 句 柄 传 递 给LzCopy 函 数, 就 可 实 现 文 件 拷 贝。
最 后, 在 退 出 之 前 调 用LzClose 函 数 来 关 闭 这 两 个 文 件。
判 断 另 一 应 用 是 否 正 在 运 行
实 现: 首 先 声 明 下 列localexternal 函 数
Function uint GetModuleHandle(string ModuleName) Library "kernel"
Function uint GetModuleUsage(uint ModuleName) Library "kernel"
Function uint FindExecutable(string FileName, &
REF string Directory, REF string Result) Library "shell"
键入下面的一个窗口级函数:
fw_check_app_status
// 返 回: boolean
// 参 数:
// string as_filename
// string as_directory
integer li_size = 144, li_result
string ls_executable = Space ( li_size )
integer li_module_usage
uint li_module_handle
li_result = FindExecutable ( as_filename, as_directory, ls_executable )
IF li_result < 32 THEN Return FALSE
//如可执行文件已载入,获取这个执行文件的句柄
li_module_handle = GetModuleHandle ( ls_executable )
IF li_module_handle < 1 THEN
// 没 有 载 入
Return FALSE
ELSE
// 获 取 有 多 少 个 实 例 被 载 入
li_module_usage = GetModuleUsage ( li_module_handle )
Return TRUE
END IF
工 作 原 理
这 段 程 序 可 以 获 取 某 个 应 用 是 否 正 在 运 行。
我 们 用windowsAPI 中 的GetModueHandle 函 数 来 判 定 是 否 另 一 个 应 用 正 在 运
行。 为 了 做 到 这 一 点, 我 们 需 要 知 道 文 件 的 全 路 径 名( 包 括 驱 动 器 名 和 路
径)。 我 们 可 以 将 它 包 含 在 应 用 的INI 文 件 中, 也 可 以 通 过 写 入 源 代 码 将 它
嵌 入 可 执 行 程 序。 这 里 向 大 家 推 荐 的 是 采 用 前 者 的 方 法, 这 样 作 可 使 应 用
具 有 更 多 的 灵 活 性。 在 上 面 的 窗 口 级 函 数 中, 我 们 首 先 在 用 户 的Windows 目
录 中 查 找win.ini 文 件。 因 为 对 于 我 们 需 要 进 行 查 询 的 应 用 与 特 定 扩 展 名 的 文
档 之 间 的 关 联 被 记 录 在WIN.INI 文 件 中。 于 是 我 们 所 要 做 的 第 一 件 事 就 是
在WIN.INI 文 档 中 查 找 这 一 关 联, 以 知 道 我 们 所 要 寻 找 应 用 是 从 通 过 哪 个 软
件 装 入 的。 我 们 可 以 自 己 搜 索WIN.INI 文 件, 或 者 调 用WindowsAPI 中
的FindExecutable 函 数 来 得 到 这 一 信 息。 这 里, 我 们 使 用 了 第 二 种 方 法。 我 们
只 要 将 与 我 们 所 希 望 寻 找 的 可 执 行 程 序 相 关 联 的 一 个 文 件 的 文 件 名 与 路
径 传 递 给FindExecutable 函 数, 就 会 得 到 该 可 执 行 程 序 的 全 路 径 名。 这 在 我 们
判 断 出 该 可 执 行 程 序 没 有 在 运 行 以 后 启 动 该 程 序 时 是 很 有 用 的。
一 旦 获 得 了 可 执 行 程 序 的 全 路 径 名, 我 们 将 它 传 递 给GefModuleHandle 函
数。 如 果 应 用 正 在 运 行, 则 该 函 数 返 回 应 用 的 句 柄。 如 果 返 回0, 说 明 应 用
并 没 有 装 入, 此 时 退 出 函 数。 如 果 应 用 正 在 运 行, 我 们 将 获 得 的 应 用 的 句
柄 传 递 给GetModuleUsage 函 数。 这 个 函 数 的 返 回 值 会 告 诉 我 们 这 个 应 用 有 几
个 不 同 的 实 例。 在 我 们 的 例 子 中, 如 查 询 的 应 用 是MicrosoftWord, 该 应 用 是
不 允 许 多 个 实 例 同 时 运 行, 但 象NotePad 这 样 的 应 用, 这 些 信 息 对 还 是 非 常
有 用 的。
激 活 另 一 个 应 用
实 现: 首 先 声 明 下 列localexternal 函 数
Subroutine BringWindowToTop(int hWnd) Library "User"
Function uint GetNextWindow(uint hWnd, int Flag) Library "user"
Function uint GetWindowText(uint hWnd, REF string Title, uint Size )
Library "user"
Function uint ShowWindow(uint hWnd, int CmdShow) Library "user"
Function integer IsIconic(uint hWnd) Library "user"
Function integer OPenIcon(uint hWnd) Library "user"
Function integer FindWindow(string ClassName, string WindowName)
Library "user"
Function integer FindWindow(long ClassName, string WindowName)
Library "user"
Function integer FindWindow(string ClassName, long WindowName)
Library "user"
键入下面的一个窗口级函数:
fw_make_app_active
// 返 回:boolean
// 参 数:
//string as_title
boolean lb_cont = TRUE
integer li_result, li_size
string ls_title
uint li_handle
li_handle = Handle ( this )
li_size = Len ( at_title ) + 1
//li_handle = FindWindow ( 0, "Control Panel" )
DO WHILE lb_cont
li_handle = GetNextWindow ( li_handle, 1 )
If li_handle = Handle ( this ) THEN Return FALSE
li_result = GetWindowText ( li_handle, ls_title, li_size )
IF ls_title = as_title THEN lb_cont = FALSE
LOOP
//ShowWindow ( li_handle, 3 )
IF IsIconic ( li_handle ) > 0 THEN
OpenIcon ( li_handle )
ELSE
BringWindowToTop ( li_handle )
END IF
Return TRUE
工 作 原 理
获 得 另 一 个 应 用 最 顶 层 窗 口 引 用 的 最 简 单 的 方 法 就 是 用FindWindow 函 数
来 查 找。FindWindow 函 数 有 两 个 参 数: 您 要 找 的 窗 口 的 类 名 和 窗 口 的 标 题。
注 意, 我 们 在localexternal 函 数 中 用 三 种 方 式 声 明 了 这 一 函 数。 这 是 因 为 您 可
以 用null 作 为“ 通 配 符” 分 别 传 递 两 个 参 数。 为 了 传 递null, 您 必 须 将 参 数 类
型 定 义 成long 型, 其 值 为0。 所 以 我 们 需 要 为 每 一 种 可 能 的 调 用 形 式 定 义 一
个localexternal 函 数。 当 我 们 真 正 使 用 这 个 函 数 时,PowerBuilder 自 动 判 断 我 们 要
用 哪 一 种 形 式。
例 如 在 窗 口 函 数fw_make_app_active 中, 我 们 可 以 用 这 种 手 段 使Findwindow 函
数 搜 索ControlPanel 窗 口。 接 下 来 只 要 将Findwindow 函 数 返 回 的 窗 口 句 柄 传 递
给BringWindowToTop 函 数 就 可 以 激 活ControlPanel 窗 口 了。
但 是 这 样 的 做 法 有 这 样 两 点 缺 陷:
您 并 不 总 是 知 道 某 个 应 用 的 顶 层 窗 口 的 全 名。 例 如 当 您 使
用MicosotWord, 当 前 打 开 的 文 档 的 名 字 也 将 出 现 在 窗 口 的 标 题 上。 因 此, 这
种 情 况 下, 寻 找 顶 层 窗 口 需 要 另 一 种 方 法。
如 果 您 希 望 激 活 的 窗 口 正 处 于 最 小 化 状 态,BringWindowToTop 函 数 将 不 能
正 常 工 作。
实 际 上, 上 面 提 到 的 第 二 个 问 题 比 较 容 易 解 决。 我 们 加 入IsIconic 函 数 判
断 我 们 所 要 激 活 的 窗 口 是 否 最 小 化。 如 果 不 是 最 小 化 状 态, 就 使
用BringWindowsToTop 函 数。 如 果 是 最 小 化 状 态, 就 用OpenIcon 函 数 来 激 活 该 窗
口。 这 种 方 法 只 假 定 我 们 想 以 窗 口 最 小 化 前 的 大 小 及 位 置 显 示 该 窗 口。 我
们 也 可 以 用ShoWindow 函 数 来 对 要 显 示 的 其 它 应 用 的 窗 口 施 以 更 多 的 控 制。
本 例 中, 我 们 传 送 一 个 参 数 使 被 激 活 窗 口 以 最 大 化 方 式 显 示。 如 果 您
想 以 不 同 的 方 式 激 活 窗 口, 请 参 照 下 表 的 参 数 对 应:
0
隐 藏 窗 口
1
以 窗 口 原 来 的 大 小 和 位 置( 如 果 当 前 窗 口 处 于 最 大 化 或 最 小 化 状 态) 并
激 活 该 窗 口( 与 值 相 同)
2
以 最 小 化 方 式 显 示 并 激 活 窗 口
3
以 最 大 化 方 式 显 示 并 激 活 窗 口
4
以 窗 口 最 近 一 次 的 大 小 和 位 置 显 示 但 不 激 活 窗 口
5
以 窗 口 最 近 一 次 的 大 小 和 位 置 显 示 并 激 活 窗 口
6
最 小 化 窗 口 并 在 系 统 列 表 中 激 活 顶 层 窗 口
7
最 小 化 窗 口 但 不 激 活 窗 口( 保 持 当 前 窗 口 激 活)
8
以 窗 口 的 当 前 状 态 显 示 但 并 不 激 活 它( 保 持 当 前 窗 口 激 活)
9
恢 复 窗 口 原 先 的 大 小 和 位 置( 如 果 窗 口 处 于 最 小 化 或 最 大 化 状 态) 并 激
活 它 解 决 第 二 个 问 题 时, 我 们 声 明 了 另 外 两 个 函 数,GetNextWindow
和GetWindowsText。 如 果 我 们 将 一 个 窗 口 句 柄 传 递 给GetNextWindow 函 数, 它 将
在 父 窗 口 所 属 的 所 有 子 窗 口 之 间 循 环。 如 果 将 一 个 顶 层 窗 口 句 柄 传 递 给 该
函 数, 该 函 数 将 在 所 有 顶 层 窗 口 之 间 循 环。 我 们 希 望 得 到 的 是 后 一 种 方
式, 所 以 我 们 首 先 要 获 取 自 己 应 用 的 顶 层 窗 口 句 柄。
当 我 们 在 顶 层 窗 口 之 间 循 环 时, 用GetWindowText 函 数 返 回 它 们 的 标 题。
这 个 函 数 有 三 个 参 数, 窗 口 句 柄, 一 个 用 以 返 回 标 题 的 字 符 串 以 及 返 回 字
符 串 的 最 大 长 度。 我 们 要 好 好 利 用 最 后 一 个 参 数, 因 为 我 们 并 不 想 要 匹 配
整 个 窗 口 标 题, 而 是 要 匹 配 能 保 证 我 们 发 现 所 要 寻 找 的 窗 口 的 长 度。 例
如, 如 果 我 们 将“MicrosoftWord” 传 递 给 这 个 窗 口 函 数 时, 这 个 函 数 判 断 文
本 的 长 度 并 将 它 加1, 这 样 只 将 我 们 将 要 比 较 的 串 的 长 度 传 递 给
了GetWindowText 函 数, 该 函 数 在 顶 层 窗 口 之 间 循 环, 寻 找 以 该 字 符 串 开 头 的
窗 口。 如 果 我 们 发 现 了 一 个 匹 配, 就 设 置 结 束 循 环 标 志, 退 出 循 环 并 继 续
执 行。 如 果 我 们 没 有 发 现 匹 配, 将 在 循 环 到 我 们 自 己 的 应 用 窗 口 时 退 出 循
环。 这 时, 我 们 简 单 地 退 出 函 数。
--
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: 202.97.236.132]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: whs.hit.edu.cn]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: cadcam.hit.edu.c]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.391毫秒