为了实现如下的功能:表或查询每相邻两行字段相减。例如下面的这张表或查询,结果是成绩列的每两行相减。
姓名 学号 成绩
小王 001 240
大王 002 260
小王 001 280
大王 002 290
大王 002 260
思路如下:
1、先把表另存一份表1,加一个自增长的ID。
2、表1再另存一份表2。
3、表1和表2用“表1的ID=表2ID-1”来连接,就是相邻两行连接起来。
4、将上面的连接表成绩字段相减,再另存一份。
5、删除表1和表2.
为了实现如下的功能:表或查询每相邻两行字段相减。例如下面的这张表或查询,结果是成绩列的每两行相减。
姓名 学号 成绩
小王 001 240
大王 002 260
小王 001 280
大王 002 290
大王 002 260
思路如下:
1、先把表另存一份表1,加一个自增长的ID。
2、表1再另存一份表2。
3、表1和表2用“表1的ID=表2ID-1”来连接,就是相邻两行连接起来。
4、将上面的连接表成绩字段相减,再另存一份。
5、删除表1和表2.
为了实现如下的功能:表或查询每相邻两行字段相减。例如下面的这张表或查询,结果是成绩列的每两行相减。
姓名 学号 成绩
小王 001 240
大王 002 260
小王 001 280
大王 002 290
大王 002 260
思路如下:
1、先把表另存一份表1,加一个自增长的ID。
2、表1再另存一份表2。
3、表1和表2用“表1的ID=表2ID-1”来连接,就是相邻两行连接起来。
4、将上面的连接表成绩字段相减,再另存一份。
5、删除表1和表2.
最近使用EXCEL处理数据,总是会用到2张表数据的查找匹配的功能,EXCEL提供了强大的Vlookup函数能很好的实现我需要的功能。但是函数在用起来有点麻烦,尤其是在2张表之间切换时很容易会点错参数,而且敲击代码对非程序员很不友好,于是就想找一个VBA窗体实现Vlookup的模板。可是在网上找了好久都没能找到,只能自己动手做一个出来了。
这个VBA实例很简单,也就是把Vlookup进行了改写,提供了用户输入界面的窗体。
先来看下Vlookup函数:VLOOKUP(lookup_value,table_array,col_index_num,range_lookup)
翻译过来就是VLOOKUP(查找关键字,查找的范围,返回列,模糊匹配),需要把这些参数设置为变量,让用户输入即可。
1、 在EXCEL表1中添加一个按钮
2、点击按钮,显示VlookupForm输入窗口
3、输入数据(只需要输入第几列)就可以实现vlookup的功能了
下面简单介绍下代码。模块里面就是按钮单击事件,调用/显示VlookupForm窗口。
Sub VlookupSub() VlookupForm.ShowEnd Sub
VlookupForm窗体的代码主要还是使用vlookup函数把输入的数据进行处理。
Private Sub CommandOK_Click()Dim RowStartDim RowEndDim ppRowStart = Val(TextStart.Text)RowEnd = Val(TextEnd.Text)For m = RowStart To RowEnd pp = Application.VLookup(Cells(m, Val(TextKeyword.Text)), Sheets(TextSheet.Text).Range("a:z"), Val(TextReturn.Text), 0) If Not Application.IsNA(pp) Then Sheets("Sheet1").Cells(m, Val(TextInsert.Text)) = pp Else '查找不到匹配项,置为0,vlookup默认为N/A Sheets("Sheet1").Cells(m, Val(TextInsert.Text)) = 0 End IfNext m End SubPrivate Sub HideButton_Click() VlookupForm.HideEnd Sub
整个的实例下载地址:使用VBA实现Vlookup实例.rar
最近使用EXCEL处理数据,总是会用到2张表数据的查找匹配的功能,EXCEL提供了强大的Vlookup函数能很好的实现我需要的功能。但是函数在用起来有点麻烦,尤其是在2张表之间切换时很容易会点错参数,而且敲击代码对非程序员很不友好,于是就想找一个VBA窗体实现Vlookup的模板。可是在网上找了好久都没能找到,只能自己动手做一个出来了。
这个VBA实例很简单,也就是把Vlookup进行了改写,提供了用户输入界面的窗体。
先来看下Vlookup函数:VLOOKUP(lookup_value,table_array,col_index_num,range_lookup)
翻译过来就是VLOOKUP(查找关键字,查找的范围,返回列,模糊匹配),需要把这些参数设置为变量,让用户输入即可。
1、 在EXCEL表1中添加一个按钮
2、点击按钮,显示VlookupForm输入窗口
3、输入数据(只需要输入第几列)就可以实现vlookup的功能了
下面简单介绍下代码。模块里面就是按钮单击事件,调用/显示VlookupForm窗口。
Sub VlookupSub() VlookupForm.ShowEnd Sub
VlookupForm窗体的代码主要还是使用vlookup函数把输入的数据进行处理。
Private Sub CommandOK_Click()Dim RowStartDim RowEndDim ppRowStart = Val(TextStart.Text)RowEnd = Val(TextEnd.Text)For m = RowStart To RowEnd pp = Application.VLookup(Cells(m, Val(TextKeyword.Text)), Sheets(TextSheet.Text).Range("a:z"), Val(TextReturn.Text), 0) If Not Application.IsNA(pp) Then Sheets("Sheet1").Cells(m, Val(TextInsert.Text)) = pp Else '查找不到匹配项,置为0,vlookup默认为N/A Sheets("Sheet1").Cells(m, Val(TextInsert.Text)) = 0 End IfNext m End SubPrivate Sub HideButton_Click() VlookupForm.HideEnd Sub
整个的实例下载地址:使用VBA实现Vlookup实例.rar
FileName = App.Path + "\CONFIG"
'如果文件不存在,则创建文件
If Dir(FileName) = "" Then
Open FileName For Output As #1 '打开顺序文件,我们可以使用Open语句
a = Encode("123") + vbCrLf + "10" + vbCrLf 'vbCrLf为回车
Print #1, a '写数据
Close #1 '关闭文件
End If
SetAttr FileName, vbSystem Or vbHidden '隐藏文件
Open FileName For Binary As #99
Close #99 '关闭文件
最近在写的一个小程序中有个配置文件,这个文件对整个程序来说是至关重要的,如果它被删除或者改写的话,整个程序无法运行,或者运行后无法关闭。所以我一直在寻找如果让手工无法改写文件的方法。
对于“删除”来说是很容易解决的,程序中查找配置文件的路径,若为空则创建,并给些默认值。VB的示例代码如下:
FileName = App.Path + "\CONFIG"'如果文件不存在,则创建文件If Dir(FileName) = "" Then Open FileName For Output As #1 '打开顺序文件,我们可以使用Open语句 a = Encode("123") + vbCrLf + "10" + vbCrLf 'vbCrLf为回车 Print #1, a '写数据 Close #1 '关闭文件 End If
对于手工改写配置文件,我一直无能为力,我试图在程序中把该文件隐藏掉。VB的示例代码如下:
SetAttr FileName, vbSystem Or vbHidden '隐藏文件
但终归来说是治标不治本,文件仍然会被改写的。然后我想到修改配置文件后缀法,让人手工没那么容易打开文件,但是总是有方法打开的。最终让我想到一个简单的解决方法是,在程序中先打开配置文件,之后手工就无法打开了。VB的示例代码如下:
Open FileName For Binary As #99
只是记得程序在改写该文件时要先关闭打开的文件,不然改写会失败的。VB的示例代码如下:
Close #99 '关闭文件
总结一下,防止文件被改写的简单实现方式就是在程序中先打开该文件。完整的程序示例可参考这里。
'计算空闲时间
Private 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
Private Declare Function EnableWindow Lib "user32" (ByVal hWnd As Integer, ByVal aBOOL As Integer) As Integer
Private Declare Function IsWindowEnabled Lib "user32" (ByVal hWnd As Integer) As Integer
Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Integer) As Integer
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, ByVal lpvParam As Any, ByVal fuWinIni As Long) As Long
'常量声明
Const SWP_NOMOVE = &H2 '保持当前位置(x和y设定将被忽略)
Const SWP_NOSIZE = &H1 '保持当前大小(cx和cy会被忽略)
Const HWND_TOPMOST = -1
Const HWND_NOTOPMOST = -2
Const flags = SWP_NOMOVE Or SWP_NOSIZE
'使用GetLastInputInfo来检测键盘、鼠标无动作
Private Declare Function GetLastInputInfo Lib "user32" (plii As LASTINPUTINFO) As Boolean
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Type LASTINPUTINFO
cbSize As Long
dwTime As Long
End Type
Private Sub Form_Load()
If App.PrevInstance = True Then
'用APP对象的PrevInstance属性,防止同时运行屏幕保护程序的两个实例
Unload Me
Exit Sub
End If
Timer1.Interval = 1000
'读取配置信息
Call GetConfig
'打开配置文件,防止手工修改
FileName = App.Path + "\CONFIG"
Open FileName For Binary As #99
End Sub
Private Sub BntOk_Click()
If (Text1.Text = password) Then
' 卸载钩子
UnhookWindowsHookEx lHook
Timer1.Enabled = True
Me.Visible = False
Text1.Text = ""
Timer2.Enabled = False
Else
Label2.Visible = True
Label2.Caption = "输入密码不正确,请重新输入!"
Text1.Text = ""
Text1.SetFocus
End If
End Sub
Private Sub BntEmpty_Click()
Text1.Text = ""
End Sub
'显示主程序界面
Private Sub ShowForm()
' 安装钩子
lHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf CallKeyHookProc, App.hInstance, 0)
'如果更改的背景文件不存在,或者文件目录为空,则显示默认背景
If (filedir <> "" And Dir(filedir) <> "") Then
'开始的时候使用的是改变窗口的默认背景,这样的话这个背景不会被拉伸,只能保持默认大小,舍弃 Me.Picture = LoadPicture(filedir)
'现在使用image控件来实现
Image1.Width = Screen.Width
Image1.Height = Screen.Height
'这里把窗口设为全屏,因为image 要随着窗口变化
Top = 0
Left = 0
Me.Width = Screen.Width
Me.Height = Screen.Height
Me.Image1.Visible = False
Me.Image1.Picture = LoadPicture(filedir)
Me.AutoRedraw = True
Me.PaintPicture Image1.Picture, 0, 0, Me.ScaleWidth, Me.ScaleHeight
End If
Me.Show 'setFocus前面须有这个
'设置窗口在最上面
Dim Ok
Ok = SetWindowPos(Me.hWnd, HWND_TOPMOST, 0, 0, 0, 0, flags)
'设置全屏
Top = 0
Left = 0
Me.Width = Screen.Width
Me.Height = Screen.Height
'设置输入框的位置
Frame1.Top = Screen.Height - Frame1.Height
Frame1.Left = Screen.Width - Frame1.Width
Label2.Left = Frame1.Left
Label2.Top = Frame1.Top - Label2.Height
Label2.Width = Frame1.Width
Label2.Visible = False
Text1.SetFocus
'禁用alt+ctrl+delete
'Open Environ$("WinDir") & "\system32\taskmgr.exe" For Binary As #1
Timer1.Enabled = False
Timer2.Enabled = True
Text1.SetFocus
End Sub
'设置窗口
Private Sub BntSet_Click()
If (Text1.Text = password) Then
' 卸载钩子
UnhookWindowsHookEx lHook
Me.Visible = False
Text1.Text = ""
setform.Show
Timer1.Enabled = True
Else
Label2.Visible = True
Label2.Caption = "输入密码不正确,请重新输入!"
Text1.Text = ""
Text1.SetFocus
End If
End Sub
'回车之后的动作
Private Sub Text1_KeyPress(KeyAscii As Integer)
' Text1 响应回车键
If KeyAscii = 13 Then
If (Text1.Text = password) Then
' 卸载钩子
UnhookWindowsHookEx lHook
Me.Visible = False
Text1.Text = ""
Timer1.Enabled = True
Timer2.Enabled = False
Else
Label2.Visible = True
Label2.Caption = "输入密码不正确,请重新输入!"
Text1.Text = ""
Text1.SetFocus
End If
End If
End Sub
'当空闲时间大于IntervalTime时,调用ShowForm
Private Sub Timer1_Timer()
Dim lii As LASTINPUTINFO
lii.cbSize = Len(lii)
If GetLastInputInfo(lii) Then
If (GetTickCount - lii.dwTime)/60000 > IntervalTime Then
Call ShowForm
End If
End If
End Sub
'禁用任务管理器
Private Sub Timer2_Timer()
Shell ("cmd /c taskkill /f /im taskmgr.exe"), vbHide
End Sub
Dim change As Boolean
Private Sub Command1_Click()
'先读出密码
passwordstr = password
FileName = App.Path + "\CONFIG" '配置文件路径
'验证密码
If Text1.Text = passwordstr And Text3.Text = Text2.Text Then
NewPassword = Encode(Text2.Text)
change = SetConfig(NewPassword, 0)
'设置以后重新读取配置文件
Call GetConfig
If (change = True) Then MsgBox "口令修改成功"
Else
If Text2.Text <> Text3.Text Then
MsgBox "两次口令输入不一致,请重新输入"
Else
MsgBox "旧口令错,请重新输入"
End If
End If
End Sub
Private Sub Command2_Click()
Unload Me
End Sub
Private Sub Command3_Click()
Set w = CreateObject("wscript.shell")
w.regwrite "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\" & App.EXEName, App.Path & "\" & App.EXEName & ".exe"
MsgBox "已经设置为开机自启动"
End Sub
Private Sub Command4_Click()
Set w = CreateObject("wscript.shell")
w.regdelete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\" & App.EXEName
MsgBox "已经取消开机自启动"
End Sub
Private Sub Command5_Click()
CommonDialog1.Filter = "jpg|*.jpg"
CommonDialog1.ShowOpen
filedir = CommonDialog1.FileName
If (filedir <> "") Then change = True
change = SetConfig(filedir, 2)
'设置以后重新读取配置文件
Call GetConfig
If (change = True) Then MsgBox "背景替换成功"
End Sub
Private Sub Command6_Click()
change = SetConfig("", 2)
'设置以后重新读取配置文件
Call GetConfig
If (change = True) Then MsgBox "已恢复为默认背景"
End Sub
Private Sub Command7_Click()
Unload Me
End Sub
Private Sub IntervalBnt_Click()
change = SetConfig(setform.IntervalTxt.Text, 1)
'设置以后重新读取配置文件
Call GetConfig
If (change = True) Then MsgBox "修改成功"
End Sub
Option Explicit
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public Const HC_ACTION = 0
Public Const WM_KEYDOWN = &H100
Public Const WM_KEYUP = &H101
Public Const WM_SYSKEYDOWN = &H104
Public Const WM_SYSKEYUP = &H105
Public Const VK_TAB = &H9
Public Const VK_CONTROL = &H11
Public Const VK_ESCAPE = &H1B
Public Const VK_DELETE = &H2E
Public Const WH_KEYBOARD_LL = 13
Public Const LLKHF_ALTDOWN = &H20
'禁用键盘的功能键
Public Type KBDLLHOOKSTRUCT
vkCode As Long
scanCode As Long
flags As Long
time As Long
dwExtraInfo As Long
End Type
Public lHook As Long
Dim p As KBDLLHOOKSTRUCT
Dim key() As Byte
'全局变量
Public password As String
Public IntervalTime As Integer
Public filedir As String
Public FileName As String
'键盘钩子
Public Function CallKeyHookProc(ByVal ncode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim fEatKeystroke As Boolean
If (ncode = HC_ACTION) Then
If wParam = WM_KEYDOWN Or wParam = WM_SYSKEYDOWN Or wParam = WM_KEYUP Or wParam = WM_SYSKEYUP Then
CopyMemory p, ByVal lParam, Len(p)
fEatKeystroke = _
((p.vkCode = VK_TAB) And ((p.flags And LLKHF_ALTDOWN) <> 0)) Or _
((p.vkCode = VK_ESCAPE) And ((p.flags And LLKHF_ALTDOWN) <> 0)) Or _
((p.flags And LLKHF_ALTDOWN) <> 0) Or _
((p.vkCode = VK_ESCAPE) And ((GetKeyState(VK_CONTROL) And &H8000) <> 0)) Or _
((p.vkCode = 91) Or (p.vkCode = VK_ESCAPE) Or (p.vkCode = 92) Or (p.vkCode = 93))
'判断是否按下了:TAB+ALT、Esc+ALT、Alt(Alt+F4)、Esc+Ctrl、左右 Win 和徽标键\Esc
End If
End If
If fEatKeystroke Then
' 设置为 1 可以屏蔽按键
CallKeyHookProc = 1
Else
CallKeyHookProc = CallNextHookEx(0, ncode, wParam, ByVal lParam)
End If
End Function
Sub initkey() '这里为密匙,建议定义的复杂些,我这里仅仅是个示例
ReDim key(9)
key(0) = 12
key(1) = 43
key(2) = 53
key(3) = 67
key(4) = 78
key(5) = 82
key(6) = 91
key(7) = 245
key(8) = 218
key(9) = 190
End Sub
Function Encode(ByVal s As String) As String '加密
On Error GoTo myerr
initkey
Dim buff() As Byte
buff = StrConv(s, vbFromUnicode)
Dim i As Long, j As Long
Dim k As Long
k = UBound(key) + 1
For i = 0 To UBound(buff)
j = i Mod k
buff(i) = buff(i) Xor key(j)
Next
Dim mstr As String
mstr = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim outstr As String
Dim temps As String
For i = 0 To UBound(buff)
k = buff(i) \ Len(mstr)
j = buff(i) Mod Len(mstr)
temps = Mid(mstr, j + 1, 1) + Mid(mstr, k + 1, 1)
outstr = outstr + temps
Next
Encode = outstr
Exit Function
myerr:
Encode = ""
End Function
Function Decode(ByVal s As String) As String '解密
On Error GoTo myerr
initkey
Dim i As Long, j As Long
Dim k As Long, n As Long
Dim mstr As String
mstr = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim outstr As String
Dim temps As String
If Len(s) Mod 2 = 1 Then
Decode = ""
Exit Function
End If
Dim t1 As String
Dim t2 As String
Dim buff() As Byte
Dim m As Long
m = 0
For i = 1 To Len(s) Step 2
t1 = Mid(s, i, 1)
t2 = Mid(s, i + 1, 1)
j = InStr(1, mstr, t1)
k = InStr(1, mstr, t2)
n = j - 1 + (k - 1) * Len(mstr)
ReDim Preserve buff(m)
buff(m) = n
m = m + 1
Next
k = UBound(key) + 1
For i = 0 To UBound(buff)
j = i Mod k
buff(i) = buff(i) Xor key(j)
Next
Decode = StrConv(buff, vbUnicode)
Exit Function
myerr:
Decode = ""
End Function
'配置信息
'定义变量,password密码,IntervalTime空闲时间
Function GetConfig()
Dim s As String, t() As String, a As String
FileName = App.Path + "\CONFIG"
'如果文件不存在,则创建文件
If Dir(FileName) = "" Then
Open FileName For Output As #1 '打开顺序文件,我们可以使用Open语句
a = Encode("123") + vbCrLf + "10" + vbCrLf 'vbCrLf为回车
Print #1, a '写数据
Close #1 '关闭文件
'隐藏文件
'SetAttr FileName, vbSystem Or vbHidden
End If
Open FileName For Binary As #11
s = Input(LOF(11), #11)
Close #11
t = Split(s, vbCrLf)
password = Decode(t(0))
IntervalTime = t(1) '第三行是2,第四行是3,类推
filedir = t(2)
End Function
Function SetConfig(ByVal Value As String, ByVal Weizhi As Integer) As Boolean
Close #99 '关闭打开的配置文件
FileName = App.Path + "\CONFIG"
Dim s As String, t() As String
Open FileName For Binary As #123
s = Input(LOF(123), #123)
Close #123
t = Split(s, vbCrLf)
t(Weizhi) = Value '第三行是2,第四行是3,类推
s = Join(t, vbCrLf)
Kill FileName
Open FileName For Binary As #11
Put #11, , s
Close #11
SetConfig = True
Open FileName For Binary As #99 '打开配置文件,防止手工修改
End Function
最近把以前写的一个小程序PClock做了一次更新,以前的程序是程序运行后系统界面锁定,需输入密码方能解锁。这次更新后的效果是,程序运行以后在后台监视空闲的时间(键盘和鼠标无动作),当空闲的时间等于设定时间时Windows系统界面锁定。
就是这么一个小功能的更新,花了我3天的时间,主要原因是走了不少的弯路。在差不多要放弃的时候让我找到了解决的方法。
程序的界面和功能没有太大的改变,以下是程序的ChangeLog:
1、程序的名称从PClock改为PcLocker
2、程序转为后台运行,当系统空闲时锁定Windows系统,类似于进入屏幕保护程序
3、改变了禁用任务管理器的方式
4、实现了手工无法修改配置文件
5、优化并精简了代码
6、程序适用于Windows XP、Windows 7,其他的系统没有测试
7、初始密码123,程序默认空闲启动时间为10分钟,默认随机自启动关闭
源程序的下载地址:点我
下面就是整个程序的源码,主要包括1个模块module1.bas,1个主程序窗口MainForm.frm,1个设置窗口setform.frm
主程序窗口MainForm.frm的代码如下,程序的主要功能集中在此。
'计算空闲时间Private 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 LongPrivate Declare Function EnableWindow Lib "user32" (ByVal hWnd As Integer, ByVal aBOOL As Integer) As IntegerPrivate Declare Function IsWindowEnabled Lib "user32" (ByVal hWnd As Integer) As IntegerPrivate Declare Function GetMenu Lib "user32" (ByVal hWnd As Integer) As IntegerPrivate Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPrivate Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, ByVal lpvParam As Any, ByVal fuWinIni As Long) As Long'常量声明Const SWP_NOMOVE = &H2 '保持当前位置(x和y设定将被忽略)Const SWP_NOSIZE = &H1 '保持当前大小(cx和cy会被忽略)Const HWND_TOPMOST = -1Const HWND_NOTOPMOST = -2Const flags = SWP_NOMOVE Or SWP_NOSIZE'使用GetLastInputInfo来检测键盘、鼠标无动作Private Declare Function GetLastInputInfo Lib "user32" (plii As LASTINPUTINFO) As BooleanPrivate Declare Function GetTickCount Lib "kernel32" () As LongPrivate Type LASTINPUTINFO cbSize As Long dwTime As LongEnd TypePrivate Sub Form_Load() If App.PrevInstance = True Then '用APP对象的PrevInstance属性,防止同时运行屏幕保护程序的两个实例 Unload Me Exit Sub End If Timer1.Interval = 1000 '读取配置信息 Call GetConfig '打开配置文件,防止手工修改 FileName = App.Path + "\CONFIG" Open FileName For Binary As #99End SubPrivate Sub BntOk_Click() If (Text1.Text = password) Then ' 卸载钩子 UnhookWindowsHookEx lHook Timer1.Enabled = True Me.Visible = False Text1.Text = "" Timer2.Enabled = False Else Label2.Visible = True Label2.Caption = "输入密码不正确,请重新输入!" Text1.Text = "" Text1.SetFocus End IfEnd SubPrivate Sub BntEmpty_Click() Text1.Text = ""End Sub'显示主程序界面Private Sub ShowForm() ' 安装钩子 lHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf CallKeyHookProc, App.hInstance, 0) '如果更改的背景文件不存在,或者文件目录为空,则显示默认背景 If (filedir <> "" And Dir(filedir) <> "") Then '开始的时候使用的是改变窗口的默认背景,这样的话这个背景不会被拉伸,只能保持默认大小,舍弃 Me.Picture = LoadPicture(filedir) '现在使用image控件来实现 Image1.Width = Screen.Width Image1.Height = Screen.Height '这里把窗口设为全屏,因为image 要随着窗口变化 Top = 0 Left = 0 Me.Width = Screen.Width Me.Height = Screen.Height Me.Image1.Visible = False Me.Image1.Picture = LoadPicture(filedir) Me.AutoRedraw = True Me.PaintPicture Image1.Picture, 0, 0, Me.ScaleWidth, Me.ScaleHeight End If Me.Show 'setFocus前面须有这个 '设置窗口在最上面 Dim Ok Ok = SetWindowPos(Me.hWnd, HWND_TOPMOST, 0, 0, 0, 0, flags) '设置全屏 Top = 0 Left = 0 Me.Width = Screen.Width Me.Height = Screen.Height '设置输入框的位置 Frame1.Top = Screen.Height - Frame1.Height Frame1.Left = Screen.Width - Frame1.Width Label2.Left = Frame1.Left Label2.Top = Frame1.Top - Label2.Height Label2.Width = Frame1.Width Label2.Visible = False Text1.SetFocus '禁用alt+ctrl+delete 'Open Environ$("WinDir") & "\system32\taskmgr.exe" For Binary As #1 Timer1.Enabled = False Timer2.Enabled = True Text1.SetFocusEnd Sub'设置窗口Private Sub BntSet_Click() If (Text1.Text = password) Then ' 卸载钩子 UnhookWindowsHookEx lHook Me.Visible = False Text1.Text = "" setform.Show Timer1.Enabled = True Else Label2.Visible = True Label2.Caption = "输入密码不正确,请重新输入!" Text1.Text = "" Text1.SetFocus End IfEnd Sub'回车之后的动作Private Sub Text1_KeyPress(KeyAscii As Integer) ' Text1 响应回车键 If KeyAscii = 13 Then If (Text1.Text = password) Then ' 卸载钩子 UnhookWindowsHookEx lHook Me.Visible = False Text1.Text = "" Timer1.Enabled = True Timer2.Enabled = False Else Label2.Visible = True Label2.Caption = "输入密码不正确,请重新输入!" Text1.Text = "" Text1.SetFocus End If End IfEnd Sub'当空闲时间大于IntervalTime时,调用ShowFormPrivate Sub Timer1_Timer() Dim lii As LASTINPUTINFO lii.cbSize = Len(lii) If GetLastInputInfo(lii) Then If (GetTickCount - lii.dwTime)/60000 > IntervalTime Then Call ShowForm End If End IfEnd Sub'禁用任务管理器Private Sub Timer2_Timer() Shell ("cmd /c taskkill /f /im taskmgr.exe"), vbHideEnd Sub
设置窗口setform.frm的代码,包括密码设置、背景图片设置、开机自启动设置和空闲启动时间设置。
Dim change As BooleanPrivate Sub Command1_Click() '先读出密码 passwordstr = password FileName = App.Path + "\CONFIG" '配置文件路径 '验证密码 If Text1.Text = passwordstr And Text3.Text = Text2.Text Then NewPassword = Encode(Text2.Text) change = SetConfig(NewPassword, 0) '设置以后重新读取配置文件 Call GetConfig If (change = True) Then MsgBox "口令修改成功" Else If Text2.Text <> Text3.Text Then MsgBox "两次口令输入不一致,请重新输入" Else MsgBox "旧口令错,请重新输入" End If End IfEnd SubPrivate Sub Command2_Click() Unload MeEnd SubPrivate Sub Command3_Click() Set w = CreateObject("wscript.shell") w.regwrite "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\" & App.EXEName, App.Path & "\" & App.EXEName & ".exe" MsgBox "已经设置为开机自启动"End SubPrivate Sub Command4_Click() Set w = CreateObject("wscript.shell") w.regdelete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\" & App.EXEName MsgBox "已经取消开机自启动"End SubPrivate Sub Command5_Click() CommonDialog1.Filter = "jpg|*.jpg" CommonDialog1.ShowOpen filedir = CommonDialog1.FileName If (filedir <> "") Then change = True change = SetConfig(filedir, 2) '设置以后重新读取配置文件 Call GetConfig If (change = True) Then MsgBox "背景替换成功"End SubPrivate Sub Command6_Click() change = SetConfig("", 2) '设置以后重新读取配置文件 Call GetConfig If (change = True) Then MsgBox "已恢复为默认背景"End SubPrivate Sub Command7_Click() Unload MeEnd SubPrivate Sub IntervalBnt_Click() change = SetConfig(setform.IntervalTxt.Text, 1) '设置以后重新读取配置文件 Call GetConfig If (change = True) Then MsgBox "修改成功"End Sub
模块module1.bas代码,主要是禁用键盘和加密函数。
Option ExplicitPublic Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Public Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As IntegerPublic Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As LongPublic Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As LongPublic Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As LongPublic Const HC_ACTION = 0Public Const WM_KEYDOWN = &H100Public Const WM_KEYUP = &H101Public Const WM_SYSKEYDOWN = &H104Public Const WM_SYSKEYUP = &H105Public Const VK_TAB = &H9Public Const VK_CONTROL = &H11Public Const VK_ESCAPE = &H1BPublic Const VK_DELETE = &H2EPublic Const WH_KEYBOARD_LL = 13Public Const LLKHF_ALTDOWN = &H20'禁用键盘的功能键Public Type KBDLLHOOKSTRUCT vkCode As Long scanCode As Long flags As Long time As Long dwExtraInfo As LongEnd TypePublic lHook As LongDim p As KBDLLHOOKSTRUCTDim key() As Byte'全局变量Public password As StringPublic IntervalTime As IntegerPublic filedir As StringPublic FileName As String'键盘钩子Public Function CallKeyHookProc(ByVal ncode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim fEatKeystroke As Boolean If (ncode = HC_ACTION) Then If wParam = WM_KEYDOWN Or wParam = WM_SYSKEYDOWN Or wParam = WM_KEYUP Or wParam = WM_SYSKEYUP Then CopyMemory p, ByVal lParam, Len(p) fEatKeystroke = _ ((p.vkCode = VK_TAB) And ((p.flags And LLKHF_ALTDOWN) <> 0)) Or _ ((p.vkCode = VK_ESCAPE) And ((p.flags And LLKHF_ALTDOWN) <> 0)) Or _ ((p.flags And LLKHF_ALTDOWN) <> 0) Or _ ((p.vkCode = VK_ESCAPE) And ((GetKeyState(VK_CONTROL) And &H8000) <> 0)) Or _ ((p.vkCode = 91) Or (p.vkCode = VK_ESCAPE) Or (p.vkCode = 92) Or (p.vkCode = 93)) '判断是否按下了:TAB+ALT、Esc+ALT、Alt(Alt+F4)、Esc+Ctrl、左右 Win 和徽标键\Esc End If End If If fEatKeystroke Then ' 设置为 1 可以屏蔽按键 CallKeyHookProc = 1 Else CallKeyHookProc = CallNextHookEx(0, ncode, wParam, ByVal lParam) End IfEnd FunctionSub initkey() '这里为密匙,建议定义的复杂些,我这里仅仅是个示例 ReDim key(9) key(0) = 12 key(1) = 43 key(2) = 53 key(3) = 67 key(4) = 78 key(5) = 82 key(6) = 91 key(7) = 245 key(8) = 218 key(9) = 190 End Sub Function Encode(ByVal s As String) As String '加密 On Error GoTo myerr initkey Dim buff() As Byte buff = StrConv(s, vbFromUnicode) Dim i As Long, j As Long Dim k As Long k = UBound(key) + 1 For i = 0 To UBound(buff) j = i Mod k buff(i) = buff(i) Xor key(j) Next Dim mstr As String mstr = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" Dim outstr As String Dim temps As String For i = 0 To UBound(buff) k = buff(i) \ Len(mstr) j = buff(i) Mod Len(mstr) temps = Mid(mstr, j + 1, 1) + Mid(mstr, k + 1, 1) outstr = outstr + temps Next Encode = outstr Exit Functionmyerr: Encode = "" End Function Function Decode(ByVal s As String) As String '解密 On Error GoTo myerr initkey Dim i As Long, j As Long Dim k As Long, n As Long Dim mstr As String mstr = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" Dim outstr As String Dim temps As String If Len(s) Mod 2 = 1 Then Decode = "" Exit Function End If Dim t1 As String Dim t2 As String Dim buff() As Byte Dim m As Long m = 0 For i = 1 To Len(s) Step 2 t1 = Mid(s, i, 1) t2 = Mid(s, i + 1, 1) j = InStr(1, mstr, t1) k = InStr(1, mstr, t2) n = j - 1 + (k - 1) * Len(mstr) ReDim Preserve buff(m) buff(m) = n m = m + 1 Next k = UBound(key) + 1 For i = 0 To UBound(buff) j = i Mod k buff(i) = buff(i) Xor key(j) Next Decode = StrConv(buff, vbUnicode) Exit Functionmyerr: Decode = ""End Function'配置信息'定义变量,password密码,IntervalTime空闲时间Function GetConfig() Dim s As String, t() As String, a As String FileName = App.Path + "\CONFIG" '如果文件不存在,则创建文件 If Dir(FileName) = "" Then Open FileName For Output As #1 '打开顺序文件,我们可以使用Open语句 a = Encode("123") + vbCrLf + "10" + vbCrLf 'vbCrLf为回车 Print #1, a '写数据 Close #1 '关闭文件 '隐藏文件 'SetAttr FileName, vbSystem Or vbHidden End If Open FileName For Binary As #11 s = Input(LOF(11), #11) Close #11 t = Split(s, vbCrLf) password = Decode(t(0)) IntervalTime = t(1) '第三行是2,第四行是3,类推 filedir = t(2)End FunctionFunction SetConfig(ByVal Value As String, ByVal Weizhi As Integer) As Boolean Close #99 '关闭打开的配置文件 FileName = App.Path + "\CONFIG" Dim s As String, t() As String Open FileName For Binary As #123 s = Input(LOF(123), #123) Close #123 t = Split(s, vbCrLf) t(Weizhi) = Value '第三行是2,第四行是3,类推 s = Join(t, vbCrLf) Kill FileName Open FileName For Binary As #11 Put #11, , s Close #11 SetConfig = True Open FileName For Binary As #99 '打开配置文件,防止手工修改End Function
Open "C:\WINDOWS\system32\taskmgr.exe" For Binary As #1
Shell ("cmd /c taskkill /f /im taskmgr.exe"), vbHide
Private Sub Timer1_timer()
Shell ("cmd /c taskkill /f /im taskmgr.exe"), vbHide
End Sub
在Windows XP下禁用Ctrl-Alt-Delete的方法比较简单,因为Ctrl-Alt-Delete组合键的功能就是调用任务管理器,直接把任务管理器给禁用了,Ctrl-Alt-Delete的功能也就没有了,相当于也给禁用了。这个方法的简单的实现是用二进制 stream 形式先打开 C:\windows\system32\taskmgr.exe任务管理器程序,使后续无法手工正常打开任务管理器。代码如下:
Open "C:\WINDOWS\system32\taskmgr.exe" For Binary As #1
这种方法在XP上是可行的,但是在VISTA和WIN7上是无效的。我的解决方法是用taskkill命令来结束任务管理器程序taskmgr.exe。代码如下:
Shell ("cmd /c taskkill /f /im taskmgr.exe"), vbHide
在VB程序里实现的话,最好把上述语句放到Timer事件中,每隔一段时间执行一次,就能实现禁用任务管理器的目的了。代码如下:
Private Sub Timer1_timer() Shell ("cmd /c taskkill /f /im taskmgr.exe"), vbHideEnd Sub
'API调用与常用定义:
Private Declare Function SystemParametersInfo _
Lib "user32" _
Alias "SystemParametersInfoA" _
(ByVal uiAction As Long, _
ByVal uiParam As Long, _
pvParam As Any, _
ByVal fWInIni As Long) As Boolean
Private Const SPI_GETSCREENSAVEACTIVE As Long = &H10 '屏保是否启用的常量
Private Const SPI_GETSCREENSAVERRUNNING As Long = &H72 '屏保是否运行的常量
Private Sub Timer1_Timer()
Dim bRunning As Boolean '屏保是否运行的变量,当然你可以定义全局变量
SystemParametersInfo SPI_GETSCREENSAVERRUNNING, 0, bRunning, False '调用API,bRunning返回屏保运行状态
Debug.Print Time; "屏保运行="; bRunning '演示:打印屏保是否运行的信息
End Sub
'另外,查看屏保是否启用,也可以用下面方法:
SystemParametersInfo SPI_GETSCREENSAVEACTIVE, 0, bActive, False 'bActive为返回值(逻辑型)
Option Explicit
Private Declare Function GetLastInputInfo Lib "user32" (plii As LASTINPUTINFO) As Boolean
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Type LASTINPUTINFO
cbSize As Long
dwTime As Long
End Type
Private Sub Form_Load()
Timer1.Interval = 1000
End Sub
Private Sub Timer1_Timer()
Dim lii As LASTINPUTINFO
lii.cbSize = Len(lii)
If GetLastInputInfo(lii) Then
If (GetTickCount - lii.dwTime) / 60000 >= 15 Then
Call MsgBox("由于本机15分钟没有操作,如果3分钟后没有反应,系统将强制关机", vbYesNo + vbExclamation + vbDefaultButton2, "提示")
End If
End If
End Sub
我想要实现的功能是,当键盘无输入、鼠标无移动或点击动作时调用程序。首先想到的是用钩子HOOK来获取键盘或者鼠标的动作,如果无动作时调用程序。我尝试的结果是HOOK来HOOK去总是有问题。
后来想到Windows的屏幕保护程序就是当键盘鼠标无动作时进入屏幕保护的,于是改变思路,想把程序做成这样的形式,键盘鼠标无动作,系统进入屏幕保护,然后检测系统是否运行屏幕保护程序,如果运行的话则调用程序。这种方式就是以屏幕保护程序作为中介,把检测键盘鼠标动作的工作交给屏幕保护程序来完成了。SystemParametersInfo可以实现获取屏幕保护信息的函数。参考代码如下:
'API调用与常用定义:Private Declare Function SystemParametersInfo _ Lib "user32" _ Alias "SystemParametersInfoA" _ (ByVal uiAction As Long, _ ByVal uiParam As Long, _ pvParam As Any, _ ByVal fWInIni As Long) As BooleanPrivate Const SPI_GETSCREENSAVEACTIVE As Long = &H10 '屏保是否启用的常量Private Const SPI_GETSCREENSAVERRUNNING As Long = &H72 '屏保是否运行的常量Private Sub Timer1_Timer() Dim bRunning As Boolean '屏保是否运行的变量,当然你可以定义全局变量 SystemParametersInfo SPI_GETSCREENSAVERRUNNING, 0, bRunning, False '调用API,bRunning返回屏保运行状态 Debug.Print Time; "屏保运行="; bRunning '演示:打印屏保是否运行的信息End Sub'另外,查看屏保是否启用,也可以用下面方法:SystemParametersInfo SPI_GETSCREENSAVEACTIVE, 0, bActive, False 'bActive为返回值(逻辑型)
可是不知道为什么我在WIN7下调试还是有问题,提示SystemParametersInfo SPI_GETSCREENSAVERRUNNING, 0, bRunning, False
中的bRunning类型错误,只能作罢。
最后来说一下最终实现的方案是使用GetLastInputInfo函数获取系统的空闲时间,参考代码如下:
Option ExplicitPrivate Declare Function GetLastInputInfo Lib "user32" (plii As LASTINPUTINFO) As BooleanPrivate Declare Function GetTickCount Lib "kernel32" () As LongPrivate Type LASTINPUTINFO cbSize As Long dwTime As LongEnd TypePrivate Sub Form_Load() Timer1.Interval = 1000 End SubPrivate Sub Timer1_Timer() Dim lii As LASTINPUTINFO lii.cbSize = Len(lii) If GetLastInputInfo(lii) Then If (GetTickCount - lii.dwTime) / 60000 >= 15 Then Call MsgBox("由于本机15分钟没有操作,如果3分钟后没有反应,系统将强制关机", vbYesNo + vbExclamation + vbDefaultButton2, "提示") End If End IfEnd Sub
题目很拗口,主要是想要表达的东西比较曲折,还是以实例来说明比较直观,假设在Access中有以下的表table1。table1是一张成绩表,我想要的结果是:所有人的成绩按着总分(Score)从大到小排列,然后在排列好的表中从上到下累加English/Score列(第1行+第2行+……+第N行的值),当累加值>0.7时,取出第1行到第N行的记录。
Private Sub Form_Click()
Dim db As New ADODB.Connection, RS As New ADODB.Recordset 'ADO连接对象和记录集
Dim strSQL As String 'SQL字符串
db.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;Data source =" & App.Path & "/xs.mdb" '数据库连接
db.Open '打开数据库
strSQL = "select * from xj" 'SQL字符串
RS.Open strSQL, db, 3, 1 '查询数据表
Do While Not RS.EOF '循环输出查询到的结果
Print RS!姓名; RS!性别; RS!班级; RS!出生年月 '在窗口中打印输出结果
RS.MoveNext '记录下移
Loop
RS.Close '关闭记录集
Set RS = Nothing
End Sub
这里只是个简单不能再简单的VB小程序实例,但它包含这几个关键字:VB6.0、ADO、Access
环境:visual basic 6.0 企业版(非精简版,不然会缺少必须的控件)
数据库:Access数据库,数据库是xs.mbd,内建表为xj
结果:vb使用ADO连接access数据库,查询xj表中的所有数据,然后把查询到的结果循环输出到窗口中。
代码:
Private Sub Form_Click()Dim db As New ADODB.Connection, RS As New ADODB.Recordset 'ADO连接对象和记录集Dim strSQL As String 'SQL字符串db.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;Data source =" & App.Path & "/xs.mdb" '数据库连接db.Open '打开数据库strSQL = "select * from xj" 'SQL字符串RS.Open strSQL, db, 3, 1 '查询数据表Do While Not RS.EOF '循环输出查询到的结果Print RS!姓名; RS!性别; RS!班级; RS!出生年月 '在窗口中打印输出结果RS.MoveNext '记录下移LoopRS.Close '关闭记录集Set RS = NothingEnd Sub
源代码下载地址:vb_ado_access.zip
Public Function decprime(k As Integer) As Boolean
Dim i As Integer
i = 2 '用最小质数2去除
While k > 1
If k Mod i = 0 Then '如果可以整除,则i为所求的质因子
Print i
k = k / i '求得商
Else
i = i + 1
End If
Wend
End Function