Access makes it easy to retrieve the modification date and time for files on disk, using the FileDateTime function. In one application, though, you need to be able to reset the last-modification date of files manually; the Access FileCopy function doesn't reset file date and time stamps, and you'd like copied files to have the current time. Is there a Windows API call that allows you to set file date and time stamps?
Windows provides the GetFileTime and SetFileTime API functions. Both work with three different date/time values: date of creation, date of last access, and date of last write. You want to preserve the date of creation and update the dates of last access and update. The code shown in this example will allow you to do this.
The sample form, frmTimeStamp, allows you to select a filename. The function then displays the date and time of last modification for the file, as shown in Figure 11-13. In addition, you can set a new file date, time, or both (the function retains whichever setting you don't change, if you just change one).
To set file date and time information in your own applications, follow these steps:
Import the module basTimeStamp from 11-11.MDB. This module includes the type definitions and Windows API declarations you'll need, as well as a VBA function to convert dates and times as retrieved from the API call into date/time values that Access can understand. If you want to use this sample form in your own applications, you'll also need to import basFillList, which includes functions to retrieve the list of files.
To set the modification-date information for a specific file, call the acbSetFileDateTime function, passing it a filename and a date/time value as parameters. For example, the following code will change the last-modification time and date for C:\AUTOEXEC.BAT to the current date and time:
blnOK = acbSetFileDateTime("C:\AUTOEXEC.BAT", Now)
The acbSetFileDateTime function consists of three basic steps. Its source code is:
Public Function acbSetFileDateTime( _ strFileName As String, varDate As Date) As Boolean Dim hFile As Long Dim of As OFSTRUCT Dim st As SYSTEMTIME Dim ftCreation As FILETIME Dim ftLastAccess As FILETIME Dim ftLastWrite As FILETIME Dim ftLocal As FILETIME Dim blnOK As Boolean st.wYear = Year(varDate) st.wMonth = Month(varDate) st.wDay = Day(varDate) st.wHour = Hour(varDate) st.wMinute = Minute(varDate) st.wSecond = Second(varDate) hFile = OpenFile(strFileName, of, OF_READWRITE) If hFile > 0 Then blnOK = GetFileTime(hFile, ftCreation, ftLastAccess, ftLastWrite) If blnOK Then blnOK = SystemTimeToFileTime(st, ftLastWrite) If blnOK Then blnOK = LocalFileTimeToFileTime(ftLastWrite, ftLocal) If blnOK Then blnOK = SetFileTime(hFile, ftCreation, ftLocal, ftLocal) CloseHandle hFile End If acbSetFileDateTime = blnOK End Function
The first step the function takes is to copy the date information from the Access Date-type variable into a structure that the API can use:
' In the declarations section: 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 Integer End Type ' In the function: Dim st As SYSTEMTIME st.wYear = Year(varDate) st.wMonth = Month(varDate) st.wDay = Day(varDate) st.wHour = Hour(varDate) st.wMinute = Minute(varDate) st.wSecond = Second(varDate)
Next, the function must open the requested file with read/write access so that it can write to the file's time stamp:
hFile = OpenFile(strFileName, of, OF_READWRITE)
If this succeeds, the function then retrieves the current time stamps, converts the system time structure to a file time structure, converts that time from local time to the internal generalized time that Windows uses, and finally sets the file time:
blnOK = GetFileTime(hFile, ftCreation, ftLastAccess, ftLastWrite) If blnOK Then blnOK = SystemTimeToFileTime(st, ftLastWrite) If blnOK Then blnOK = LocalFileTimeToFileTime(ftLastWrite, ftLocal) If blnOK Then blnOK = SetFileTime(hFile, ftCreation, ftLocal, ftLocal) CloseFileHandle hFile
The function sets both the time of last access and the time of last write to be the date and time you've specified.
When you select the Set button on the sample form, Access executes the following procedure:
Private Sub cmdSetTime_Click( ) Dim varDate As Date Dim strDate As String Dim strTime As String strDate = IIf(IsNull(Me.txtNewDate), Me.txtDate, Me.txtNewDate) strTime = IIf(IsNull(Me.txtNewTime), Me.txtTime, Me.txtNewTime) varDate = CVDate(strDate & " " & strTime) If Not acbSetFileDateTime(GetPath( ), varDate) Then MsgBox "Unable to set the file date!" Else Me.txtDate = Format(varDate, "Short Date") Me.txtTime = Format(varDate, "Short Time") End If End Sub
This procedure retrieves the dates you've typed on the form, converts them to an Access date/time value, and then sets the date for the file you've selected. Note that the example uses the existing date or time for any value you didn't enter. Because the Set button isn't enabled unless you enter at least the date or the time, there's no need to worry about when they're both null.
Unless you take the extra step of converting the passed-in date/time value from local time to the internal time Windows uses (Greenwich Mean Time), the time you set will be off by the difference in time zones between your time and the standardized time. The call to LocalTimeToFileTime takes care of this for you. Of course, this counts on the local time having been set correctly on the local system.