|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic File API Routines SetFileTime: Modify the Date/Time of Folders and Files |
||
Posted: | Saturday September 21, 2002 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB6, Windows XP | |
OS restrictions: | Windows NT/2000/XP | |
Author: | VBnet - Randy Birch | |
Related: |
SetFileTime: Obtain and Change a File's Created, Accessed and Modified Dates | |
Prerequisites |
Windows NT4, Windows 2000 or Windows XP. |
|
Changing
the created, accessed or modified date of files or folders under Windows
NT, 2000 or XP requires only a few simple API calls. By using
CreateFile's special FILE_FLAG_BACKUP_SEMANTICS
flag we can obtain a handle to a folder or file and,
with SetFileTime, change its created, accessed or modified dates. When
dealing with folders, the created date is reflected in the folder's property window, while
Explorer shows the modified date (which under normal circumstances is
always the same as the created date). Under Windows XP at least, the last
accessed date of a folder is never shown. To change the folder or file time, the SYSTEMTIME structure is populated with the day, month and year, and hour, minute and second of the desired date / time. However, when those values are used directly in a call to SetFileTime, Windows interprets the values passed as reflecting a Universal Coordinated Time (UTC) - aka a time at Greenwich mean time (GMT). In order for the date / time entered to be properly reflected with the SetFileTime call, the values contained in the SYSTEMTIME structure must first be converted to a FILETIME structure via SystemTimeToFileTime, and then the system must apply the local system's time-zone bias via LocalFileTimeToFileTime. Once the FILETIME structure has been changed, it is passed to SetFileTime and the new folder or file date / time is set. Note that the code used in this method differs considerably from that used to change a file's created, accessed or modified date / time under Windows 9x (a method which is also applicable to NT-based machines), in that this method requires obtaining the folder's handle via CreateFile with the NT-specific FILE_FLAG_BACKUP_SEMANTICS flag set. The 9x-compatible method uses OpenFile to obtain the file handle where the FILE_FLAG_BACKUP_SEMANTICS flag is not supported. Command1 ("New Date") is provided as a convenience to rapidly test this code and just calls a routine to randomly select values from the combo. Command2 ("Change Date") executes the APIs responsible for the date change. |
BAS Module Code |
None. |
|
Form Code |
The form consists of three text boxes (Text1 - Text3), two command buttons (Command1, Command2) and six combo boxes (Combo1 - Combo6). Label as desired and add the following code: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const GENERIC_READ = &H80000000 Private Const GENERIC_WRITE = &H40000000 Private Const FILE_SHARE_READ = &H1 Private Const FILE_SHARE_DELETE As Long = &H4 Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000 Private Const OPEN_EXISTING = 3 Private Type FILETIME dwLowDateTime As Long dwHighDateTime As Long End Type Private Type SYSTEMTIME wYear As Integer wMonth As Integer wDayOfWeek As Integer wDay As Integer wHour As Integer wMinute As Integer wSecond As Integer wMilliseconds As Long End Type Private Declare Function CreateFile Lib "kernel32" _ Alias "CreateFileA" _ (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) As Long Private Declare Function CloseHandle Lib "kernel32" _ (ByVal hObject As Long) As Long Private Declare Function GetFileTime Lib "kernel32" _ (ByVal hFile As Long, _ lpCreationTime As FILETIME, _ lpLastAccessTime As FILETIME, _ lpLastWriteTime As FILETIME) As Long Private Declare Function FileTimeToLocalFileTime Lib "kernel32" _ (lpFileTime As FILETIME, _ lpLocalFileTime As FILETIME) As Long Private Declare Function FileTimeToSystemTime Lib "kernel32" _ (lpFileTime As FILETIME, _ lpSystemTime As SYSTEMTIME) As Long Private Declare Function SystemTimeToFileTime Lib "kernel32" _ (lpSystemTime As SYSTEMTIME, _ lpFileTime As FILETIME) As Long Private Declare Function LocalFileTimeToFileTime Lib "kernel32" _ (lpLocalFileTime As FILETIME, _ lpFileTime As FILETIME) As Long Private Declare Function SetFileTime Lib "kernel32" _ (ByVal hFile As Long, _ lpCreationTime As FILETIME, _ lpLastAccessTime As Any, _ lpLastWriteTime As Any) As Long Private Sub Form_Load() Dim cnt As Long 'days With Combo1 For cnt = 1 To 31 .AddItem cnt Next End With 'months With Combo2 For cnt = 1 To 12 .AddItem MonthName(cnt) .ItemData(.NewIndex) = cnt Next End With 'years (note: if you change this 'range, also change the Combo3 'random number maximum in 'SelectNewTestDate) With Combo3 For cnt = 1980 To 2002 .AddItem cnt Next End With 'hours With Combo4 For cnt = 1 To 24 .AddItem cnt Next End With 'minutes With Combo5 For cnt = 0 To 59 .AddItem cnt Next End With 'seconds With Combo6 For cnt = 0 To 59 .AddItem cnt Next End With Randomize Timer Call SelectNewTestDate Command1.Caption = "New Date" Command1.TabIndex = 0 Command2.Caption = "Change Date" End Sub Private Sub Command1_Click() 'select a new set of list indicies Call SelectNewTestDate End Sub Private Sub Command2_Click() Dim hFolder As Long 'obtain handle to the folder specified 'in Text1 hFolder = GetFolderFileHandle(Text1.Text) If (hFolder <> 0) And (hFolder > -1) Then 'show the current folder date/time info Call GetFolderFileDate(hFolder, Text2) 'attempt to change the date/time to the 'values set in the combos If ChangeFolderFileDate(hFolder) Then 'show the new folder date/time info Call GetFolderFileDate(hFolder, Text3) Else Text3.Text = "ChangeFolderFileDate failed." End If 'clean up. If hfolder = -1 on a subsequent 'run, you didn't close the hFolder handle. 'Save the project and exit VB to release 'the handle, then restart VB and re-run. Call CloseHandle(hFolder) Else Text2.Text = "Specified folder/file not found" End If End Sub Private Function ChangeFolderFileDate(ByVal hFolder As Long) As Boolean Dim st As SYSTEMTIME Dim ft As FILETIME 'set the day, month and year, and 'the hour, minute and second to the 'values representing the desired date/time With st .wDay = Combo1.List(Combo1.ListIndex) .wMonth = Combo2.ItemData(Combo2.ListIndex) .wYear = Combo3.List(Combo3.ListIndex) .wHour = Combo4.List(Combo4.ListIndex) .wMinute = Combo5.List(Combo5.ListIndex) .wSecond = Combo6.List(Combo6.ListIndex) End With 'call SystemTimeToFileTime to convert the system 'time (st) to a file time (ft) If SystemTimeToFileTime(st, ft) = 1 Then 'call LocalFileTimeToFileTime to convert the 'local file time to a file time based on the 'Coordinated Universal Time (UTC). Conveniently, 'the same FILETIME can be used as the in/out 'parameters! If LocalFileTimeToFileTime(ft, ft) = 1 Then 'and call SetFileTime to set the date and 'time that a file was created, last accessed, 'and/or last modified (in this case all to 'the same date/time). Since SetFileTime 'returns 1 if successful, cast to return 'a Boolean indicating failure or success. ChangeFolderFileDate = SetFileTime(hFolder, ft, ft, ft) = 1 End If End If End Function Private Sub GetFolderFileDate(ByVal hFolder As Long, txt As TextBox) Dim FT_CREATE As FILETIME Dim FT_ACCESS As FILETIME Dim FT_WRITE As FILETIME Dim buff As String 'fill in the FILETIME structures for the 'created, accessed and modified date/time info If GetFileTime(hFolder, FT_CREATE, FT_ACCESS, FT_WRITE) = 1 Then buff = "Created:" & vbTab & GetFolderFileDateString(FT_CREATE) & vbCrLf buff = buff & "Access'd:" & vbTab & GetFolderFileDateString(FT_ACCESS) & vbCrLf buff = buff & "Modified:" & vbTab & GetFolderFileDateString(FT_WRITE) txt.Text = buff End If End Sub Private Function GetFolderFileDateString(ft As FILETIME) As String Dim ds As Single Dim ts As Single Dim ft_local As FILETIME Dim st As SYSTEMTIME 'convert the file time to a local 'file time If FileTimeToLocalFileTime(ft, ft_local) Then 'convert the local file time to 'the system time format If FileTimeToSystemTime(ft_local, st) Then 'calculate the DateSerial/TimeSerial 'values for the system time ds = DateSerial(st.wYear, st.wMonth, st.wDay) ts = TimeSerial(st.wHour, st.wMinute, st.wSecond) 'and return a formatted string GetFolderFileDateString = FormatDateTime(ds, vbLongDate) & " " & _ FormatDateTime(ts, vbLongTime) End If End If End Function Private Function GetFolderFileHandle(sPath As String) As Long 'open and return a handle to the folder 'for modification. ' 'The FILE_FLAG_BACKUP_SEMANTICS flag is only 'valid on Windows NT/2000/XP, and is usually 'used to indicate that the file (or folder) is 'being opened or created for a backup or restore 'operation. The system ensures that the calling 'process overrides file security checks, provided 'it has the necessary privileges (SE_BACKUP_NAME 'and SE_RESTORE_NAME). ' 'In our case, specifying this flag obtains a handle to 'a directory, and a directory handle can be passed to 'some functions (e.g.. SetFileTime) in place of a file handle. GetFolderFileHandle = CreateFile(sPath, _ GENERIC_READ Or GENERIC_WRITE, _ FILE_SHARE_READ Or FILE_SHARE_DELETE, _ 0&, _ OPEN_EXISTING, _ FILE_FLAG_BACKUP_SEMANTICS, _ 0&) End Function Private Sub SelectNewTestDate() 'this just selects a new random 'number for each combo, thereby 'providing an easy test bed for 'changing test dates Combo1.ListIndex = Int(Rnd * 31) 'days Combo2.ListIndex = Int(Rnd * 12) 'months Combo3.ListIndex = Int(Rnd * 23) 'years Combo4.ListIndex = Int(Rnd * 24) 'hours Combo5.ListIndex = Int(Rnd * 60) 'minutes Combo6.ListIndex = Int(Rnd * 60) 'seconds End Sub |
Comments |
Run your project, and enter a valid folder or filename.
This project does not prompt before changing, nor does it provide an
undo, so take care applying it to valuable folders while testing. Pressing the New Date button cycles through random date/times. The Change button will update the folder or file specified, with the old file dates reflected in Text2, and the new dates after SetFileTime shown in Text3. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |