如何检测U盘并定时提醒备份?
U盘备份器.rar
(3.65 KB)
问题:1、自动运行,但想直接最小化在托盘显示,或者在后台隐藏之类的。
2、有U盘插入后自动检测,然后提醒是否要备份,然后可以自己设定间隔多长时间提示备份,或者在电脑里留个记录文件,每隔1个月提示备份一次该U盘。
3、运行时占用内存6m,能否精简,启动载入速度也不够理想,如何优化?
VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 3510 ClientLeft = 60 ClientTop = 450 ClientWidth = 6015 LinkTopic = "Form1" ScaleHeight = 3510 ScaleWidth = 6015 StartUpPosition = 3 '系统预设值 Begin VB.ListBox List1 Height = 3300 Left = 120 TabIndex = 0 Top = 120 Width = 5775 End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Option Explicit Private Sub Form_Load() '子类化窗体的消息处理函数 HookForm Me End Sub Private Sub Form_Unload(Cancel As Integer) '程序退出时恢复原窗体处理函数 UnHookForm Me End Sub '效果图: '备注:本示例程序不仅仅能检测U盘的插入,对CDROM、网络映射盘等设备也会作出同样的反应,如果需要只检测U盘,则需要在If info.lDevicetype =DBT_DEVTYP_VOLUME '处再对iFlag结构成员作检测,其数值为0时表示设备为U盘。另外根据微软的解释,软盘的插拔是不会有引发该消息的,原因是只有支持软弹出技术的设备才会引发该消息。 '(原文:Messages for media arrival and removal are sent only for media in devices that support a soft-eject mechanism. ) '本演示程序在WINDOWS98、XP系统下调试通过。
'VB: 如何检测到U盘的插拔 (源代码) '2007年06月02日 星期六 23:22 '听说现在网络上流传着一些能实时检测到U盘插拔消息并能在其插入后伺机拷贝其中文档资料的恶意程序,而日前在CSDN论坛也看到有网友询问这类程序的实现原理,为此我想通过一个简单的VB程序演示一下核心操作过程并藉机把实现原理作一个简洁的说明。 '事实上当U盘(实际上不局限于U盘,所有能在系统中获得逻辑卷标的设备都适用)插入视窗系统的机器后操作系统将发送一个WM_DEVICECHANGE的广播消息,因此只要在相应的消息处理过程中拦截该信息并加以处理就能实时检测到U盘的插拔,之后即可进行预设的有关处理动作了。 '熟悉WINDOWS消息处理过程的人都知道,操作系统发送有关消息时还会附带上两个重要的参数:wParam、lParam,因此WM_DEVICECHANGE也不例外,当该消息发生时,wParam里的内容是指示设备变化的具体事件类别,在我们的演示程序里只需要关心DBT_DEVICEARRIVAL和DBT_DEVICEREMOVECOMPLETE这两个事件,前者表示新设备已经插入机器并能正常使用了,后者表示设备已经被物理移除了;lParam的内容实际上是一个地址,指向一个结构体,该结构的具体细节由插入系统的设备类型决定,这里有个需要注意的地方,即不论设备类型是什么,该结构的前面三个LONG型成员是固定的,因此我们可以先取得这三个成员的内容,再根据第二个成员的数值来确定新设备类型,然后再获取全部成员的内容。 ' 以下是这个VB演示程序的代码,效果就是检测到设备插入后即把该设备根目录下的全部文件名显示在LISTBOX里面。 '‘子类化窗体消息处理函数时需要使用的API,很常见,不作过多说明。 Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long) Private Const GWL_WNDPROC = -4 Private Const WM_DEVICECHANGE As Long = &H219 Private Const DBT_DEVICEARRIVAL As Long = &H8000& Private Const DBT_DEVICEREMOVECOMPLETE As Long = &H8004& '设备类型:逻辑卷标 Private Const DBT_DEVTYP_VOLUME As Long = &H2 '与WM_DEVICECHANGE消息相关联的结构体头部信息 Private Type DEV_BROADCAST_HDR lSize As Long lDevicetype As Long '设备类型 lReserved As Long End Type '设备为逻辑卷时对应的结构体信息 Private Type DEV_BROADCAST_VOLUME lSize As Long lDevicetype As Long lReserved As Long lUnitMask As Long '和逻辑卷标对应的掩码 iFlag As Integer End Type Private info As DEV_BROADCAST_HDR Private info_volume As DEV_BROADCAST_VOLUME Private PrevProc As Long '‘原来的窗体消息处理函数地址 Public Sub HookForm(F As Form) PrevProc = SetWindowLong(F.hwnd, GWL_WNDPROC, AddressOf WindowProc) End Sub Public Sub UnHookForm(F As Form) SetWindowLong F.hwnd, GWL_WNDPROC, PrevProc End Sub Private Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Select Case uMsg '插入USB DISK 则接收到此消息 Case WM_DEVICECHANGE If wParam = DBT_DEVICEARRIVAL Then '若插入USBDISK或者映射网络盘等则 'info.lDevicetype =2 '即DBT_DEVTYP_VOLUME '利用参数lParam获取结构体头部信息 CopyMemory info, ByVal lParam, Len(info) If info.lDevicetype = DBT_DEVTYP_VOLUME Then CopyMemory info_volume, ByVal lParam, Len(info_volume) '检测到有逻辑卷添加到系统中,则显示该设备根目录下全部文件名 ListFiles Chr(GetDriveName(info_volume.lUnitMask)) & ":\", Form1.List1 End If End If If wParam = DBT_DEVICEREMOVECOMPLETE Then '若移走USBDISK或者映射网络盘等则 'info.lDevicetype =2 '即DBT_DEVTYP_VOLUME '利用参数lParam获取结构体头部信息 CopyMemory info, ByVal lParam, Len(info) If info.lDevicetype = DBT_DEVTYP_VOLUME Then CopyMemory info_volume, ByVal lParam, Len(info_volume) '清除LIST中的内容 Form1.List1.Clear End If End If End Select ' 调用原来的窗体消息处理函数 WindowProc = CallWindowProc(PrevProc, hwnd, uMsg, wParam, lParam) End Function '根据输入的32位LONG型数据(只有一位为1)返回对应的卷标的ASCII数值 '规则是1:A、2:B、4:C等等 Private Function GetDriveName(ByVal lUnitMask As Long) As Byte Dim i As Long i = 0 While lUnitMask Mod 2 <> 1 lUnitMask = lUnitMask \ 2 i = i + 1 Wend GetDriveName = Asc("A") + i End Function '显示插入逻辑卷根目录的文件名列表,需要在工程里引用Microsoft Scripting Runtime库。 Private Function ListFiles(strPath As String, ByRef list As ListBox) Dim fso As New Scripting.FileSystemObject Dim objFolder As Folder Dim objFile As File Set objFolder = fso.GetFolder(strPath) For Each objFile In objFolder.Files list.AddItem objFile.Name Next End Function
VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 3090 ClientLeft = 60 ClientTop = 450 ClientWidth = 4680 LinkTopic = "Form1" ScaleHeight = 3090 ScaleWidth = 4680 StartUpPosition = 3 '系統預設值 Begin VB.Timer Timer1 Left = 3840 Top = 240 End Begin Command2 Caption = "Command2" Height = 495 Left = 2160 TabIndex = 1 Top = 240 Width = 1335 End Begin Command1 Caption = "Command1" Height = 495 Left = 360 TabIndex = 0 Top = 240 Width = 1335 End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False '用VB實現卸載U盤 '一般在拔U盤之前,都要先「安全刪除硬件」的,用VB能實現這個功能嗎? '解答之一: 'Shell "RUNDLL32.EXE shell32.dll,Control_RunDLL hotplug.dll" '這句代碼可以彈出安全刪除硬件的窗口,可是我想要的不是這樣的效果,我需要直接把U盤安全刪除掉,不用彈出窗口。也就是自動安全刪除U盤。這樣有辦法嗎? '解答2: '代碼開始: Option Explicit 'QQ:121877114 丹心軟件設計 'E-MAIL:CNSTARWORK@ '2007.6.1 Dim boTimeOut As Boolean Private Const DRIVE_CDROM As Long = 5 Private Const DRIVE_REMOVABLE As Long = 2 Private Const GENERIC_READ As Long = &H80000000 Private Const GENERIC_WRITE As Long = &H40000000 Private Const OPEN_EXISTING As Long = 3 Private Const FILE_DEVICE_FILE_SYSTEM As Long = 9 Private Const FILE_DEVICE_MASS_STORAGE As Long = &H2D& Private Const METHOD_BUFFERED As Long = 0 Private Const FILE_ANY_ACCESS As Long = 0 Private Const FILE_READ_ACCESS As Long = 1 Private Const LOCK_VOLUME As Long = 6 Private Const DISMOUNT_VOLUME As Long = 8 Private Const EJECT_MEDIA As Long = &H202 Private Const MEDIA_REMOVAL As Long = &H201 Private Const INVALID_HANDLE_VALUE As Long = -1 Private Const LOCK_TIMEOUT As Long = 1000 Private Const LOCK_RETRIES As Long = 20 Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long Private Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByRef lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long Private Declare Function DeviceIoControl Lib "kernel32.dll" (ByVal hDevice As Long, ByRef dwIoControlCode As Long, ByRef lpInBuffer As Any, ByVal nInBufferSize As Long, ByRef lpOutBuffer As Any, ByVal nOutBufferSize As Long, ByRef lpBytesReturned As Long, ByRef lpOverlapped As Long) As Long Private Function CTL_CODE(lngDevFileSys As Long, lngFunction As Long, lngMethod As Long, lngAccess As Long) As Long CTL_CODE = (lngDevFileSys * (2 ^ 16)) Or (lngAccess * (2 ^ 14)) Or (lngFunction * (2 ^ 2)) Or lngMethod End Function Private Function OpenVolume(strLetter As String, lngVolHandle As Long) As Boolean Dim lngDriveType As Long Dim lngAccessFlags As Long Dim strVolume As String lngDriveType = GetDriveType(strLetter) Select Case lngDriveType Case DRIVE_REMOVABLE lngAccessFlags = GENERIC_READ Or GENERIC_WRITE Case DRIVE_CDROM lngAccessFlags = GENERIC_READ Case Else OpenVolume = False Exit Function End Select strVolume = "\\.\" & strLetter lngVolHandle = CreateFile(strVolume, lngAccessFlags, 0, ByVal CLng(0), OPEN_EXISTING, ByVal CLng(0), ByVal CLng(0)) If lngVolHandle = INVALID_HANDLE_VALUE Then OpenVolume = False Exit Function End If OpenVolume = True End Function Private Function CloseVolume(lngVolHandle As Long) As Boolean Dim lngReturn As Long lngReturn = CloseHandle(lngVolHandle) If lngReturn = 0 Then CloseVolume = False Else CloseVolume = True End If End Function Private Function LockVolume(ByRef lngVolHandle As Long) As Boolean Dim lngBytesReturned As Long Dim intCount As Integer Dim intI As Integer Dim boLocked As Boolean Dim lngFunction As Long lngFunction = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, LOCK_VOLUME, METHOD_BUFFERED, FILE_ANY_ACCESS) intCount = LOCK_TIMEOUT / LOCK_RETRIES boLocked = False For intI = 0 To LOCK_RETRIES boTimeOut = False Timer1.Interval = intCount Timer1.Enabled = True Do Until boTimeOut = True Or boLocked = True boLocked = DeviceIoControl(lngVolHandle, ByVal lngFunction, CLng(0), 0, CLng(0), 0, lngBytesReturned, ByVal CLng(0)) DoEvents Loop If boLocked = True Then LockVolume = True Timer1.Enabled = False Exit Function End If Next intI LockVolume = False End Function Private Function DismountVolume(lngVolHandle As Long) As Boolean Dim lngBytesReturned As Long Dim lngFunction As Long lngFunction = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, DISMOUNT_VOLUME, METHOD_BUFFERED, FILE_ANY_ACCESS) DismountVolume = DeviceIoControl(lngVolHandle, ByVal lngFunction, 0, 0, 0, 0, lngBytesReturned, ByVal 0) End Function Private Function PreventRemovalofVolume(lngVolHandle As Long) As Boolean Dim boPreventRemoval As Boolean Dim lngBytesReturned As Long Dim lngFunction As Long boPreventRemoval = False lngFunction = CTL_CODE(FILE_DEVICE_MASS_STORAGE, MEDIA_REMOVAL, METHOD_BUFFERED, FILE_READ_ACCESS) PreventRemovalofVolume = DeviceIoControl(lngVolHandle, ByVal lngFunction, boPreventRemoval, Len(boPreventRemoval), 0, 0, lngBytesReturned, ByVal 0) End Function Private Function AutoEjectVolume(lngVolHandle As Long) As Boolean Dim lngFunction As Long Dim lngBytesReturned As Long lngFunction = CTL_CODE(FILE_DEVICE_MASS_STORAGE, EJECT_MEDIA, METHOD_BUFFERED, FILE_READ_ACCESS) AutoEjectVolume = DeviceIoControl(lngVolHandle, ByVal lngFunction, 0, 0, 0, 0, lngBytesReturned, ByVal 0) End Function Private Sub Eject(strVol As String) Dim lngVolHand As Long Dim boResult As Boolean Dim boSafe As Boolean strVol = strVol & ":" ' ' Open and get a Handle for the Volume ' boResult = OpenVolume(strVol, lngVolHand) If boResult = False Then MsgBox "Error Opening Volume " & Err.LastDllError Exit Sub End If ' ' Lock the Volume ' boResult = LockVolume(lngVolHand) If boResult = False Then MsgBox "Error Dismounting Volume " & Err.LastDllError CloseVolume (lngVolHand) Exit Sub End If ' 'Dismount the Volume ' boResult = DismountVolume(lngVolHand) If boResult = False Then MsgBox "Error Dismounting Volume " & Err.LastDllError CloseVolume (lngVolHand) Exit Sub End If ' ' Set to allow the Volume to be Removed ' boResult = PreventRemovalofVolume(lngVolHand) If boResult = False Then MsgBox "Error Allowing Removal of Volume " & Err.LastDllError CloseVolume (lngVolHand) Exit Sub End If boSafe = True ' ' Eject the Volume ' boResult = AutoEjectVolume(lngVolHand) If boSafe = True Then MsgBox "Media may be Safely Removed from Drive " & UCase(strVol) End If ' ' Close the Handle ' boResult = CloseVolume(lngVolHand) If boResult = False Then MsgBox "Error Closing Volume " & Err.LastDllError Exit Sub End If Unload Me End Sub Private Sub Command1_Click() Eject "k" End Sub Private Sub Timer1_Timer() boTimeOut = True End Sub '代碼結束 '上述代碼實現了以上功能,如果U盤不是K呢? '加點下面的代碼: Private Function USBDISKINDEX() As String '找到U盤 Dim i As Long For i = Asc("C") To Asc("Z") If GetDriveType(Chr(i) + ":") = 2 Then USBDISKINDEX = Chr(i) End If Next i End Function Private Sub Command2_Click() Eject USBDISKINDEX '刪除U盤 End Sub
VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 2100 ClientLeft = 60 ClientTop = 450 ClientWidth = 3240 BeginProperty Font Name = "Gulim" Size = 9.75 Charset = 0 Weight = 700 Underline = 0 'False Italic = 0 'False Strikethrough = 0 'False EndProperty LinkTopic = "Form1" ScaleHeight = 2100 ScaleWidth = 3240 StartUpPosition = 3 '系统预设值 Begin VB.ListBox List1 BeginProperty Font Name = "新宋体" Size = 9 Charset = 136 Weight = 400 Underline = 0 'False Italic = 0 'False Strikethrough = 0 'False EndProperty Height = 1860 Left = 120 TabIndex = 0 Top = 120 Width = 3015 End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Option Explicit Dim fso As FileSystemObject Dim Dr As Drive Private Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long Private Const DRIVE_UNKNOWN = 0 '驱动器类型无法确定 Private Const DRIVE_NO_ROOT_DIR = 1 '驱动器根目录不存在 Private Const DRIVE_REMOVABLE = 2 '软盘驱动器或可移动盘 Private Const DRIVE_FIXED = 3 '硬盘驱动器 Private Const DRIVE_REMOTE = 4 'Network 驱动器 Private Const DRIVE_CDROM = 5 '光盘驱动器 Private Const DRIVE_RAMDISK = 6 'RAM 存储器 Private Sub Form_Load() Dim fso As New FileSystemObject Dim DL As Long For Each Dr In fso.Drives DL = GetDriveType(Dr) Select Case DL Case DRIVE_UNKNOWN Debug.Print Dr.DriveLetter & "盘类型无法确定" List1.AddItem Dr.DriveLetter & "盘类型无法确定" Case DRIVE_NO_ROOT_DIR Debug.Print Dr.DriveLetter & "盘不存在" List1.AddItem Dr.DriveLetter & "盘不存在" Case DRIVE_REMOVABLE Debug.Print Dr.DriveLetter & "盘为软盘驱动器或可移动盘" List1.AddItem Dr.DriveLetter & "盘为软盘驱动器或可移动盘" Case DRIVE_FIXED Debug.Print Dr.DriveLetter & "盘为硬盘驱动器" List1.AddItem Dr.DriveLetter & "盘为硬盘驱动器" Case DRIVE_REMOTE Debug.Print Dr.DriveLetter & "盘为Network 驱动器" List1.AddItem Dr.DriveLetter & "盘为Network 驱动器" Case DRIVE_CDROM Debug.Print Dr.DriveLetter & "盘为光盘驱动器" List1.AddItem Dr.DriveLetter & "盘为光盘驱动器" Case DRIVE_RAMDISK Debug.Print Dr.DriveLetter & "盘为RAM 存储器" List1.AddItem Dr.DriveLetter & "盘为RAM 存储器" End Select Next End Sub