一、什么是office安全级别限制
我们用EXCEL或access为平台,开发项目并分发给客户使用时,会遇到因默认安全级别限制,而使项目不能顺畅运行的情况,这主要是因为office为了防止VBA编写的宏病毒或恶意代码的侵害,而提供的一种安全预防措施。
以2003版access为例,其宏安全级别分为:高、中、低三个级别(见图1):
高:只允许运行可靠来源签署的宏,未经签署的宏会自动取消。所谓签署的宏就是自定义的数字签名(关于如何建立自己的数字签名大家可以参看有关资料)。只有通过这个数字签名的认证才能通过此安全级别,否则项目将无法运行。
中:您可以选择是否运行可能不安全的宏。这一级别会在项目运行时弹出警示对话框,让你确认所运行的项目的宏是否安全,点确定则允许运行,取消则取消运行。
低:这三个安全级别中最低的级别,这一级别对于所有运行VBA项目不进行强制认证、拦截或给出警告提示,但这一设置有可能放任宏病毒的侵害。
(图1)
二、避开安全级别限制方法潜析
安全级别限制虽然为我们预防宏病毒提供了一定保障,但这位忠实的监护者过于热心,带给我们的不一定都是愉悦,因为它同时也限制了正常项目的运行。有什么办法能让我们避开安全级别的限制,确保我们开发项目的顺畅运行呢?
取消安全级别限制的方法论坛中见到不少,大家仁者见仁、智者见智,但总体来说无外乎三种:
1、 通过安全级别对话框,手动将安全级别设定为最低及可
2、 建立自己VBA项目数字证书,然后在VBA编辑器中设置引用该证书,就建立了属于你自己的宏签名。
3、 修改access安全级别在注册表中有关键值,将对应键值设定为:1。修改注册表的方法有很多种,可以通过手动,或是编程,还有在项目打包发布工具修改键值。
注册表中对应键值:
虽然,以上三种方法都能避开安全级别的限制,但从利于项目分发角度来说,本人倾向于第三种通过编程修改注册表的方法。
HKEY_CURRENT_USER\Software\Microsoft\Office\11.0\access\Security\Level
键值: = 1 为:低 = 2 为:中 = 3 为:高
以上啰嗦这么多,各位也许会说本文有点文不对题,大有挂羊头买狗肉这嫌,哈哈。各位不用心急,以上所述主要是让大家对于安全级别有个初步的印象,同时也是为说明本人为何倾向于选择第三种方法(代码修改注册表键值)的原委。
闲话少说,下面我们就进入本文的正题,即:如何通过程序或代码方法修改安全级别注册表键值。
三、如何用VB避开安全级别限制并启动access项目
在进入正题之前,再说几句题外话。即:为什么不用access自身的VBA来编程修改注册表安全级别对应键值而选VB来实现操作。
大家也许听过“能医不自医”俗语,ACCESS就如此 “能医”,虽VBA编程能实现修改注册表解除安全级别限制,但却因自身受安全级别限制影响,而无法运行VBA,又何以来修改安全级别。而VB工程不受VBA安全限制,就无此之忧,而且编译后的EXE直接启动ACCESS项目,让你的access项目更显专业,这就是我为什么选定VB的理由。下面正式进入正题。
用VB编程需解决的三个问题:
1、如何操作注册表。操作注册表的方法通常是运用API来进行实现,本文主要运用VBS对象方法操作注册表。
读、写注册表自定函数源码如下:
Option Explicit
'定义脚本对象
Private ER_CrpShell As Object
'------------------------------------------------------
'功 能: 读取注册表指路径键值
'输 入: strRegKey 字符串变量,指定注册表键值路径
'输 出: RegRead 长整型变量,输出所获得键值
'------------------------------------------------------
Public Function RegRead(strRegKey As String) As Long
On Error Resume Next
Set ER_CrpShell = CreateObject("WScript.Shell")
RegRead = ER_CrpShell.RegRead(strRegKey)
Set ER_CrpShell = Nothing
End Function
'------------------------------------------------------
'功 能: 在指定注册表路径写入键值
'输 入: strRegKey 字符串变量,指定注册表键值路径
' intRegVal 整型变量,输入键值
'输 出: 无
'------------------------------------------------------
Public Function RegWrite(strRegKey As String, intRegVal As Integer)
On Error Resume Next
Set ER_CrpShell = CreateObject("WScript.Shell")
ER_CrpShell.RegWrite strRegKey, intRegVal, "REG_DWORD"
Set ER_CrpShell = Nothing
End Function
2、动态读取Access版本号(适用于2003-97版本)。只有实现动态读取Access版本号,才能确保项目发布中根据每台机子所安装的access版本不同,而正确找到键值所在位置。
动态读取access版本号源码:
Dim strRegSec As String '字符串变量,安全设置键值所在注册表路径
源码说明:
Dim strVer As String '当前access版号字符串变量
Dim objWord As Object 'Word对象变量
On Error Resume Next
'创建Word对象
Set objWord = CreateObject("word.Application.8")
'获得当前office版号
strVer = objWord.Version
'退出Word,并释放内存
objWord.Quit
Set objWord = Nothing
'将注表路径赋值给变量
strRegSec = "HKEY_CURRENT_USER\Software\Microsoft\Office\" & _
strVer & "\access\Security\Level"
'RegWrite 自定义函数,用以写入键值操作
'键值1为低,2为中,3为高
RegWrite strRegSec, 1
获取ACCESS版本号的通常方法:通过返回access对象,再通过Version属性获取版号,详见源码:
Dim strVer As String '当前access版号字符串变量
但此法需要一个前提,就是必须先启动ACCESS项目,换句话说也就是ACCESS处于启动状态,可这就回到了前面我们所说“能医不自医”的老问题上了。假如ACCESS设定了最高安全级别,而使ACCESS项目无法正常启动,也就无从通过其 Version 属性获取当前access的版本号。
Dim objaccess As Object 'Word对象变量
'返回access对象引用
Set objAccess = GetObject (,"access.Application")
'获得当前office版号,赋值变量
strVer = objaccess.Version
不过,好在OFFICE家族成员众多,别看access和EXCEL防犯严密,但百密终有一疏,我们可以通过避实就虚的方法,达成曲线救国之目的,也就是通过Word 来获取版本号。见如下源码:
Dim strVer As String '当前access版号字符串变量
虽然,Word 也提供了宏安全级别设置,但经我测试,无论Word安全级别设置为什么级别,都不会影响它的正常启动,这就为我们获取版本号亮了绿灯,这也是为什么我在代码中用Word而不是access的原因。
Dim objWord As Object 'Word对象变量
'创建Word对象
Set objWord = CreateObject("word.Application.8")
'获得当前office版号
strVer = objWord.Version
3、VB编程启动access项目。本文主要讲的是通过Shell方法启动对象(注意必须引用 SHELL32.DLL 链接库)。源码如下:
Shell 方法启动对象源码:
Dim MsShell As New Shell '定义新的Shell类
如果我们解决好了上述三个问题,那么我们就完全可以用VB建一个工程并编译EXE,来避开安全级别限制启动access项目就不难了
Dim isFile as String '文件所在路径
'当前路径及mdb文件名
isFile = App.Path & "\项目名称.mdb"
'通过Shell打开指定mdb文件
MsShell.Open (isFile)