利用VB编写屏幕保护程序 |
|||||||||||||||||
熟悉Windows操作系统的朋友一定对Windows的屏幕保护程序不陌生吧。如何自己编写Windows屏幕保护程序呢?当你看完下面的讲解后便可以轻易地编写一标准的Windows屏幕保护程序了! 一个标准的屏保有以下几个特点: 一:它是以.SCR作为文件的扩展名! 二:它有三种运行方式。 (1)运行在预览框中(用于预览屏保的效果。在“显示属性”→“屏幕保护程序”→“小屏幕”)。(见图) (2)运行设置程序(用于设置一些相关的样式。在“显示属性”→“屏幕保护程序”→“点击设置按钮”)。 (3)真正的运行屏保(屏保运行时的效果。在“显示属性”→“屏幕保护程序”→“点击预览”或鼠标、键盘在指定的时间内无动作时)。 如何让屏保识别当前需要运行哪一种方式呢?答案很简单——分析Windows调用屏保的参数。下面以Windows 98为例向大家分析一下调用屏保的参数。 当Windows需要屏保显示在“小屏幕”中时会在调用屏保的后面加上两个参数。 如:myscr.scr /p 7981(参数一:/p 表示让程序显示在“小屏幕”里,参数二:7981表示“小屏幕”的句柄hWnd。这样屏保就会得知Windows要它显示在“小屏幕”中。) 当Windows需要屏保显示设置对话框时会在调用屏保的后面不加或加上两个参数。 如:myscr.scr或myscr.scr /C 7987(参数一:/C表示让程序显示设置对话框,参数二:7987表示该属性页的句柄。) 当Windows需要运行屏保时会在调用屏保的后面加上一个参数。 如:myscr.scr /S(参数:/S表示让屏保运行。) 好了,知道了Windows如何让屏保运行的三种方式后,接下来就要讨论如何实现它们了。 实现原理:Windows通过某种方式调用屏保,屏保知道了它此时要干什么便会在当前环境中搜索是否有相同的实例存在。如果该实例的运行方式与此次要启动的运行方式不同则关闭前个实例,如果该实例的运行方式与此次要启动的运行方式相同则关闭此次运行的实例。 显然要实现这种方法靠VB的App.PrevInstance是不可行的。因为我们要达到的目的是:侦测到前一个实例后要关闭它然后启动程序。而App.PrevInstance属性只能返回当前是否已启动一个应用程序的实例而不能对前个实例做些什么。(实例 简单地说就是相同的对象集合——同一程序。)在实现此方法之前首先向大家介绍三条API函数:GetClassName、FindWindow和SendMessage。其原型如下:
GetClassName用于取得窗体的类名。调用成功后返回类名长度,失败返回零。函数需要三个参数:参数一.窗体的句柄,参数二.存放类名的缓冲,参数三.缓冲的大小。 FindWindow用于寻找窗体。调用成功后返回窗体的句柄,失败返回零。函数需要两个参数:参数一.窗体的类名,参数二.窗体的标题。 SendMessage用于向窗体发送一消息。函数需要四个参数:参数一.窗体的句柄,参数二:发送的消息名称,参数三、四.分别表示消息所附带的参数。 使用了这三个函数便可轻易地实现关闭前有一个已启动的实例从而达到我们的目的。 其次我们要实现如何让屏幕保护程序显示在预览框中(“小屏幕”)。 要让屏幕保护程序在预览框中显示必须动态地改变窗口的样式使之成为“小屏幕”的子窗体,这样才能使预览框关闭时得到关闭消息。动态地改变窗口的样式可以使用GetWindowLong、SetWindowLong和SetParent。 它们的原型如下:
GetWindowLong的作用用于得到窗体的样式。调用成功后返回窗体的样式。函数需要两个参数:参数一.窗体的句柄,参数二.要取得窗体的样式只需使用常数GWL_STYLE。 SetWindowLong的作用用于设置窗体的样式。函数需要三个参数:参数一.窗体的句柄,参数二.要设置窗体的样式只需用常数GWL_STYLE,参数三.要设置窗体的样式。 SetParent的作用用于设置子窗体属于哪个父窗体。函数需要两个参数:参数一.子窗体的句柄,参数二.父窗体的句柄。 知道了以上两点就可编写出标准的屏保。(关于效果就看你自己的了!)纸上谈兵了一阵就要落实到真正的编程上了。为了着重讲解屏保的实现方法故将屏保的效果简单化。 首先新建一工程再添加一窗口,各属性设置如下:
Sub Main() '程序运行入口 Dim ClassName As String * 64 存放窗口的类名 Dim ExeCmd As String '存放命令行参数 GetClassName Frm_Setup.hwnd, ClassName, 64 取得窗口的类名 ExeCmd=UCase(Command$) 将调用的屏保的参数转换成大写后存放在变量ExeCmd里 If Not (InStr(ExeCmd,“/P”)=0)Then 检查屏保的调用参数中是否有“/P”参数 If Not (FindWindow(ClassName, WM_LOOK)=0)Then End 如果找到已有同一个运行方式的实例存在则程序结束 ClosePreWindow ClassName, WM_SET 关闭前面已启动的其他运行方式的实例 ClosePreWindow ClassName, WM_RUN 同上 SCR_Look ElseIf Not (InStr(ExeCmd,“/S”)=0)Then If Not (FindWindow(ClassName,WM_RUN)=0) Then End ClosePreWindow ClassName, WM_LOOK 同上 ClosePreWindow ClassName, WM_SET 同上
ClosePreWindow ClassName, WM_LOOK 同上 ClosePreWindow ClassName, WM_RUN 同上
PreWnd=FindWindow(ClassName, WinCaption) 寻找类名为ClassName,标题为WinCaption的窗口 If Not (PreWnd = 0) Then Call SendMessage(PreWnd, WM_CLOSE, 0, 0) 如果窗口已找到则关闭它
Frm_Run.Caption=WM_LOOK 赋上具有相应运行方式的标题 LookScrWnd=Val(Right(Command$, Len(Command$) - 2)) 取得小屏幕的窗口句柄 Style=GetWindowLong(Frm_Run.hwnd, GWL_STYLE) 取得窗口的样式 Style=Style Or WS_CHILD 在窗口的样式中加入子窗体常数 SetWindowLong Frm_Run.hwnd, GWL_STYLE, Style 改变窗体的样式 SetParent Frm_Run.hwnd, LookScrWnd 设置窗体的父窗体 GetClientRect LookScrWnd, LookRect 取得小屏幕的大小
显示窗体并将窗体的大小设置为小屏幕的大小以便覆盖小屏幕 End Sub Public Sub Scr_Setup() Frm_Run.Caption=WM_SET 赋上具有相应运行方式的标题
Frm_Run.Caption = WM_RUN 赋上具有相应运行方式的标题 ShowCursor False 隐藏鼠标
ShowCursor True 显示鼠标 Unload Frm_Setup 卸载窗体关闭屏保 Unload Frm_Run 同上 End Sub Public Function Scan_RUN() As Boolean侦测当前屏保的运行方式 If (Frm_Run.Caption = WM_RUN) Then 如果屏保是以运行方式在运行则返回“真”,否则返回“假”
Dim i As Integer 定义循环变量 Dim OldX As Integer 定义存放旧的鼠标水平坐标 Dim OldY As Integer 定义存放旧的鼠标垂直坐标 Dim Pic(1) As New StdPicture 定义一个图片类的数组 Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) If Mod_Main.Scan_RUN Then 如果此时是在运行屏保则关闭屏保
i=1 为循环变量赋初值 OldX=-1 为旧鼠标水平坐标赋初值 OldY=-1 为旧鼠标垂直坐标赋初值 Set Pic(0)=LoadPicture(请写入图片一的路径和名称) 读取图片一 Set Pic(1)=LoadPicture(请写入图片二的路径和名称) 读取图片二
If Mod_Main.Scan_RUN Then 如果此时是在运行屏保则关闭屏保
Mod_Main.CloseSCR 将鼠标当前的水平坐标和垂直坐标与旧鼠标的水平坐标和垂直坐标相减其绝对值如果大于3个像素则退出屏保
Mod_Main.CloseSCR 关闭屏保
i=1 如果循环变量大于图片的数量则变量赋为1 Else i=i+1 否则循环变量加一
1).Width,vbHimetric,vbTwips),ScaleY(Pic(i-1).Height,vbHimetric,vbTwips)在Frm_Run上画图 End Sub
好了,一个标准的屏幕保护程序就编写好了。按下F5运行试试看。不要忘了生成EXE文件时一定要将屏保的扩展名改为SCR并将其拷贝到Windows的System目录里才可在屏保设置中见到喔!(程序在VB 6.0中编写并运行通过。) |