熟悉Windows操作系統(tǒng)的朋友一定對(duì)Windows的屏幕保護(hù)程序不陌生吧。如何自己編寫Windows屏幕保護(hù)程序呢?當(dāng)你看完下面的講解后便可以輕易地編寫一標(biāo)準(zhǔn)的Windows屏幕保護(hù)程序了!
10年積累的成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有景寧畬族自治免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
一個(gè)標(biāo)準(zhǔn)的屏保有以下幾個(gè)特點(diǎn):
一:它是以.SCR作為文件的擴(kuò)展名!
二:它有三種運(yùn)行方式。
(1)運(yùn)行在預(yù)覽框中(用于預(yù)覽屏保的效果。在“顯示屬性”→“屏幕保護(hù)程序”→“小屏幕”)。(見(jiàn)圖)
(2)運(yùn)行設(shè)置程序(用于設(shè)置一些相關(guān)的樣式。在“顯示屬性”→“屏幕保護(hù)程序”→“點(diǎn)擊設(shè)置按鈕”)。
(3)真正的運(yùn)行屏保(屏保運(yùn)行時(shí)的效果。在“顯示屬性”→“屏幕保護(hù)程序”→“點(diǎn)擊預(yù)覽”或鼠標(biāo)、鍵盤在指定的時(shí)間內(nèi)無(wú)動(dòng)作時(shí))。
如何讓屏保識(shí)別當(dāng)前需要運(yùn)行哪一種方式呢?答案很簡(jiǎn)單——分析Windows調(diào)用屏保的參數(shù)。下面以Windows 98為例向大家分析一下調(diào)用屏保的參數(shù)。
當(dāng)Windows需要屏保顯示在“小屏幕”中時(shí)會(huì)在調(diào)用屏保的后面加上兩個(gè)參數(shù)。
如:myscr.scr /p 7981(參數(shù)一:/p 表示讓程序顯示在“小屏幕”里,參數(shù)二:7981表示“小屏幕”的句柄hWnd。這樣屏保就會(huì)得知Windows要它顯示在“小屏幕”中。)
當(dāng)Windows需要屏保顯示設(shè)置對(duì)話框時(shí)會(huì)在調(diào)用屏保的后面不加或加上兩個(gè)參數(shù)。
如:myscr.scr或myscr.scr /C 7987(參數(shù)一:/C表示讓程序顯示設(shè)置對(duì)話框,參數(shù)二:7987表示該屬性頁(yè)的句柄。)
當(dāng)Windows需要運(yùn)行屏保時(shí)會(huì)在調(diào)用屏保的后面加上一個(gè)參數(shù)。
如:myscr.scr /S(參數(shù):/S表示讓屏保運(yùn)行。)
好了,知道了Windows如何讓屏保運(yùn)行的三種方式后,接下來(lái)就要討論如何實(shí)現(xiàn)它們了。
實(shí)現(xiàn)原理:Windows通過(guò)某種方式調(diào)用屏保,屏保知道了它此時(shí)要干什么便會(huì)在當(dāng)前環(huán)境中搜索是否有相同的實(shí)例存在。如果該實(shí)例的運(yùn)行方式與此次要啟動(dòng)的運(yùn)行方式不同則關(guān)閉前個(gè)實(shí)例,如果該實(shí)例的運(yùn)行方式與此次要啟動(dòng)的運(yùn)行方式相同則關(guān)閉此次運(yùn)行的實(shí)例。
顯然要實(shí)現(xiàn)這種方法靠VB的App.PrevInstance是不可行的。因?yàn)槲覀円_(dá)到的目的是:偵測(cè)到前一個(gè)實(shí)例后要關(guān)閉它然后啟動(dòng)程序。而App.PrevInstance屬性只能返回當(dāng)前是否已啟動(dòng)一個(gè)應(yīng)用程序的實(shí)例而不能對(duì)前個(gè)實(shí)例做些什么。(實(shí)例 簡(jiǎn)單地說(shuō)就是相同的對(duì)象集合——同一程序。)在實(shí)現(xiàn)此方法之前首先向大家介紹三條API函數(shù):GetClassName、FindWindow和SendMessage。其原型如下:
Declare Function GetClassName Lib “user32” Alias “GetClassNameA” (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Declare Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function SendMessage Lib “user32” Alias “SendMessageA” (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
GetClassName用于取得窗體的類名。調(diào)用成功后返回類名長(zhǎng)度,失敗返回零。函數(shù)需要三個(gè)參數(shù):參數(shù)一.窗體的句柄,參數(shù)二.存放類名的緩沖,參數(shù)三.緩沖的大小。
FindWindow用于尋找窗體。調(diào)用成功后返回窗體的句柄,失敗返回零。函數(shù)需要兩個(gè)參數(shù):參數(shù)一.窗體的類名,參數(shù)二.窗體的標(biāo)題。
SendMessage用于向窗體發(fā)送一消息。函數(shù)需要四個(gè)參數(shù):參數(shù)一.窗體的句柄,參數(shù)二:發(fā)送的消息名稱,參數(shù)三、四.分別表示消息所附帶的參數(shù)。
使用了這三個(gè)函數(shù)便可輕易地實(shí)現(xiàn)關(guān)閉前有一個(gè)已啟動(dòng)的實(shí)例從而達(dá)到我們的目的。
其次我們要實(shí)現(xiàn)如何讓屏幕保護(hù)程序顯示在預(yù)覽框中(“小屏幕”)。
要讓屏幕保護(hù)程序在預(yù)覽框中顯示必須動(dòng)態(tài)地改變窗口的樣式使之成為“小屏幕”的子窗體,這樣才能使預(yù)覽框關(guān)閉時(shí)得到關(guān)閉消息。動(dòng)態(tài)地改變窗口的樣式可以使用GetWindowLong、SetWindowLong和SetParent。
它們的原型如下:
Public Declare Function GetWindowLong Lib “user32” Alias “GetWindowLongA” (ByVal hwnd As Long, ByVal nIndex As Long) As Long Public Declare Function SetWindowLong Lib “user32” Alias “SetWindowLongA” (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Declare Function SetParent Lib “user32” (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
GetWindowLong的作用用于得到窗體的樣式。調(diào)用成功后返回窗體的樣式。函數(shù)需要兩個(gè)參數(shù):參數(shù)一.窗體的句柄,參數(shù)二.要取得窗體的樣式只需使用常數(shù)GWL_STYLE。
SetWindowLong的作用用于設(shè)置窗體的樣式。函數(shù)需要三個(gè)參數(shù):參數(shù)一.窗體的句柄,參數(shù)二.要設(shè)置窗體的樣式只需用常數(shù)GWL_STYLE,參數(shù)三.要設(shè)置窗體的樣式。
SetParent的作用用于設(shè)置子窗體屬于哪個(gè)父窗體。函數(shù)需要兩個(gè)參數(shù):參數(shù)一.子窗體的句柄,參數(shù)二.父窗體的句柄。
知道了以上兩點(diǎn)就可編寫出標(biāo)準(zhǔn)的屏保。(關(guān)于效果就看你自己的了?。┘埳险劚艘魂嚲鸵鋵?shí)到真正的編程上了。為了著重講解屏保的實(shí)現(xiàn)方法故將屏保的效果簡(jiǎn)單化。
首先新建一工程再添加一窗口,各屬性設(shè)置如下:
窗口 名稱 Caption BorderStyle
Form1 Frm_Setup 無(wú) 1 - None
Form2 Frm_Run 任意 1 - Fixed Single
其余屬性均缺省。再在Frm_Run中添加一Timer控件,將該控件的名稱改為Timer_Mov,Interval屬性制改為500。
添加兩個(gè)模塊,將Module1的名稱改為Mod_Const,Module2的名稱改為Mod_Main,添加以下代碼:
Mod_Const:
Option Explicit
Public Const WM_LOOK=“屏保預(yù)覽(demo)”
Public Const WM_SET=“屏保設(shè)置(demo)”
Public Const WM_RUN=“屏保運(yùn)行(demo)”
Public Const HWND_TOP=0&
Public Const WS_CHILD=&H40000000
Public Const GWL_STYLE=(-16)
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Public Const SWP_NOZORDER=&H4
Public Const SWP_NOACTIVATE=&H10
Public Const SWP_SHOWWINDOW=&H40
Public Const WM_CLOSE=&H10
Declare Function GetClientRect Lib “user32” (ByVal hwnd As Long, lpRect As RECT) As Long
Declare Function GetClassName Lib “user32” Alias “GetClassNameA” (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Declare Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function SendMessage Lib “user32” Alias “SendMessageA” (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Function SetParent Lib “user32” (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
Public Declare Function GetWindowLong Lib “user32” Alias “GetWindowLongA” (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib “user32” Alias “SetWindowLongA” (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function SetWindowPos Lib “user32” (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
Declare Function ShowCursor Lib “user32” (ByVal bShow As Long) As Long
Mod_Main:
Option Explicit
Sub Main() '程序運(yùn)行入口
Dim ClassName As String * 64 ’存放窗口的類名
Dim ExeCmd As String '存放命令行參數(shù)
GetClassName Frm_Setup.hwnd, ClassName, 64 ’取得窗口的類名
ExeCmd=UCase(Command$) ’將調(diào)用的屏保的參數(shù)轉(zhuǎn)換成大寫后存放在變量ExeCmd里
If Not (InStr(ExeCmd,“/P”)=0)Then ’檢查屏保的調(diào)用參數(shù)中是否有“/P”參數(shù)
If Not (FindWindow(ClassName, WM_LOOK)=0)Then End ’如果找到已有同一個(gè)運(yùn)行方式的實(shí)例存在則程序結(jié)束
ClosePreWindow ClassName, WM_SET ’關(guān)閉前面已啟動(dòng)的其他運(yùn)行方式的實(shí)例
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 ’同上
Scr_Run
Else
If Not (FindWindow(ClassName, WM_SET)=0) Then End
ClosePreWindow ClassName, WM_LOOK ’同上
ClosePreWindow ClassName, WM_RUN ’同上
Scr_Setup
End If
End Sub
Public Sub ClosePreWindow(ClassName As String, WinCaption As String)
Dim PreWnd As Long
PreWnd=FindWindow(ClassName, WinCaption) ’尋找類名為ClassName,標(biāo)題為WinCaption的窗口
If Not (PreWnd = 0) Then Call SendMessage(PreWnd, WM_CLOSE, 0, 0) ’如果窗口已找到則關(guān)閉它
End Sub
Public Sub SCR_Look()
Dim LookScrWnd As Long
Dim Style As Long
Dim LookRect As RECT
Frm_Run.Caption=WM_LOOK ’賦上具有相應(yīng)運(yùn)行方式的標(biāo)題
LookScrWnd=Val(Right(Command$, Len(Command$) - 2)) ’取得小屏幕的窗口句柄
Style=GetWindowLong(Frm_Run.hwnd, GWL_STYLE) ’取得窗口的樣式
Style=Style Or WS_CHILD ’在窗口的樣式中加入子窗體常數(shù)
SetWindowLong Frm_Run.hwnd, GWL_STYLE, Style ’改變窗體的樣式
SetParent Frm_Run.hwnd, LookScrWnd ’設(shè)置窗體的父窗體
GetClientRect LookScrWnd, LookRect ’取得小屏幕的大小
SetWindowPos Frm_Run.hwnd, HWND_TOP, 0, 0, LookRect.Right, LookRect.Bottom, SWP_
NOZORDER Or SWP_NOACTIVATE Or SWP_SHOWWINDOW
'顯示窗體并將窗體的大小設(shè)置為小屏幕的大小以便覆蓋小屏幕
End Sub
Public Sub Scr_Setup()
Frm_Run.Caption=WM_SET ’賦上具有相應(yīng)運(yùn)行方式的標(biāo)題
Frm_Setup.Show
End Sub
Public Sub Scr_Run()
Frm_Run.Caption = WM_RUN ’賦上具有相應(yīng)運(yùn)行方式的標(biāo)題
ShowCursor False ’隱藏鼠標(biāo)
Frm_Run.Move 0, 0, Screen.Width, Screen.Height
Frm_Run.Show
End Sub
Public Sub CloseSCR()
ShowCursor True ’顯示鼠標(biāo)
Unload Frm_Setup ’卸載窗體關(guān)閉屏保
Unload Frm_Run ’同上
End Sub
Public Function Scan_RUN() As Boolean’偵測(cè)當(dāng)前屏保的運(yùn)行方式
If (Frm_Run.Caption = WM_RUN) Then ’如果屏保是以運(yùn)行方式在運(yùn)行則返回“真”,否則返回“假”
Scan_RUN=True
Else
Scan_RUN=False
End If
End Function
Frm_Run:
Option Explicit
Dim i As Integer ’定義循環(huán)變量
Dim OldX As Integer ’定義存放舊的鼠標(biāo)水平坐標(biāo)
Dim OldY As Integer ’定義存放舊的鼠標(biāo)垂直坐標(biāo)
Dim Pic(1) As New StdPicture ’定義一個(gè)圖片類的數(shù)組
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If Mod_Main.Scan_RUN Then ’如果此時(shí)是在運(yùn)行屏保則關(guān)閉屏保
Mod_Main.CloseSCR
End If
End Sub
Private Sub Form_Load()
i=1 ’為循環(huán)變量賦初值
OldX=-1 ’為舊鼠標(biāo)水平坐標(biāo)賦初值
OldY=-1 ’為舊鼠標(biāo)垂直坐標(biāo)賦初值
Set Pic(0)=LoadPicture(請(qǐng)寫入圖片一的路徑和名稱) ’讀取圖片一
Set Pic(1)=LoadPicture(請(qǐng)寫入圖片二的路徑和名稱) ’讀取圖片二
End Sub
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y A
s Single)
If Mod_Main.Scan_RUN Then ’如果此時(shí)是在運(yùn)行屏保則關(guān)閉屏保
Mod_Main.CloseSCR
End If
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Mod_Main.Scan_RUN Then
If (OldX=-1) And (OldY=-1) Then
OldX=X
OldY=Y
Else
If (ScaleX(Abs(X-OldX),vbTwips,vbPixels)= 3) Then
Mod_Main.CloseSCR ’將鼠標(biāo)當(dāng)前的水平坐標(biāo)和垂直坐標(biāo)與舊鼠標(biāo)的水平坐標(biāo)和垂直坐標(biāo)相減其絕對(duì)值如果大于3個(gè)像素則退出屏保
End If
End If
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
Mod_Main.CloseSCR ’關(guān)閉屏保
End Sub
Private Sub Timer_Mov_Timer()
If (i=2) Then
i=1 ’如果循環(huán)變量大于圖片的數(shù)量則變量賦為1
Else
i=i+1 ’否則循環(huán)變量加一
End If
Frm_Run.PaintPicture Pic(i-1),0,0,Width,Height,0,0,ScaleX(Pic(i-1).Width,vbHimetric,vbTwips),ScaleY(Pic(i-1).Height,vbHimetric,vbTwips)’在Frm_Run上畫圖
End Sub
Frm_Setup:
Option Explicit
Private Sub Com_OK_Click()
Mod_Main.CloseSCR
End Sub
Private Sub Form_Unload(Cancel As Integer)
Mod_Main.CloseSCR
End Sub
好了,一個(gè)標(biāo)準(zhǔn)的屏幕保護(hù)程序就編寫好了。按下F5運(yùn)行試試看。不要忘了生成EXE文件時(shí)一定要將屏保的擴(kuò)展名改為SCR并將其拷貝到Windows的System目錄里才可在屏保設(shè)置中見(jiàn)到喔!(程序在VB 5.0中編寫并運(yùn)行通過(guò)。)
首先你得保證你的程序沒(méi)有錯(cuò)誤。是一個(gè)能夠脫離VB窗口運(yùn)行的可執(zhí)行文件。如果你程序都沒(méi)寫好,怎么能當(dāng)屏保?
先編成xxx.EXE程序,然后改成xxx.SCR后綴名,放到c:\windows\system32\文件夾下面,然后在windows的屏幕保護(hù)里面就可以看到你的那個(gè)文件了。你的怎么不行,我用系統(tǒng)的cmd.exe都能當(dāng)屏保。
系統(tǒng)就有這個(gè)屏保啊!~!
Option EXPlicit
Dim quitflag As Boolean '聲明終止程序標(biāo)志變量
Dim lleft
'聲明隱藏或顯示鼠標(biāo)的API函數(shù)
Private Declare Function ShowCursor Lib "user32"
(ByVal bShow As Long) As Long
'檢測(cè)鼠標(biāo)單擊或移動(dòng)
Private Sub Form_Click()
quitflag = True
End Sub
Private Sub Form_MouseMove(Button As Integer,Shift As Integer, X As Single, Y As Single)
Static xlast, ylast
Dim xnow As Single
Dim ynow As Single
xnow = X
ynow = Y
If xlast = 0 And ylast = 0 Then
xlast = xnow
ylast = ynow
Exit Sub
End If
If xnow xlast Or ynow ylast Then
quitflag = True
End If
End Sub
'檢測(cè)按鍵
Private Sub Form_KeyDown(KeyCode As Integer,Shift As Integer)
quitflag = True
End Sub
Private Sub Form_Load()
Dim X As Long
lleft = 0
'橫向滾動(dòng)文字的起始X坐標(biāo)
If App.PrevInstance = True Then
'用APP對(duì)象的PrevInstance屬性
Unload Me
'防止同時(shí)運(yùn)行屏幕保護(hù)程序的兩個(gè)實(shí)例
Exit Sub
End If
Select Case Ucase$(Left$(Command$, 2))
'裝載命令行參數(shù)
Case "/S" '在顯示器屬性對(duì)話框中單擊了
預(yù)覽按鈕或屏幕保護(hù)程序被系統(tǒng)正常調(diào)用。
Show
'全屏顯示Form1窗體
Randomize
'初始化隨機(jī)數(shù)生成器
X = ShowCursor(False)
'隱藏鼠標(biāo)
BackColor = VBBlack
Do
Timer2.Enabled = True
'啟動(dòng)Timer2 ,顯示屏幕保護(hù)滾動(dòng)文字
DoEvents
'轉(zhuǎn)讓控制權(quán),以便檢測(cè)鼠標(biāo)和按鍵行為
Loop Until quitflag = True
'運(yùn)行屏幕保護(hù)滾動(dòng)文字直至有鼠標(biāo)和按鍵行為
Timer2.Enabled = False
'終止?jié)L動(dòng)文字
Timer1.Enabled = True
'啟動(dòng)Timer1,退出屏幕保護(hù)程序
Case Else
Unload Me
Exit Sub
End Select
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim X
X = ShowCursor(True)
'顯示鼠標(biāo)
End Sub
Private Sub Timer1_Timer()
Unload Me
'退出屏幕保護(hù)程序
End Sub
Private Sub Timer2_Timer()
顯示橫向滾動(dòng)文字
lleft = lleft + 100
If lleft = 11810 Then
lleft = 0
Lab1.Top = Int(Rnd * 7000)
End If
Lab1.Left = lleft
Timer2.Enabled = False
End Sub