首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用VBA保护VBAProject

使用VBA保护VBAProject
EN

Stack Overflow用户
提问于 2022-01-03 15:37:04
回答 1查看 518关注 0票数 -2

我有一个包含大量VBA的主工作簿,它从其他工作簿收集数据,操作这些数据,最后将数据输出写入一个新的工作簿,该工作簿本身包含一些VBA。此输出工作簿被发送给许多应该而不是能够更改或查看VBA的人。因此,我必须将VBAProject从视图中锁定。由于我的主工作簿的用户根本没有VBA技能,所以我不会让他们锁定VBAProject (在VBA编辑器:菜单工具/ VBAProject属性中)./保护/查看锁定项目/等等)。我宁愿使用VBA锁定VBAProject。我见过几个SendKeys做的。但是,我不喜欢使用SendKeys。相反,我更喜欢“真实的”VBA -,但是如何做到呢?也许通过使用一些Windows函数?--这一点我一点也不熟悉,但是如果我只需要复制/粘贴一些代码,就可以使用了。;-)

EN

回答 1

Stack Overflow用户

发布于 2022-01-11 13:03:06

最后,我提出了如下解决方案。它将在Excel 64位上运行,但可能很容易被更改为32位(参见代码中的建议)。我已经在Excel 2016上测试过了。

代码语言:javascript
运行
复制
' Helge V. Larsen (MSc, PhD)
' Helge@Engfred.dk
' HELA Consulting
' January 2022.

' Regarding Windows API: Very much inspired by the late Howard Kaikow:
' http://www.standards.com/Office/SetVBAProjectPassword.html
'
' Author: Howard Kaikow
' URL   : http://www.standards.com/
' Email : kaikow@standards.com
' Date  : April 2005

' This will run in Excel 64 bit.
' It will probably run in Excel 32 bit
' if you remove all "PtrSafe" and change all "LongPtr" to "Long".
' (I cannot test it since I do not have access to Exccel 32 bit.)
'
' Alternatively, you could use compiler directives
'     #If VBA7 Then
'     #Else
'     #End If
' to make it run in Excel 32 and 64 bit    .

Option Explicit

' API constants
Private Const BM_CLICK As Long = &HF5&
Private Const BM_SETCHECK As Long = &HF1&
Private Const BST_CHECKED As Long = &H1&
Private Const EM_REPLACESEL As Long = &HC2&
Private Const HWND_TOPMOST As Long = -1
Private Const SWP_NOACTIVATE As Long = &H10&
Private Const SWP_NOMOVE As Long = &H2&
Private Const SWP_NOSIZE As Long = &H1&
Private Const SWP_SHOWWINDOW As Long = &H40&
Private Const TCM_SETCURFOCUS As Long = &H1330&

' API functions and subs
Private Declare PtrSafe Function EnumChildWindows Lib "user32" _
    (ByVal hWndParent As LongPtr, ByVal lpEnumFunc As LongPtr, ByVal lParam As Long) As Long
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function GetDlgItem Lib "user32.dll" _
    (ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long) As Long
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare PtrSafe Function SetFocusAPI Lib "user32" Alias "SetFocus" _
    (ByVal hWnd As Long) As Long
Private Declare PtrSafe Sub SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _
    ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long)

Private hWndProjectProperties As LongPtr

Sub HVL_Lock_VBProject()
    
    ' Protect VBProject in workbook.
    ' The workbook is opened in another instance of Excel.
    
    Dim appExcel As Excel.Application
    Dim wbkExcel As Excel.Workbook
    
    Dim aFile As String
    Dim Pass  As String
    
    aFile = HVL_GetFile_Dialog("Browse for Excel workbook", ThisWorkbook.Path, "Excel files, *.xl*,")
    If aFile = vbNullString Then Exit Sub
    
    Set appExcel = New Excel.Application
    appExcel.Visible = False
    
    Set wbkExcel = appExcel.Workbooks.Open(aFile)
    
    If wbkExcel.VBProject.Protection = vbext_pp_none Then
       Pass = HVL_Get_PassWord
       If Pass = vbNullString Then GoTo Exit_Sub
       SetPassword wbkExcel.VBProject, Pass
    Else ' vbext_pp_locked
       MsgBox "The VBproject in" & vbCr & _
              aFile & vbCr & _
              "is protected." & vbCr & vbCr & _
              "Cannot change Project Password.", _
              vbInformation, _
              "Information"
       GoTo Exit_Sub
    End If
    
    wbkExcel.Save
    wbkExcel.Close False
    
    MsgBox "The VBproject in" & vbCr & _
           aFile & vbCr & _
           "has been locked.", _
           vbInformation, _
           "Information"
    
Exit_Sub:

    appExcel.Quit
    
    Set appExcel = Nothing
    Set wbkExcel = Nothing

End Sub

Sub SetPassword(ByRef aVBProject As VBProject, ByVal strPassword As String)

    ' Author: Howard Kaikow
    ' URL   : http://www.standards.com/
    ' Email : kaikow@standards.com
    ' Date  : April 2005
    ' spy++ was used to find the Control IDs in Project Properties dialog
    
    ' Changed by Helge V. Larsen.

    Const ControlIDConfirmPassword As Long = &H1556&
    Const ControlIDLockProject As Long = &H1557&
    Const ControlIDOK As Long = &H1&
    Const ControlIDPassword As Long = &H1555&
    Const ControlIDSysTabControl32 As Long = &H3020&
    
    Dim Ctrl As Office.CommandBarControl
    Dim hWnd As Long
    Dim hWndLockProject As Long
    Dim hWndPassword As Long
    Dim hWndConfirmPassword As Long
    Dim hWndOK As Long
    Dim hWndSysTabControl32 As Long
    Dim strCaption As String
    
    With aVBProject
        strCaption = .Name & " - Project Properties"
        With .VBE
            ' Find Project Properties dialog
            Set Ctrl = .CommandBars.FindControl(ID:=2578)
            ' Display Project Properties dialog
            Ctrl.Execute
            Set Ctrl = Nothing
        End With
    End With
    
    ' Get hWnd for Project Properties dialog
    hWndProjectProperties = FindWindow(vbNullString, strCaption)
    If hWndProjectProperties = 0 Then
        Exit Sub
    End If

    ' Get hWnd for OK button in Project Properties dialog
    hWndOK = GetDlgItem(hWndProjectProperties, ControlIDOK)
    
    ' Get hWnd for Tab Control in Project Properties dialog
    hWndSysTabControl32 = GetDlgItem(hWndProjectProperties, ControlIDSysTabControl32)

    'Move to Protection tab
    SendMessage hWndSysTabControl32, TCM_SETCURFOCUS, 1, ByVal 0&

    ' Must reset hWndProjectProperties probably because tab changed.
    EnumChildWindows ByVal hWndProjectProperties, AddressOf EnumChildProc, ByVal 0
    
    ' Get hWnd for Password Edit control in Project Properties dialog
    hWndPassword = GetDlgItem(hWndProjectProperties, ControlIDPassword)
    
    ' Get hWnd for Confirm Password Edit control in Project Properties dialog
    hWndConfirmPassword = GetDlgItem(hWndProjectProperties, ControlIDConfirmPassword)
    
    ' Get hWnd for Lock Project checkbox control in Project Properties dialog
    hWndLockProject = GetDlgItem(hWndProjectProperties, ControlIDLockProject)

    ' Lock project for &viewing
    SendMessage hWndLockProject, BM_SETCHECK, BST_CHECKED, 0

    ' &Password
    SendMessage hWndPassword, EM_REPLACESEL, vbTrue, ByVal strPassword

    ' &Confirm password
    SendMessage hWndConfirmPassword, EM_REPLACESEL, vbTrue, ByVal strPassword

    'OK button
    SetFocusAPI hWndOK
    SendMessage hWndOK, BM_CLICK, 0&, 0&
    
End Sub

Function EnumChildProc(ByVal hWnd As LongPtr, ByVal lParam As Long) As Long
    hWndProjectProperties = hWnd
    ' Do not recurse
    EnumChildProc = 0
End Function

Function HVL_GetFile_Dialog(Optional DialogTitle As String, _
                            Optional InitDirectory As String, _
                            Optional Filter As String, _
                            Optional InitView As Office.MsoFileDialogView = msoFileDialogViewDetails) As String

    ' Filter: e.g. "Data bases, *.mdb; *.accdb"

    Dim Filter_Arr As Variant
    Dim ViewType   As Office.MsoFileDialogView

    With Application.FileDialog(msoFileDialogFilePicker)
        .InitialView = InitView
        .AllowMultiSelect = False
         
         If DialogTitle <> vbNullString Then .Title = DialogTitle
         
         If Dir(InitDirectory, vbDirectory) <> vbNullString Then
           .InitialFileName = InitDirectory
         Else
           .InitialFileName = CurDir
         End If
         
         If Filter <> vbNullString Then
            Filter_Arr = Split(Filter, ",")
           .Filters.Add Trim(Filter_Arr(0)), Trim(Filter_Arr(1)), 1
         End If
         
         If .Show = True Then
             HVL_GetFile_Dialog = .SelectedItems(1)
         Else
             HVL_GetFile_Dialog = vbNullString
         End If
         
    End With

End Function

Function HVL_Get_PassWord()

    Dim Pass1 As String
    Dim Pass2 As String

    Pass1 = InputBox("Enter VBproject password:", "Lock VBroject")
    If Pass1 = vbNullString Then GoTo No_Password
    
    Pass2 = InputBox("Caution: If you loose or forget the password," & vbCr & _
                     "it cannot be recovered. It is advisable to keep" & vbCr & _
                     "a list of passwords and their corresponding" & vbCr & _
                     "workbook names in a safe place." & vbCr & _
                     "(Remember that passwords are case-sensitive.)" & vbCr & vbCr & _
                     "Confirm VBproject password:", _
                     "Lock VBproject")
    If Pass2 = vbNullString Then GoTo No_Password
    
    If Pass1 <> Pass2 Then
       MsgBox "Confirmation password is not identical!", vbCritical, "Error"
       GoTo No_Password
    End If
    
    HVL_Get_PassWord = Pass1
    
    Exit Function
    
No_Password:
    HVL_Get_PassWord = vbNullString
    
End Function
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70568084

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档