在普通 Windows 环境中部署 Microsoft Access 应用程序并不困难,但需要几个步骤。此处提供的方法和脚本将 - 从字面上看 - 将流程变成用户的一键式流程,即使在 Citrix 环境中也是如此。
一、目标
部署 Microsoft Access 应用程序的方法有很多种。其中许多需要用户执行几个步骤,而有些则不考虑更新。
然而,这里的方法只需要用户一键安装和运行应用程序。此外,它将允许根据开发人员的意愿对应用程序进行全自动更新——只需一个新版本的简单文件副本即可,并且可以在部分或所有用户启动应用程序时完成。
用户只需要直接访问快捷方式文件。这可以位于网络文件夹中、从 URL 检索或附加电子邮件。次双击时,它将安装应用程序和桌面快捷方式。下一次,将从分发文件夹中提取应用程序的新副本 - 更新当前副本,或替换可能已损坏或臃肿的前端文件。
二、它是如何完成的
实现起来非常简单:
- 双击快捷方式打开脚本
- 脚本运行并处理其余部分:
- 将应用程序文件复制到本地文件夹
- 设置注册表项以信任此本地文件夹
- 将快捷方式复制到用户的桌面文件夹
- 启动应用程序
当用户关闭应用程序时,快捷方式出现在桌面上。要再次启动应用程序,用户将双击快捷方式,并重复上述过程。
分发文件夹和文件的基本结构如下:
如图所示,在主分发文件夹中只有快捷方式和一个子文件夹。
子文件夹(此处:Files)仅包含三个文件:
- 应用程序文件 - accdb、acde 或 accdr 类型
- 快捷方式的图标文件(可选,但推荐)
- 脚本
扩展结构可以包括两组或多组快捷方式和子文件夹,例如:
- 分销\生产
- 分发\测试
分发给用户的快捷方式与上图中顶部列出的快捷方式相同。请记住,它是脚本文件的快捷方式,而不是 Microsoft Access 或应用程序文件的快捷方式。
要更新应用程序,只需更新子文件夹中的应用程序文件。当用户注销并稍后重新启动应用程序时,应用程序文件将被复制到用户的本地文件夹,覆盖之前的副本,然后启动新版本。这再简单不过了。
当然,也可以进行降级 ;将应用程序文件替换为以前的版本,仅此而已。
三、要求
要按照描述部署和运行您的 Access 应用程序,您将需要:
- 将Microsoft Access安装为完整安装或运行时
- 已授予用户完全权限 的本地文件夹路径
- 为注册表中 的 受信任位置设置一些安全设置
- 用于复制应用程序文件并创建桌面快捷方式的脚本
- 调用脚本的快捷方式
Microsoft Access runtime(运行时)
如何安装以及选择哪个版本对于流程和脚本并不重要。它是为 Microsoft Access 2010 创建的,应该适用于 2013 和 2019,并且已经过 2016/365 测试。
如何安装和配置其中任何一个 - 作为完整安装或作为运行时 - 超出了本文的范围。
本地文件夹
使用的佳文件夹路径是LocalAppData。 要查看它的位置,请在 Windows 资源管理器中键入%localappdata% :
并按Enter。它将解析为:
C:\Users\NameOfUserProfile\AppData\Local
在这里,您通常会创建一个子文件夹和一个子文件夹,例如:
\组织名称\应用程序名称
托管应用程序文件的本地副本。
使用上面列出的分发文件夹和文件示例名称,生成的本地结构将 - 除了桌面文件夹中的快捷方式文件 - 仅包含一个文件:
注册表设置
这些是特定于每个版本的 Microsoft Access,因此请注意。
脚本中的一行控制了这一点。默认情况下,它设置为适合Microsoft Access 2016和Microsoft Access 365:
' Environment specific constants.
'
' Expected version of Microsoft Access - the returned value of property:
' ? Access.Application.Version
Const AccessVersion = "16.0"
保存设置的注册表项(对于 16.0 版)将是:
HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Access\Security\
它将保存分配给上述本地文件夹的受信任位置的条目,并防止在启动应用程序时显示来自 Microsoft Access 的警告消息。
脚本
该脚本是用VBScript 编写的,看起来可能非常全面。但是,它并不复杂,并且内嵌注释解释了每一步。它执行的主要任务是:
- 验证/创建本地文件夹
- 将应用程序文件复制到本地文件夹和桌面的快捷方式
- 为 Microsoft Access 安全性编写注册表项
- 启动应用程序
完整清单是:
Option Explicit
' Launch script for a Microsoft Access application.
' Version 2.0.2
' 2019-01-15
' Cactus Data. Gustav Brock
' ---------------------------------------------------------------------------------
' This script file must be placed in a distribution folder, like:
' F:\Distribution\AppName
'
' That folder must have subfolder(s) for the app type(s).
' - for one app type only, for example:
' F:\Distribution\AppName\Files
' - for, say, three app *:
' F:\Distribution\AppName\Operations
' F:\Distribution\AppName\Test
' F:\Distribution\AppName\Development
'
' Specify the next constants for a resulting install path of:
' %LocalAppData%\OrgSubfolderName\AppSubfolderName\App*ubfolderName
' - for example resulting in:
' C:\Users\UserProfileName\AppData\Local\Organisation\AppName\Operations
' ---------------------------------------------------------------------------------
' ---------------------------------------------------------------------------------
' Environment specific constants.
'
' Expected version of Microsoft Access - the returned value of property:
' ? Access.Application.Version
Const AccessVersion = "16.0"
' ---------------------------------------------------------------------------------
' ---------------------------------------------------------------------------------
' Application specific constants.
'
' Source filename.
Const AppBaseName = "DMadresser"
' Extension name. Uncomment ONE extension name only.
'Const AppExtensionName = "accdb"
'Const AppExtensionName = "accde"
Const AppExtensionName = "accdr"
' Optional suffix.
Const AppNoColourSuffix = "NC"
' Local install folder names. Will be (sub)subfolders of %LocalAppData%.
Const OrgSubfolderName = "DM"
Const AppSubfolderName = "DM Administration"
' Shortcut name(s). Uncomment ONE folder name ONLY:
Const ShortcutBaseName = "DM Adresser"
'Const ShortcutBaseName = "DM Adresser Test"
' Title of the application when running. For TaskKill in subfunction KillTask.
Const AppWindowTitle = "DM ADRESSER"
' ---------------------------------------------------------------------------------
' ---------------------------------------------------------------------------------
' Installation specific constants.
' Distribution folder names. Uncomment ONE folder name ONLY:
Const App*ubfolderName = "Files"
'Const App*ubfolderName = "Development"
'Const App*ubfolderName = "Operations"
'Const App*ubfolderName = "Test"
' Indicate if the script is for the normal version (0) or a no-colour version (1):
Const NoColour = 0
' Force a close of an open application even if blocked by a modal message box.
Const ForceClose = True
' ---------------------------------------------------------------------------------
' ---------------------------------------------------------------------------------
' Script.
' Windows folder constants.
Const DESKTOP = &H10
Const LOCALAPPDATA = &H1C
' Extension of a shortcut.
Const ShortcutExtensionName = "lnk"
' Objects.
Dim FileSystemObject
Dim AppShell
Dim DesktopFolder
Dim LocalAppDataFolder
Dim LocalFolder
Dim RemoteFolder
' Variables.
Dim LocalFolderName
Dim RemoteFolderName
Dim DesktopFolderName
Dim LocalAppDataFolderName
Dim LocalAppDataOrgFolderName
Dim LocalAppDataOrgAppFolderName
Dim AppName
Dim AppExtension
Dim AppSuffix
Dim ShortcutName
Dim AppLocalPath
Dim AppRemotePath
Dim ShortcutExtension
Dim ShortcutLocalPath
Dim ShortcutRemotePath
Dim RegPath
Dim RegKey
Dim RegValue
Dim Value
' Create the Shell object and the File System Object.
Set FileSystemObject = CreateObject("Scripting.FileSystemObject")
Set AppShell = CreateObject("Shell.Application")
' Build distribution folder name.
RemoteFolderName = FileSystemObject.GetParentFolderName(WScript.ScriptFullName)
' Build filenames.
If NoColour = 1 Then
AppSuffix = AppNoColourSuffix
Else
AppSuffix = ""
End If
AppExtension = "." & AppExtensionName
AppName = AppBaseName & AppSuffix & AppExtension
ShortcutExtension = "." & ShortcutExtensionName
ShortcutName = ShortcutBaseName & AppSuffix & ShortcutExtension
' Enable in-line error handling.
On Error Resume Next
' Find user's Desktop and AppData\Local folder.
Set DesktopFolder = AppShell.Namespace(DESKTOP)
DesktopFolderName = DesktopFolder.Self.Path
Set LocalAppDataFolder = AppShell.Namespace(LOCALAPPDATA)
LocalAppDataFolderName = LocalAppDataFolder.Self.Path
' Uncomment to debug.
'WScript.Echo "Desktop: " & DesktopFolderName & vbCrLf & "LocalAppData: " & LocalAppDataFolderName
' Dynamic parameters.
LocalAppDataOrgFolderName = FileSystemObject.BuildPath(LocalAppDataFolderName, OrgSubfolderName)
LocalAppDataOrgAppFolderName = FileSystemObject.BuildPath(LocalAppDataOrgFolderName, AppSubfolderName)
LocalFolderName = FileSystemObject.BuildPath(LocalAppDataOrgAppFolderName, App*ubfolderName)
AppLocalPath = FileSystemObject.BuildPath(LocalFolderName, AppName)
ShortcutLocalPath = FileSystemObject.BuildPath(DesktopFolderName, ShortcutName)
' Permanent parameters.
AppRemotePath = FileSystemObject.BuildPath(RemoteFolderName, AppName)
ShortcutRemotePath = FileSystemObject.BuildPath(FileSystemObject.BuildPath(RemoteFolderName, ".."), ShortcutName)
' Verify/create the local folders.
If Not FileSystemObject.FolderExists(RemoteFolderName) Then
Call ErrorHandler("No access to " & RemoteFolderName & ".")
Else
Set RemoteFolder = FileSystemObject.GetFolder(RemoteFolderName)
' If the local folder does not exist, create the folder.
If Not FileSystemObject.FolderExists(LocalFolderName) Then
If Not FileSystemObject.FolderExists(LocalAppDataOrgFolderName) Then
Set LocalFolder = FileSystemObject.CreateFolder(LocalAppDataOrgFolderName)
If Not Err.Number = vbEmpty Then
Call ErrorHandler("Folder " & LocalAppDataOrgFolderName & " could not be created.")
End If
End If
If Not FileSystemObject.FolderExists(LocalAppDataOrgAppFolderName) Then
Set LocalFolder = FileSystemObject.CreateFolder(LocalAppDataOrgAppFolderName)
If Not Err.Number = vbEmpty Then
Call ErrorHandler("Folder " & LocalAppDataOrgAppFolderName & " could not be created.")
End If
End If
If Not FileSystemObject.FolderExists(LocalFolderName) Then
Set LocalFolder = FileSystemObject.CreateFolder(LocalFolderName)
If Not Err.Number = vbEmpty Then
Call ErrorHandler("Folder " & LocalFolderName & " could not be created.")
End If
End If
End If
Set LocalFolder = FileSystemObject.GetFolder(LocalFolderName)
End If
' Copy the distribution file to the local folder and the shortcut to the Desktop.
If Not FileSystemObject.FileExists(AppRemotePath) Then
Call ErrorHandler("The application file:" & vbCrLf & AppRemotePath & vbCrLf & "could not be found.")
Else
' First, close a running application - using the setting of constant ForceClose.
Call KillTask(AppWindowTitle)
' Wait while TaskKill is running to close the instance of the application.
Call AwaitProcess("taskkill.exe")
' Copy app to local folder.
If FileSystemObject.FileExists(AppLocalPath) Then
FileSystemObject.DeleteFile(AppLocalPath)
If Not Err.Number = 0 Then
If IsProcess("MSACCESS.EXE") Then
' The application may be blocked for closing by a modal message box.
MsgBox "Cannot update or reinstall the application while it is running.", vbCritical + vbOkOnly, AppWindowTitle
WScript.Quit
Else
Call ErrorHandler("The application file:" & vbCrLf & AppName & vbCrLf & "can not be refreshed/updated. It may be in use.")
End If
End If
End If
If FileSystemObject.FileExists(AppLocalPath) Then
Call ErrorHandler("The local application file:" & vbCrLf & AppLocalPath & vbCrLf & "could not be replaced.")
Else
FileSystemObject.CopyFile AppRemotePath, AppLocalPath
If Not Err.Number = vbEmpty Then
Call ErrorHandler("Application could not be copied to " & LocalFolderName & ".")
End If
End If
' Uncomment to debug.
'WScript.Echo "Shortcut remote: " & ShortcutRemotePath & vbCrLf & "Shortcut local: " & ShortcutLocalPath
' Copy shortcut.
FileSystemObject.CopyFile ShortcutRemotePath, ShortcutLocalPath
If Not Err.Number = vbEmpty Then
Call ErrorHandler("Shortcut could not be copied to your Desktop.")
End If
End If
' Write Registry entries for Microsoft Access security.
RegKey = "HKEY_CURRENT_USER\Software\Microsoft\Office\" & AccessVersion & "\Access\Security\"
RegValue = "VBAWarnings"
RegPath = RegKey & RegValue
Value = 1
Call WriteRegistry(RegPath, Value,"REG_DWORD")
RegKey = RegKey & "Trusted Locations\LocationLocalAppData\"
RegValue = "AllowSubfolders"
RegPath = RegKey & RegValue
Value = 1
Call WriteRegistry(RegPath, Value, "REG_DWORD")
RegValue = "Date"
RegPath = RegKey & RegValue
Value = Now
Value = FormatDateTime(Value, vbShortDate) & " " & FormatDateTime(Value, vbShortTime)
Call WriteRegistry(RegPath, Value, "REG_SZ")
RegValue = "Description"
RegPath = RegKey & RegValue
Value = "Local AppData"
Call WriteRegistry(RegPath, Value, "REG_SZ")
RegValue = "Path"
RegPath = RegKey & RegValue
Value = LocalAppDataFolderName & "\"
Call WriteRegistry(RegPath, Value, "REG_SZ")
' Launch the application.
If FileSystemObject.FileExists(AppLocalPath) Then
Call RunApp(AppLocalPath)
Else
Call ErrorHandler("The local application file:" & vbCrLf & AppLocalPath & vbCrLf & "could not be found.")
End If
Set RemoteFolder = Nothing
Set LocalFolder = Nothing
Set LocalAppDataFolder = Nothing
Set DesktopFolder = Nothing
Set AppShell = Nothing
Set FileSystemObject = Nothing
' Exit.
WScript.Quit
' Exit script.
' ---------------------------------------------------------------------------------
' ---------------------------------------------------------------------------------
' Supporting (sub)functions.
Sub RunApp(ByVal Filename)
Const vbNormalFocus = 1
Const WaitOnReturn = False
Dim Shell
Dim Command
Dim WindowStyle
' Open as default foreground application.
WindowStyle = vbNormalFocus
Set Shell = CreateObject("WScript.Shell")
Command = """" & Filename & """"
Shell.Run Command, WindowStyle, WaitOnReturn
Set Shell = Nothing
End Sub
Sub KillTask(ByVal WindowTitle)
Const vbMinimizedNoFocus = 7
Const WaitOnReturn = False
Const ForcedCloseOn = "/F"
Const ForcedCloseOff = ""
Dim Shell
Dim Command
Dim WindowStyle
Dim CloseStyle
' Run silently.
WindowStyle = vbMinimizedNoFocus
Set Shell = CreateObject("WScript.Shell")
If ForceClose = True Then
CloseStyle = ForcedCloseOn
Else
CloseStyle = ForcedCloseOff
End If
Command = "TaskKill.exe /FI ""WINDOWTITLE eq " & WindowTitle & """ " & CloseStyle
Shell.Run Command, WindowStyle, WaitOnReturn
Set Shell = Nothing
End Sub
Sub AwaitProcess(ByVal Process)
Dim Service
Dim Query
Dim Processes
Dim Count
Set Service = GetObject("winmgmts:root\cimv2")
Query = "select * from win32_process where name = '" & Process & "'"
Do
Set Processes = Service.Execquery(Query)
Count = Processes.Count
If Count > 0 Then
WScript.Sleep 300
End If
Loop Until Count = 0
Set Processes = Nothing
Set Service = Nothing
End Sub
Function IsProcess(ByVal Process)
Dim Service
Dim Query
Dim Processes
Dim Result
Set Service = GetObject("winmgmts:root\cimv2")
Query = "select * from win32_process where name = '" & Process & "'"
Set Processes = Service.Execquery(Query)
If Processes.Count > 0 Then
Result = True
Else
Result = False
End If
Set Processes = Nothing
Set Service = Nothing
IsProcess = Result
End Function
Sub WriteRegistry(ByVal RegPath, ByVal Value, ByVal RegType)
' RegType should be:
' "REG_SZ" for a string
' "REG_DWORD" for an integer
' "REG_BINARY" for a binary or boolean
' "REG_EXPAND_SZ" for an expandable string
Dim Shell
Set Shell = CreateObject("WScript.Shell")
Call Shell.RegWrite(RegPath, Value, RegType)
Set Shell = Nothing
End Sub
Sub ErrorHandler(Byval Message)
Set RemoteFolder = Nothing
Set LocalFolder = Nothing
Set LocalAppDataFolder = Nothing
Set DesktopFolder = Nothing
Set AppShell = Nothing
Set FileSystemObject = Nothing
MsgBox Message, vbExclamation + vbOkOnly, ShortcutBaseName
WScript.Quit
End Sub
' End script.
' ---------------------------------------------------------------------------------
特定环境的所有设置和脚本的行为都由脚本顶部的常量 控制。它们都经过仔细的评论,因此应该很容易使其按照您的要求运行。
如果您希望修改脚本而不是简单地调整常量或提示符,我强烈建议您为此使用Visual Studio Code,因为它很好地强调了关键字以及控制缩进,从这段代码中可以看出:
潜在阻塞
当然,必须允许用户运行 VBScript 才能使此设置生效。此外,Windows 10 有一个特殊选项可以阻止“未知应用程序”对桌面的更改。如果是这种情况,用户将看到一条本地化的滑入式消息,如下所示:
并且脚本将失败,因为它无法按预期运行。
捷径
这是非常基本的,可能看起来像这个例子:
虽然不是强制性的,但我强烈建议附上一个 图标文件(如图所示)。
四、Citrix环境
这种部署方法也适用于 Citrix 环境。这在上一篇文章中有介绍:
并且关于 Citrix 的评论仍然适用。实际上,这里介绍的脚本是原始脚本的改进版本。前面的脚本和这里列出的脚本之间的一个主要区别是,前面的脚本部署了应用程序文件的两个副本,而这个脚本——就像大多数场景的情况一样——只部署一个副本。
五、结论
通过使用此处描述的方法以及附加和呈现的脚本,您将拥有一个非常简单的方法来部署和更新对用户完全透明的 Microsoft Access 应用程序。此外,它几乎不需要任何维护。
六:下载
该脚本作为文本文件附加:Setup DMadresser.txt
下载后,将其重命名为具有vbs扩展名,例如:Setup YourApplication.vbs
我希望你觉得这篇文章有用。我们鼓励您在下面提出问题、报告任何错误或对此发表任何其他评论。
来源 https://zhuanlan.zhihu.com/p/462727629