Blast's Security Lab
22 Jun 2010
PowerBasic高效易用,从Visual Basic转到PowerBasic并不是难事,但是PowerBasic建立窗口困难,可能让新用户望而却步,随后PwrDev等软件诞生了,填补了它的不足。不过PwrDev并不像VB那样简单,每个控件都对应有各自的函数,但是查遍整个帮助文档,却没有看到它对ProgressBar的介绍。
PwrDev不支持ProgressBar吗?不是,在它的“Common ctrls”(标准控件)中就有一个ProgressBar,但是不知道什么原因的,PwrDev并没有它的相关函数,固然PwrDev是不支持ProgressBar1.Value这种用法的,然而又不能使用像TextBox那样的VD_GetText、VD_SetText等函数来设置或获取值,但是这个控件确实是一个常用控件,如果要使用它怎么办,看来只能动用Windows API了。
本文来自www.sacour.cn 转载请注明来源
Windows是一个句柄当道的系统,每个控件都有各自的句柄,PwrDev建立的程序更是不例外,使用GetWindow函数的话,我们可以实现遍历所有控件的目标。
GetWindow
函数功能:该函数返回与指定窗口有特定关系(如Z序或所有者)的窗口句柄。
函数原型:HWND GetWindow(HWND hWnd,UNIT nCmd);
PwrDev中和PowerBasic一样,引用了win32api.inc,所以不需要额外声明就可以直接调用这个函数,不过我们首先得获取主窗体的句柄,用什么函数吗?不需要,PwrDev中有个保留字就是用来存储主窗体句柄的,它是:nCbHndl (代码区会显示蓝色的),这样,有了它一切都好办了。
建立一个Button,一个ProgressBar,Function Form1_Button1_Click( ByVal nCbHndl As Long, ByVal nCbCtl As Long ) As Long的代码为:
遍历主窗体,找到一个类名为msctls_progress32(注意不是PwrDev自己说的Class:ProgressBar)的控件,它就是我们先前加上去的ProgressBar进度条了。
那么有了句柄怎么给它传递信息呢?估计你也想到了,使用SendMessage函数。
SendMessage
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
函数原型: LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
如果像我一样不熟悉ProgressBar而直接在VB6提供的API浏览器里面找WM_开头的常量,那是肯定找不到的,因为操作ProgressBar的Msg是PBM开头的,而API浏览器里面根本没这个常量……
请参考MSDN:http://msdn.microsoft.com/en-us/library/bb760816(VS.85).aspx (Progress Bar Controls)
请参考MSDN:http://msdn.microsoft.com/en-us/library/ff485990(v=VS.85).aspx (Progress Bar Control Reference --> Messages)
请参考MSDN:http://msdn.microsoft.com/en-us/library/bb760844(VS.85).aspx (PBM_SETPOS Message)
请参考BCB代码:http://www.functionx.com/bcb/controls/progressbar.htm
我们所需要的就是PBM_SETPOS这个常量,顾名思义,ProgressBarMessage-SetPosition。
在使用之前也许我们需要阅读一下,了解下它的规则(摘自PBM_SETPOS Message,网址见上方):
| Sets the current position for a progress bar and redraws the bar to reflect the new position. Parameters lParam Return Value Remarks Do not send this message to a control that has the PBS_MARQUEE style. |
翻译一下,
| 为进度条设置当前位置并重绘进度条以便反应实时位置。 参数: wParam, 有符号整数, 表明新位置 参数: lParam, 必须为0 返回值:返回之前位置 注意:如果wParam超出范围(大于最大值(.Max)或小于最小值(.Min)),位置会被设置到最近的边界(即最大值或最小值); 不要向有PBS_MARQUEE风格的控件发送这条指令。 |
好了,一切都准备完了,下面就可以直接写代码了。 测试用的代码如下: (行末有注释)
Static hnd As Dword, isChecked As Long 'hnd用于存储其句柄,不用每次都遍历控件;isChecked用于标记是否检查过。注意PwrDev(PowerBasic)没有Boolean布尔型,可以使用长整型或其他类型替代。
Static value As Long 'value用于测试效果
value+=1 'value自加一
If isChecked = 0 Then '如果没有检测那么
Dim dc As Dword,hdc As Dword '存储句柄用
Dim buff As Asciiz*255 'GetClassName需要Asciiz类型的变量
dc = GetWindow(nCbHndl ,%GW_CHILD)
hdc = GetWindow(dc,%GW_HWNDFIRST) '获取第一个控件的句柄
While(hdc) '一直到获取不到句柄位置
GetClassName(hdc,buff,255) '获取类名
If (Trim$(buff)= "msctls_progress32") Then '如果类名是msctls_progress32那么
SendMessage(hdc,%PBM_SETPOS,value,0) '修改进度为value
isChecked=1 '标记为已检测
hnd=hdc '存储句柄
Exit Do '退出循环
End If
hdc = GetWindow(hdc,%GW_HWNDNEXT) '不是msctls_progress32则继续
Wend
Else
SendMessage(hnd,%PBM_SETPOS,value,0) '已经检测过则直接修改进度为value
End If '结束。
等等,等等,这儿几个常量没有定义啊?常量在哪儿声明?之前我有发过一个帖子,名为《PwrDev中函数的声明位置》(http://www.sacour.cn/view.asp?id=61),只不过这次我们换到Constants(常数),
在里面写上:
Option Explicit
%GW_HWNDFIRST = 0
%GW_CHILD = 5
%GW_HWNDNEXT = 2
%PBM_SETPOS = &H402
这样就可以了!
顺便附上一些PBM常量的值:
%WM_USER = &H400
%PBM_SETRANGE = (%WM_USER + 1)
%PBM_SETPOS = (%WM_USER + 2)
%PBM_DELTAPOS = (%WM_USER + 3)
%PBM_SETRANGE32 = (%WM_USER + 6)
%PBM_GETRANGE = (%WM_USER + 7)
%PBM_GETPOS = (%WM_USER + 8)
按下F5编译运行程序,点击几次按钮,ProgressBar的值成功改变,修改成功!
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。