看表面意思:Get(获取)Window(窗口)Thread(线程)Process(程序)Id(ID),组合:获取当前线程的窗口进程ID。至于进程ID要着有什么用,自己以后深入32编程就知道了。 看看参数,ByVal hwnd As Long,哈哈,熟悉吧,一个hWnd句柄。lpdwProcessId As Long这个就是咱们需要的进程ID,老规矩,新建标准EXE,添加一个CommandButton,属性:Caption=获取窗口进程ID。代码如下:
Private Declare Function GetWindowThreadProcessId Lib \(ByVal hwnd As Long, lpdwProcessId As Long) As Long Private Sub Command1_Click() Dim PID As Long
GetWindowThreadProcessId Me.hwnd, PID
MsgBox \窗口进程的ID是:\
End Sub
我已经习惯了给大家分析了。首先看看第一个参数,ByVal hwnd As Long,又是句柄来的(问:废话!答:教会了你也别这样啊),lpdwProcessId As Long,这个就要注意了,看看这个参数的传递方式,是以ByRef进行传递的(问:呵呵,不懂什么意思?答:不懂?转回去看过程函数这章),也就是说ByRef是以地址进行传递的,过程中可以改变传递的参数值。明白了吗?还不明白的话回去乖乖看书吧!现在明白了传递方式,也就是说我们声明的PID是用来获取窗口进程ID的,厉害啊。
F5,运行之,点击Command1,PID出来了吧?没出来我马上从十楼跳下去。
温馨小提示^_^:hWnd可以传入其它窗口句柄,同样可以获取其它窗口进程ID。
接下来我们再来看看Set(设置),Set什么呢?当然还是Window(窗口)容易些,先列出几个常用的API:
SetWindowLong、SetWindowPos、SetWindowRgn、SetWindowText
接上面的。
首先咱们先看SetWindowText,咱们在上面讲过GetWindowText这个API,GetWindowText是用来获取窗口文本的,而这个正好相反。现在可以看看表面意思Set(设置)Window(窗口)Text(文本),好了这样理解就够了,我们已经知道这个API是设置窗口文本的,接着咱们就到API浏览器中找找这个API,如下:
Private Declare Function SetWindowText Lib \Alias \(ByVal hwnd As Long, ByVal lpString As String) As Long
接着咱们看里面所需要传递的参数,一共有两,第一个ByVal hwnd As Long我就不用说了,传入句柄呗,第二个ByVal lpString As String,其中声明的lpString是字符串变量,可想而知,这里需要传入字符串,好了,开始实践。新建一个标准EXE,然后添加一个TextBox控件,然后再添加一个CommandButton,写入以下代码:
Private Declare Function SetWindowText Lib \Alias \(ByVal hwnd As Long, ByVal lpString As String) As Long Private Sub Command1_Click()
SetWindowText Text1.hwnd, \这是咱们设置的文本\ End Sub
呵呵,这个看似比前面的更简单,不过我还是要罗嗦一下,首先把Text1的句柄传入第一个参数,这样API知道咱们需要操作哪个窗口,第二个是一个字符串变量,所以这里就是我们需要传入的文本。好了,F5运行,点击Command1,OK。
再看SetWindowPos,可以说这个API可以看成设置窗口位置,但是最终的实现效果取决于咱们传递的参数,好了,在API浏览器中找到这个API,如下:
Private Declare Function SetWindowPos Lib \Alias \al hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
呵!好家伙,这个API看起来有些复杂啊?不过别担心,有我在嘛,我会帮你好好分析的,这里还请大家别光我一个人分析,必须把自己融入进来,咱们一起分析这样不更有趣?好了,废话少说,先看第一个参数:
ByVal hwnd As Long 这里我就不讲了,传入窗口句柄
ByVal hWndInsertAfter As Long 好了,看看这个!hwndInstrAfter,可以看到里面包函有hwnd字符,这时你可能会说我前面不是已经说过嘛,只要看见包函有hwnd字符的都应该传入句柄嘛?呵呵,没错,你很聪明,记得我说的话呢!在这里夸一下你,别骄傲啊!现在咱们好好分析一下这个地方应该传入哪些参数!打开MSDN,不好意思是英文,这里我就把翻译过来的说明放上来,如下:
hWndInsertAfter - Long,窗口句柄。在窗口列表中,窗口hwnd会置于这个窗口句柄的后面。也可能选用下述值之一:
HWND_BOTTOM 将窗口置于窗口列表底部
HWND_TOP 将窗口置于Z序列的顶部;Z序列代表在分级结构中,窗口针对一个给定级别的窗口显示的顺序
HWND_TOPMOST 将窗口置于列表顶部,并位于任何最顶部窗口的前面
HWND_NOTOPMOST 将窗口置于列表顶部,并位于任何最顶部窗口的后面
可以看到这个地方有四个参数供我们选择,一般我们会使用第三个API常数和第四个API常数,这几个API常数都可以在API浏览器中找到,至于具体实现什么功能我相信大家都知道吧,后面有写呢!
再看看后面的几个 x,y,cx,cy 分别为Long变量,我上面讲过,SetWindowPos可以看成设置窗口位置嘛,所以这里理所当然是传入相关的坐标值,如果忽略则为0,自己可以试下。
ByVal wFlags As Long,这个参数,我又说过,看看字符Flags,呵呵,熟悉吧,所以这里咱们需要传入相关的标识常数,利用咱们以前学过的常数分析法进行分析,Set(S)Window(W)Pos(P)=SWP_ ,可以看到相关的常数了吧?这里我把相关常数的说明发上来大家看下,如下:
SWP_DRAWFRAME 围绕窗口画一个框
SWP_HIDEWINDOW 隐藏窗口
SWP_NOACTIVATE 不激活窗口
SWP_NOMOVE 保持当前位置(x和y设定将被忽略)
SWP_NOREDRAW 窗口不自动重画
SWP_NOSIZE 保持当前大小(cx和cy会被忽略)
SWP_NOZORDER 保持窗口在列表的当前位置(hWndInsertAfter将被忽略)
SWP_SHOWWINDOW 显示窗口
SWP_FRAMECHANGED 强迫一条WM_NCCALCSIZE消息进入窗口,即使窗口的大小没有改变
所以我说过,一个这样的API他具体实现的功能取决于你所传递的参数。假设这里咱们需要实现一个窗口永远置前的功能,首先新建一个标准EXE,输入以下代码:
Private Declare Function SetWindowPos Lib \(ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long Private Const HWND_TOPMOST = -1 Private Const SWP_NOMOVE = &H2 Private Const SWP_NOSIZE = &H1 Private Sub Form_Load()
SetWindowPos Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE End Sub
现在咱们开始分析,第一个参数传入句柄,第二个我上面讲过,实现什么功能传入什么参数,这里咱们是实现的窗口永久置前的功能,所以传入HWND_TOPMOST常数,现在看看其实坐标,如果你不想改变窗口的具体位置的话,这里可不设为0,再看看后面的wFlags,我传入了两个常数,这两个常数的相关说明请大家看看上面就知道,主要是不改变窗口位置和不改变窗口大小的前提下把窗口置前,其它常数如果大家有兴趣可以自己试试。
最后一个,看看SetWindowRgn,这里我要解释一番,这个API所实现的功能呢就是改变窗口外观,也就是咱们所说的异形窗口等,通过这个API咱们可以把窗口改变成任何形状,在API浏览器找到这个API,如下:
Private Declare Function SetWindowRgn Lib \al hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
好了,第一个参数,句柄。第二个参数,Long变量,这里需要传入什么咱们下面会讲到。第三个,Boolean变量,可以说明这里需要传入布尔值,Redraw为重画的意思,所以如果我们用这个API改变窗口形状,这里需要为True,表示重画窗口。
现在新建一个标准EXE,然后把Form的ScaleMode设置成3-Pixel,我们知道Windows是以像素为单位的,所以使用这个API进行设置的时候是以像素为单位进行处理窗口外观。然后把BorderStyle设置为0-None,这样看得更明显。好了,写入以下代码:
Private Declare Function SetWindowRgn Lib \al hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
Private Declare Function CreateRoundRectRgn Lib \al X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, ByVal X3 As Long, ByVal Y3 As Long) As Long Private Sub Form_Load() Dim hRgn As Long
hRgn = CreateRoundRectRgn(0, 0, Me.ScaleWidth, Me.ScaleHeight, 10, 10) SetWindowRgn Me.hWnd, hRgn, True End Sub
我不得不说一下这里我又用了一个API,主要是因为使用SetWindowRgn API是需要和其它API一起进行工作的,首先让我们先看看CreateRoundRectRgn这个API。分析如下:
整体的意思是:创建圆角矩形。这里提示大家一个技巧,一般API中包函Rgn字符的都是代表可以改变对象外观的。可以看看我们使用的两个API,一个是SetWindowRgn(Rgn),一个是CreateRoundRectRgn(Rgn),希望你能明白其中的共同点。 参数:x1,y1,x2,y2,x3,y3这些都是坐标值,具体说明见以下:
X1,Y1 ---------- Long,矩形左上角的X,Y坐标
X2,Y2 ---------- Long,矩形右下角的X,Y坐标
X3 ------------- Long,圆角椭圆的宽。其范围从0(没有圆角)到矩形宽(全圆) Y3 ------------- Long,圆角椭圆的高。其范围从0(没有圆角)到矩形高(全圆) 所以上面的代码具体是先通过CreateRoundRectRgn创建一个圆角矩形对象,然后通过SetWindowRgn来改变窗口的外观。
小提示:使用CreateRoundRectRgn可以创建圆角矩形,也可以使用CreateEllipticRgn创建椭圆形,CreatePolyPolygonRgn创建多边形,CreateRectRgn矩形等,细心观察它们最后三个字符 Rgn 呵呵,明白了吧。
3,获取其它窗口的句柄
这个我本来打算不讲的,不过网友们既然提出来了,我也只好详细说说。一般获取其它窗口的句柄使用以下API:
FindWindow,FindWindowEx,WindowFromPoint
这两个API就足矣,先看看第一个API的原型:
Private Declare Function FindWindow Lib \Alias \A\(ByVal lpClassName As String, ByVal lpWindowName As String) As Long 里面一共有两个参数,先看第一个:ByVal lpClassName As String,字符串变量,所以这里需要传入字符串,第二个ByVal lpWindowName As String,同样一个字符串变量,这里也需要传入字符串。再看这个API为Function,有返回值的,那返回值就是我们需要的句柄了。好了,现在了解了两个参数的具体传递类型,那我们现在就要知道这两个参数中到底应该传入哪些值?如下:
ByVal lpClassName As String,lpClassName:类名。指窗口类名,如果忽略则传入vbNullString。
ByVal lpWindowName As String,lpWindowName:窗口名称。指窗口文本,如果忽略则传入vbNullString。
现在明白了两个参数需要传入哪些值就好办了,一个窗口的类名咱们有可能不知道,但是一个窗口的名称就好办了。如:咱们打开记事本程序,可以看到窗口标题显示为“无标题-记事本”。好了这就是咱们需要的,现在咱们就要通过这个窗口标题来获取记事本的句柄。新建一个标准EXE,然后输入以下代码:
Private Declare Function FindWindow Lib \Alias \al lpClassName As String, ByVal lpWindowName As String) As Long Private Sub Form_Load()
Dim WindowHandle As Long
WindowHandle = FindWindow(vbNullString, \无标题 - 记事本\
MsgBox WindowHandle End Sub
好了,F5运行,显示MsgBox消息框,如果不为0,那么咱们就获取成功了,如果为0,那么表示获取失败,这个时候你有必要检查一下你所要获取的窗口文本是否符合你所要获取的那个窗口文本(呵,这句话还真长!)。具体代码意思我就不讲了,大家可以自己分析下。
小提示:这个时候咱们已经得到句柄了,具体得到这个句柄干什么?那就看你了。给个