前一段看Acer笔记本的广告,看到笔记本全屏了一个音乐的波形图。脑子里闪过了一个念头,用音乐做屏保加上音乐波谱的屏幕效果应该很不错,作为程序员,往往脑子里想的是:如果要我写这个东西要怎样怎样做。于是就有了我今天要谈论的话题。
从网上查找了一下关于如何做屏保程序的资料,不是很多,好多都是写好的软件。代码级别的就找到一个微软的,不过Microsoft还不错,把思想讲清楚了,最让人感动的是居然有全部的代码。链接如下:http://support.microsoft.com/kb/818359/zh-cn
参照上面的文章,还要搞清楚windows是怎么设定和启动屏保程序的。桌面上右击,在弹出菜单中选择“属性”,出现“显示属性”窗口,选择“屏幕保护程序”页,有一个选择屏保程序的下拉框,其选项对应系统盘\WINDOWS\system32下以scr为后缀名的文件(应用程序)。你选择了某个选项作为屏保后,系统的Timer就会计时,满足启动屏保的条件时,被选择的屏保程序就启动运行,启动后它会做一些动作,比如全屏,在所有窗口前,黑底,显示字或者图形并运动起来。所有的屏保共通点是:必须在点击或移动鼠标,按下键盘上的任意键时结束,这个时候屏保程序的任务就完成了。如果你在先前设置屏保时,在“密码保护”前的复选框上打上钩,那么此时程序将回到系统的欢迎界面让你输入密码,我想这不是屏保的工作,而是由Timer来做的,在屏保程序结束的地方进行判断是否需要做密码保护。上面都是我查阅资料加上我自己的理解,搞不好Windows就是这么做的,呵呵。
按照上面的理解,还需要可行性分析。自己写一个程序,以scr为后缀名,把他放到系统盘\WINDOWS\system32下,然后在刚才那个屏保的下拉框里选择我们自己的屏保可行吗?能用吗?事实证明还真的可以,可行性分析OK了。
分析上面链接里的资料,先读懂它的代码先。示例代码有一个对话框窗体(设置滚动文字内容),一个屏保窗体和一个Module。从程序代码中我们可以学到不少东西。①程序入口Sub Main在Module中,从这里我们可以了解到原来设置屏保程序时,在“屏幕保护程序”属性页点击设定时windows向屏保程序传递的第一个启动参数包含"/c",而预览和实绩运行时,windows向屏保程序传递的第一个启动参数包含"/s"。②对话框窗体frmcnfg和屏保窗体frmscr分别提供了如何写入系统注册表和读取注册表的方法。③PrevInstance()函数提供了如何防止一个程序被启动多个的方法④屏保窗体frmscr类中提供了关闭和打开Windows的CTRL+ALT+DEL 和 ALT+TAB组合键的方法(使用了API函数)。⑤对于移动鼠标时程序结束的处理。如果要自己写程序,可能会在这个地方遇到问题,如果在MouseMove事件中只有me.close(),那么屏保程序总是闪一下就停了。参照上面的资料我们就能知道原因了,因为窗体启动之后有个初始化鼠标位置的动作,其动作应该是一格一格的(我根据代码猜的),所以我们看到微软提供的方法是移动鼠标的幅度大于3才结束程序。⑥美中不足的是这个程序没有响应鼠标MouseDown事件,自己加上就行了。
还是把完整的代码贴在下面,方便查阅,再次声明是转自以下链接: http://support.microsoft.com/kb/818359/zh-cn1Imports Microsoft.Win32
2Imports Microsoft.VisualBasic
3Imports System.Math
4Public Class frmscrClass frmscr
5 Inherits System.Windows.Forms.Form
6
7Windows Form Designer generated code#Region " Windows Form Designer generated code "
8
9 Public Sub New()Sub New()
10 MyBase.New()
11
12 'The Windows Form Designer requires this call.
13 InitializeComponent()
14
15 'Add any initialization after the InitializeComponent() call.
16
17 End Sub
18
19 'Form overrides dispose to clean up the component list.
20 Protected Overloads Overrides Sub Dispose()Sub Dispose(ByVal disposing As Boolean)
21 If disposing Then
22 If Not (components Is Nothing) Then
23 components.Dispose()
24 End If
25 End If
26 MyBase.Dispose(disposing)
27 End Sub
28
29 'Required by the Windows Form Designer.
30 Private components As System.ComponentModel.IContainer
31
32 'NOTE: The Windows Form Designer requires the following procedure.
33 'It can be modified by using the Windows Form Designer.
34 'Do not modify the procedure by using the Code editor.
35 Friend WithEvents lblMessage As System.Windows.Forms.Label
36 Friend WithEvents Timer1 As System.Windows.Forms.Timer
37 <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()Sub InitializeComponent()
38 Me.components = New System.ComponentModel.Container
39 Me.lblMessage = New System.Windows.Forms.Label
40 Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
41 Me.SuspendLayout()
42 '
43 'lblMessage
44 '
45 Me.lblMessage.AutoSize = True
46 Me.lblMessage.BackColor = System.Drawing.Color.Black
47 Me.lblMessage.ForeColor = System.Drawing.Color.Yellow
48 Me.lblMessage.Location = New System.Drawing.Point(72, 118)
49 Me.lblMessage.Name = "lblMessage"
50 Me.lblMessage.Size = New System.Drawing.Size(193, 36)
51 Me.lblMessage.TabIndex = 1
52 Me.lblMessage.Text = "screen saver"
53 Me.lblMessage.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
54 '
55 'Timer1
56 '
57 Me.Timer1.Enabled = True
58 '
59 'frmscr
60 '
61 Me.AutoScaleBaseSize = New System.Drawing.Size(15, 33)
62 Me.BackColor = System.Drawing.Color.Black
63 Me.ClientSize = New System.Drawing.Size(292, 273)
64 Me.ControlBox = False
65 Me.Controls.Add(Me.lblMessage)
66 Me.Font = New System.Drawing.Font("Microsoft Sans Serif", 21.75!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
67 Me.MaximizeBox = False
68 Me.MinimizeBox = False
69 Me.Name = "frmscr"
70 Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
71 Me.TopMost = True
72 Me.WindowState = System.Windows.Forms.FormWindowState.Maximized
73 Me.ResumeLayout(False)
74
75 End Sub
76
77#End Region
78
79 Private Sub frmscr_Load()Sub frmscr_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
80
81 Dim tmpLng As Integer
82 tmpLng = SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1&, 0&, 0&)
83
84 'Get the user's previous preference for the marquee message.
85
86 Dim pRegKey As RegistryKey = Registry.CurrentUser
87 pRegKey = pRegKey.OpenSubKey("Software\\Test Screen Saver")
88 Dim val As Object = pRegKey.GetValue("Message")
89 pRegKey.Close()
90 lblMessage.Text = val.ToString
91
92 'Make the cursor disappear.
93
94 Me.Cursor.Current.Hide()
95 End Sub
96
97 Private Sub frmscr_KeyDown()Sub frmscr_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
98 'Immediately end when any key is pressed.
99 Me.Close()
100 End Sub
101
102 Private Sub frmscr_Activated()Sub frmscr_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated
103 'Center the lblMessage label to the form.
104 lblMessage.Left = GetScaleWidth(Me)
105 lblMessage.Top = (GetScaleWidth(Me) - lblMessage.Height) / 3
106 End Sub
107
108 Private Sub frmscr_Closing()Sub frmscr_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
109 'System.Windows.Forms.Cursor.Current.Show
110 ''Restore the mouse cursor.
111 Dim tmplng As Integer
112 Me.Cursor.Current.Show()
113
114 tmplng = SystemParametersInfo(SPI_SCREENSAVERRUNNING, 0&, 0&, 0&)
115 End Sub
116
117 Private Sub Timer1_Tick()Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
118 'Determine whether the Message has moved completely off the left side of the screen.
119 If lblMessage.Left < (0 - lblMessage.Width) Then
120 lblMessage.Left = GetScaleWidth(Me) 'ScaleWidth
121 End If
122
123 'Moves lblMessage to the left.
124 lblMessage.Left = lblMessage.Left - 10
125
126
127 End Sub
128
129 Private Sub frmscr_MouseMove()Sub frmscr_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
130
131 Static OldX As Integer
132 Static OldY As Integer
133
134 'Determines whether the mouse was moved and whether the movement was large.
135 'if so, the screen saver is ended.
136 If (OldX > 0 And OldY > 0) And (Abs(e.X - OldX) > 3 Or Abs(e.Y - OldY) > 3) Then
137 Me.Close()
138
139 End If
140
141 'Assigns the current X and Y locations to OldX and OldY.
142 OldX = e.X
143 OldY = e.Y
144
145 End Sub
146End Class
1Imports Microsoft.Win32
2Public Class frmcnfgClass frmcnfg
3 Inherits System.Windows.Forms.Form
4
5Windows Form Designer generated code#Region " Windows Form Designer generated code "
6
7 Public Sub New()Sub New()
8 MyBase.New()
9
10 'The Windows Form Designer requires this call.
11 InitializeComponent()
12
13 'Add any initialization after the InitializeComponent() call.
14
15 End Sub
16
17 'Form overrides dispose to clean up the component list.
18 Protected Overloads Overrides Sub Dispose()Sub Dispose(ByVal disposing As Boolean)
19 If disposing Then
20 If Not (components Is Nothing) Then
21 components.Dispose()
22 End If
23 End If
24 MyBase.Dispose(disposing)
25 End Sub
26
27 'Required by the Windows Form Designer.
28 Private components As System.ComponentModel.IContainer
29
30 'NOTE: The Windows Form Designer requires the following procedure.
31 'It can be modified by using the Windows Form Designer.
32 'Do not modify the procedure by using the Code editor.
33 Friend WithEvents txtmessage As System.Windows.Forms.TextBox
34 Friend WithEvents cmdcancel As System.Windows.Forms.Button
35 Friend WithEvents cmdOk As System.Windows.Forms.Button
36 Friend WithEvents label1 As System.Windows.Forms.Label
37 <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()Sub InitializeComponent()
38 Me.cmdOk = New System.Windows.Forms.Button
39 Me.cmdcancel = New System.Windows.Forms.Button
40 Me.label1 = New System.Windows.Forms.Label
41 Me.txtmessage = New System.Windows.Forms.TextBox
42 Me.SuspendLayout()
43 '
44 'cmdOk
45 '
46 Me.cmdOk.Location = New System.Drawing.Point(200, 184)
47 Me.cmdOk.Name = "cmdOk"
48 Me.cmdOk.Size = New System.Drawing.Size(56, 24)
49 Me.cmdOk.TabIndex = 0
50 Me.cmdOk.Text = "&OK"
51 '
52 'cmdcancel
53 '
54 Me.cmdcancel.Location = New System.Drawing.Point(272, 184)
55 Me.cmdcancel.Name = "cmdcancel"
56 Me.cmdcancel.Size = New System.Drawing.Size(56, 24)
57 Me.cmdcancel.TabIndex = 1
58 Me.cmdcancel.Text = "&Cancel"
59 '
60 'label1
61 '
62 Me.label1.Location = New System.Drawing.Point(24, 40)
63 Me.label1.Name = "label1"
64 Me.label1.Size = New System.Drawing.Size(152, 24)
65 Me.label1.TabIndex = 2
66 Me.label1.Text = "Enter Message"
67 '
68 'txtmessage
69 '
70 Me.txtmessage.Location = New System.Drawing.Point(32, 64)
71 Me.txtmessage.Multiline = True
72 Me.txtmessage.Name = "txtmessage"
73 Me.txtmessage.Size = New System.Drawing.Size(296, 96)
74 Me.txtmessage.TabIndex = 3
75 Me.txtmessage.Text = ""
76 '
77 'frmcnfg
78 '
79 Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
80 Me.ClientSize = New System.Drawing.Size(344, 221)
81 Me.Controls.Add(Me.txtmessage)
82 Me.Controls.Add(Me.label1)
83 Me.Controls.Add(Me.cmdcancel)
84 Me.Controls.Add(Me.cmdOk)
85 Me.Name = "frmcnfg"
86 Me.Text = "CONFIGURATION"
87 Me.ResumeLayout(False)
88
89 End Sub
90
91#End Region
92
93
94 Private Sub cmdcancel_Click()Sub cmdcancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdcancel.Click
95 Me.Close()
96 End Sub
97
98 Private Sub cmdOk_Click()Sub cmdOk_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOk.Click
99 'Save the current settings to
100 'HKEY_CURRENT_USER\Software\
101 'in the registry.
102
103
104 Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey("Software", True)
105 Dim newkey As RegistryKey = key.CreateSubKey("Test Screen Saver")
106 newkey.SetValue("Message", txtmessage.Text)
107 newkey.Close()
108 Me.Close()
109 End Sub
110End Class
1Imports System.Runtime.InteropServices
2Imports System.Environment
3
4Module Module1Module Module1
5
6 Public Declare Auto Function SystemParametersInfo()Function SystemParametersInfo Lib "user32" (ByVal uAction As Integer, ByVal uParam As Integer, ByRef pvParam As Integer, ByVal fuWinIni As Integer) As Boolean
7 Public Const SPI_SCREENSAVERRUNNING = 97&
8 Public Const frmedge As Integer = 4
9 Public nMouseMoves&
10 Dim sStartType
11
12
13 Public Sub Main()Sub Main(ByVal args As String())
14 Dim Inst As Boolean = False
15
16
17 If args.Length > 0 Then
18 sStartType = args(0).ToLower.Trim().Substring(0, 2)
19
20 If sStartType = "" Then
21 'This will occur when a user right-clicks the .SCR
22 'file and chooses "configure"
23 sStartType = "/c"
24 End If
25
26 ' Determine whether the screen saver should show user-definable options.
27 If sStartType = "/c" Then
28 Dim usercnfg As New frmcnfg
29 usercnfg.ShowDialog()
30
31 ' Exit the application.
32 Exit Sub
33 End If
34
35 ' Determine whether the screen saver should just execute.
36 If sStartType = "/s" Then
37 'Check for previous instance.
38 Inst = PrevInstance()
39 If Not (Inst) Then
40 ' Create a Screen Saver form and display the form.
41 Dim scrsvr As New frmscr
42 scrsvr.ShowDialog()
43 Else
44 'If a previous instance exists, exit the application.
45 Exit Sub
46 End If
47 End If
48 End If
49 End Sub
50
51
52 Function PrevInstance()Function PrevInstance() As Boolean
53 If UBound(Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)) > 0 Then
54 Return True
55 Else
56 Return False
57 End If
58 End Function
59 Public Function GetScaleWidth()Function GetScaleWidth(ByVal frm As Form) As Integer
60
61 Dim ctl As Control
62 Dim w As Integer = frm.ClientSize.Width
63
64 For Each ctl In frm.Controls
65 With ctl
66 If .GetContainerControl() Is frm Then
67 If .Dock = DockStyle.Left Or .Dock = DockStyle.Right Then
68 w = w - .Size.Width
69 End If
70 End If
71 End With
72 Next
73 GetScaleWidth = w - frmedge
74 End Function
75
76
77
78End Module
上面的东西就是屏保程序的基本框架了,窗体启动之后就是我们可以DIY的部分了,可以加个Timer做一些移动文字,图形的动作,这些都是数学的算法游戏,我们可以充分发挥自己的想象力,还可以操作音频放音乐,系统的资源应该都是可以用的。大家一起DIY吧。