通过CreateFileA OPEN_EXISTING参数更改属性后的MS Access安全警告

时间:2019-04-16 02:07:13

标签: c# vba ms-access winapi

我有一个代码如下所示,要点是在.accdb文件中进行一些更改,保存文件的现有CreationTime,LastAccessTime和LastWriteTime属性。

一切正常,但是我遇到了这个问题: 原始的MS Access项目(成千上万的.accdb文件)包含VBA宏。标准策略是:“禁用所有带通知的宏”。因此,一旦用户单击该按钮,该文件将保存他的首选项(仅适用于此文件)-很好。

但是,当我通过以下脚本对文件进行更改后,它将重置该确切文件的安全设置,并且在下一次用户打开数据库时,黄色的“安全警告”会出现(所有宏和活动内容都相同,没有新内容!)。

问题是:我有成千上万个accdb文件。我需要进行一些小的更改,但要保存现有属性。 而且,当用户打开这些文件时,不应再有任何新的“安全警报”栏。

我可以,但是我不想:

  • 更改活动内容的安全设置

  • 将此文件夹设置为“受信任”文件夹

  • 任何其他安全设置更改,例如Regedit等。

我不添加任何宏或活动内容,出现此消息是因为使用CreateFileA之后的某些设置被更改了。 (例如,如果我手动重命名该文件,MS Access会认为它是另一个文件-并显示“安全”栏-没错;但是为什么更改文件属性后会显示它?)

谢谢! 附言我们正在使用MS Access 2016。


Option Explicit

Public Const GENERIC_WRITE = &H40000000, GENERIC_READ = &H80000000, FILE_ATTRIBUTE_NORMAL = &H80, OPEN_EXISTING = 3

Public Type FileTime:  dwLowDateTime As Long:  dwHighDateTime As Long: End Type

Public 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

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

Declare Function SetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FileTime, lpLastAccessTime As FileTime, lpLastWriteTime As FileTime) As Long

Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FileTime, lpLastAccessTime As FileTime, lpLastWriteTime As FileTime) As Long

Declare Function SystemTimeToFileTime Lib "kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FileTime) As Long

Declare Function LocalFileTimeToFileTime Lib "kernel32" (lpFileTime As FileTime, lpLocalFileTime As FileTime) As Long

Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As FileTime, lpSystemTime As SYSTEMTIME) As Long

Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpLocalFileTime As FileTime, lpFileTime As FileTime) As Long

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Public GlobCreationDate As Date, GlobLastAccess As Date, GlobLastWrite As Date

Public FileAddress As String



Function DTtoFT(ByVal DT As Date) As FileTime 'DateTimeToFileTime
Dim ST As SYSTEMTIME, lTime As FileTime
ST.wYear = Year(DT): ST.wMonth = Month(DT): ST.wDay = Day(DT): ST.wHour = Hour(DT): ST.wMinute = Minute(DT): ST.wSecond = Second(DT)
SystemTimeToFileTime ST, lTime
LocalFileTimeToFileTime lTime, DTtoFT
End Function

Function FTtoDT(FT As FileTime) As Date 'FileTimeToDateTime
Dim lTime As FileTime, ST As SYSTEMTIME
FileTimeToLocalFileTime FT, lTime
FileTimeToSystemTime lTime, ST
FTtoDT = DateSerial(ST.wYear, ST.wMonth, ST.wDay) + TimeSerial(ST.wHour, ST.wMinute, ST.wSecond)
End Function


Sub GetFTime(fName As String, Creation As Date, LastAccess As Date, LastWrite As Date)
Dim hFile As Long, ct As FileTime, at As FileTime, wt As FileTime
hFile = CreateFile(fName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
GetFileTime hFile, ct, at, wt
CloseHandle hFile
Creation = FTtoDT(ct): LastAccess = FTtoDT(at): LastWrite = FTtoDT(wt)
GlobCreationDate = FTtoDT(ct): GlobLastAccess = FTtoDT(at): GlobLastWrite = FTtoDT(wt)
End Sub

Sub SetFTime(fName As String, Optional Creation As Date = -657434, Optional LastAccess As Date = -657434, Optional LastWrite As Date = -657434)
Dim hFile As Long, ct As Date, at As Date, wt As Date

If Creation = -657434 Or LastAccess = -657434 Or LastWrite = -657434 Then
  GetFTime fName, ct, at, wt
  If Creation = -657434 Then Creation = ct
  If LastAccess = -657434 Then LastAccess = at
  If LastWrite = -657434 Then LastWrite = wt
End If

hFile = CreateFile(fName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
SetFileTime hFile, DTtoFT(Creation), DTtoFT(LastAccess), DTtoFT(LastWrite)
CloseHandle hFile
End Sub




Sub SetChanges()
Dim T1 As Date, T2 As Date, T3 As Date, T4 As Date, T5 As Date, T6 As Date
Dim cn As Object, strQuery As String
Dim strPathToDB As String

FileAddress = "D:\Projects\DB1.accdb"

GetFTime FileAddress, T1, T2, T3


'some code right here


SetFTime FileAddress, T1, T2, T3


'
End Sub

1 个答案:

答案 0 :(得分:0)

好的,伙计们,我已经找到了解决方案,所以也许这会对某人有所帮助。

MS Access显示“安全警告”的原因是因为脚本在技术上更改了创建日期,即使该日期是相同的日期。

现在,我可以声明MS Access正在使用“创建日期”,“文件位置”和“文件名”作为触发器,但我不确切知道是否将它们组合用作校验和之类,但是如果您更改了这些属性中的任何一个, Access认为我猜可能是另一个文件。

我通过MS Windows API进行了查找,发现了这一点:

  

使用FILETIME结构的函数可以允许零或正值之外的值,这些值通常由dwLowDateTime和dwHighDateTime成员指定。例如,SetFileTime函数使用0xFFFFFFFF来指定应保留文件的先前访问时间。

所以我稍微修改了代码:

Option Explicit
Public Const GENERIC_WRITE = &H40000000, GENERIC_READ = &H80000000, FILE_ATTRIBUTE_NORMAL = &H80, OPEN_EXISTING = 3
Public Type FileTime:  dwLowDateTime As Long:  dwHighDateTime As Long: End Type
Public 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
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
Declare Function SetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FileTime, lpLastAccessTime As FileTime, lpLastWriteTime As FileTime) As Long
Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FileTime, lpLastAccessTime As FileTime, lpLastWriteTime As FileTime) As Long
Declare Function SystemTimeToFileTime Lib "kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FileTime) As Long
Declare Function LocalFileTimeToFileTime Lib "kernel32" (lpFileTime As FileTime, lpLocalFileTime As FileTime) As Long
Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As FileTime, lpSystemTime As SYSTEMTIME) As Long
Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpLocalFileTime As FileTime, lpFileTime As FileTime) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public GlobCreationDate As Date, GlobLastAccess As Date, GlobLastWrite As Date
Public FileAddress As String

Function DTtoFT(ByVal DT As Date) As FileTime 
Dim ST As SYSTEMTIME, lTime As FileTime
ST.wYear = Year(DT): ST.wMonth = Month(DT): ST.wDay = Day(DT): ST.wHour = Hour(DT): ST.wMinute = Minute(DT): ST.wSecond = Second(DT)
SystemTimeToFileTime ST, lTime
LocalFileTimeToFileTime lTime, DTtoFT
End Function

Function FTtoDT(FT As FileTime) As Date 
Dim lTime As FileTime, ST As SYSTEMTIME
FileTimeToLocalFileTime FT, lTime
FileTimeToSystemTime lTime, ST
FTtoDT = DateSerial(ST.wYear, ST.wMonth, ST.wDay) + TimeSerial(ST.wHour, ST.wMinute, ST.wSecond)
End Function

Sub GetFTime(fName As String, Creation As Date, LastAccess As Date, LastWrite As Date)
Dim hFile As Long, ct As FileTime, at As FileTime, wt As FileTime
hFile = CreateFile(fName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
GetFileTime hFile, ct, at, wt
CloseHandle hFile
Creation = FTtoDT(ct): LastAccess = FTtoDT(at): LastWrite = FTtoDT(wt)
GlobCreationDate = FTtoDT(ct): GlobLastAccess = FTtoDT(at): GlobLastWrite = FTtoDT(wt)
End Sub



Sub SetFTime(fName As String, Optional Creation As Date = -657434, Optional LastAccess As Date = -657434, Optional LastWrite As Date = -657434)
Dim hFile As Long, ct As Date, at As Date, wt As Date
Dim CreateF As FileTime, AccessF As FileTime

If Creation = -657434 Or LastAccess = -657434 Or LastWrite = -657434 Then
  GetFTime fName, ct, at, wt
  If Creation = -657434 Then Creation = ct
  If LastAccess = -657434 Then LastAccess = at
  If LastWrite = -657434 Then LastWrite = wt
End If

CreateF.dwLowDateTime = 0: CreateF.dwHighDateTime = 0
AccessF.dwLowDateTime = 0: AccessF.dwLowDateTime = 0

hFile = CreateFile(fName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
SetFileTime hFile, CreateF, AccessF, DTtoFT(LastWrite)
CloseHandle hFile
End Sub



Sub SetChanges()
Dim T1 As Date, T2 As Date, T3 As Date
Dim cn As Object, strQuery As String
Dim strPathToDB As String

FileAddress = "D:\Projects\DB1.accdb"

GetFTime FileAddress, T1, T2, T3

'some code right here'

SetFTime FileAddress, T1, T2, T3

End Sub

它是如何工作的:现在该脚本不对CreationTime和LastAccessTime进行任何更改,并使用文件的先前属性。但是它会在执行某些代码后立即更改LastWriteTime。而且-最终-在不为最终用户重置安全性的情况下工作。