【问题标题】:Excel only when VBA is enabled it should be possible to save the file, possible?只有在启用 VBA 时 Excel 才应该可以保存文件,可能吗?
【发布时间】:2018-05-23 18:21:35
【问题描述】:

我创建了一个具有三个权限级别的文件。
系统会提示您在用户窗体上输入密码,然后您将获得管理员权限、读/写或只读权限。
这很好用,除非您不启用宏。

如果您不启用提示用户表单的宏,并且未设置权限,则您拥有完全访问权限。

我看到您可以使用启动屏幕,但要使其正常工作,您需要根据我的理解保存工作簿?
它们的基本概念是在关闭隐藏工作表和取消隐藏启动屏幕之前,然后保存工作簿。 但是如果用户犯了一个错误,什么要关闭而不保存并稍后重新打开呢?文件在所有工作表可见的情况下关闭?

所以我想也许我可以使用“资源管理器->右键单击->属性->只读”属性作为额外的保护层?

我找到了这些功能。

ActiveWorkbook.ChangeFileAccess Mode:=xlreadonly
ActiveWorkbook.ChangeFileAccess Mode:=xlreadwrite 

但我尝试了 readonly 行,它确实设置为只读,文件无法保存。
然后我关闭工作簿而不保存并再次打开。但似乎该属性没有在文件的属性中设置,因为它没有被勾选,当我打开文件时我可以保存它。

还有其他方法可以解决这个问题吗?
我想对用户“强制”VBA,或者确保在没有 VBA 的情况下打开文件时他/她无法保存文件。

【问题讨论】:

  • 强制用户启用宏的唯一方法是将文件另存为加载项并将其加载到加载项集合中。
  • 如果文件是加载项,每个用户将在他们的加载项文件夹中拥有自己的文件副本。那是行不通的。这个想法是共享同一个文件。
  • 您可以使用插件在用户之间共享数据(不是文件);)我之前一直在成功。
  • 我之前确实考虑过,但文件很大。它有大约 20 张带有单元格颜色的表格和大约 6 MB 的数据。将数据外部存储在不同的文件中会非常繁重。但是是的,我之前也做过类似的事情。
  • 这(20 张纸、彩色单元格等)没有任何改变。我建议将Bussines Logic LayerData Access Layer 分开。这就是OOP 的力量。

标签: vba excel


【解决方案1】:

我找到了一个似乎可行的解决方案。

您可以在Workbook_BeforeClose 中使用此行在文件属性中将文件设为只读。

SetAttr Application.ActiveWorkbook.FullName, vbReadonly

这将在属性中设置标记,Excel 会注意到文件被写保护。

然后在Workbook_Open() (或者在我的情况下,当权利已经建立时)

SetAttr Application.ActiveWorkbook.FullName, vbReadwrite
ActiveWorkbook.ChangeFileAccess Mode:=xlReadWrite

第一行删除了文件属性中的勾号,但 Excel 仍将文件“记住”为只读文件。
第二行将告诉 Excel 使其成为 ReadWrite 并且文件再次正常工作。

【讨论】:

    【解决方案2】:

    这是一个Adreas' 复杂的方法,但不会像技术娴熟的普通用户右键单击文件并弹出“属性”面板一样存在风险.

    创建 2 个新工作表。其中之一设置为xlVeryHidden - 对于下面的示例,我将其称为hsSheetStatus。另一个,用一个很好的大通知告诉你的倒霉的奴才同事启用宏,将改变可见性。我称它为hsEnableNotice

    然后我有一个宏来显示 hsEnableNotice 隐藏所有其他工作表(将它们的可见性和 ActiveSheet 存储在 hsSheetStatus 上),以及第二个宏来执行相反的操作(从 hsSheetStatus 恢复可见性/ActiveSheet)并将它们设置为在Workbook_BeforeSaveWorkbook_AfterSaveWorkbook_Open 上运行:

    Option Explicit
    
    Private Sub Workbook_AfterSave(ByVal Success As Boolean)
        UnlockAndShow
    End Sub
    
    Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
        LockAndHide
    End Sub
    
    Private Sub Workbook_Open()
        UnlockAndShow
    End Sub
    
    Private Sub LockAndHide()
        Dim lSheet As Long, ActiveName As String
        Application.ScreenUpdating = False
        Application.EnableEvents = False
        ActiveName = ThisWorkbook.ActiveSheet.Name
        hsEnableNotice.Visible = xlSheetVisible
        hsEnableNotice.Activate
    
        hsSheetStatus.Range(hsSheetStatus.Cells(1, 1), hsSheetStatus.Cells(hsSheetStatus.Rows.Count, 1)).EntireRow.Delete
    
        For lSheet = 1 To ThisWorkbook.Sheets.Count 'By using Sheets instead of Worksheets, we include Charts etc
            hsSheetStatus.Cells(lSheet, 1).Value = ThisWorkbook.Sheets(lSheet).Name
            hsSheetStatus.Cells(lSheet, 2).Value = ThisWorkbook.Sheets(lSheet).Visible
            If ThisWorkbook.Sheets(lSheet).Name = ActiveName Then hsSheetStatus.Cells(lSheet, 3).Value = 1
            If ThisWorkbook.Sheets(lSheet).Name <> hsEnableNotice.Name Then ThisWorkbook.Sheets(lSheet).Visible = xlSheetVeryHidden
        Next lSheet
    
        ThisWorkbook.Protect Password:="ThisIsMyPassword.ThereAreManyLikeIt,ButThisOneIsMine.", Structure:=True, Windows:=False
        Application.EnableEvents = True
    End Sub
    
    Private Sub UnlockAndShow()
        Dim WasSaved As Boolean, lSheet As Long, lMax As Long
        WasSaved = ThisWorkbook.Saved
        Application.ScreenUpdating = False
        Application.EnableEvents = False
    
        lMax = hsSheetStatus.Cells(hsSheetStatus.Rows.Count, 1).End(xlUp).Row
    
        ThisWorkbook.Unprotect Password:="ThisIsMyPassword.ThereAreManyLikeIt,ButThisOneIsMine."
        For lSheet = 1 To lMax
            ThisWorkbook.Sheets(hsSheetStatus.Cells(lSheet, 1).Value).Visible = hsSheetStatus.Cells(lSheet, 2).Value
            If hsSheetStatus.Cells(lSheet, 3).Value = 1 Then ThisWorkbook.Sheets(hsSheetStatus.Cells(lSheet, 1).Value).Activate
        Next lSheet
    
        hsSheetStatus.Visible = xlSheetVeryHidden
        hsEnableNotice.Visible = xlSheetVeryHidden
    
        Application.EnableEvents = True
        Application.ScreenUpdating = True
        ThisWorkbook.Saved = WasSaved
    End Sub
    

    【讨论】:

    • 我会看看它,但我想我之前发现了这种方法的弱点。我一有时间就会试一试。可能今天不是为了提醒您。
    • 它确实有效。我错了。您使用了保存前和保存后。我没想到。我在关闭之前就在想,那是行不通的。最后我使用了这两种方法的组合。我显示了一个闪屏,但工作簿没有完全锁定,仍然有一些工作表可见,并且工作簿在属性中是只读的。我知道你可以绕过它。但是,如果不应该保存文件的人这样做了。我会和那个人聊一聊。
    猜你喜欢
    • 1970-01-01
    • 2012-10-12
    • 2018-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 2019-08-31
    相关资源
    最近更新 更多