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. |
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 |