链接到受密码保护的工作簿

时间:2017-11-02 06:28:31

标签: excel vba hyperlink passwords

这是我想要做的。我没有成功地进行了广泛的搜索。 我有两个 spreadhseets 。 第一册 Book2的密码为open = "green"

第1册在单元格A1 ='C:\[Book2.xlsm]Sheet1'!A1

中有一个公式

我希望我的宏将Book1单元格中的公式 A1复制到A2 ,以便从受密码保护的Book2中获取ref A2。问题是它不断弹出来询问密码。我想在不打开Book2的情况下自动输入该密码。粘贴新公式后,我无法立即通过密码弹出。

任何帮助非常感谢。代码I到目前为止使用:

Sub Macro1()
    Range("A1").Select
    Selection.Copy
    Range("A2").Select
    ActiveSheet.Paste

    UpDateLinks

End Sub

Sub UpDateLinks()
    Const PWord As String = "green"
    Dim xlLinks
    Dim i As Integer
    xlLinks = ThisWorkbook.LinkSources(xlExcelLinks)
    If Not IsEmpty(xlLinks) Then
        For i = 1 To UBound(xlLinks)
            SendKeys PWord & "{Enter}"
            ThisWorkbook.UpdateLink Name:=xlLinks(i)
        Next i
    End If
End Sub

2 个答案:

答案 0 :(得分:0)

您可以在单个工作簿中实现此目的。将数据表的可见属性设置为xlVeryHidden,然后为VBA设置密码。然后无法从用户界面取消隐藏工作表

答案 1 :(得分:0)

问题在于时间问题:在您致电UpdateLink(或编写带有链接的公式)之前,密码对话框不会显示,到那时您的SendKeys已经很久了,不见了。另一方面,一旦密码对话框打开,VBA就会卡在该行上,并且Excel有效挂起,直到有人或某事输入密码并单击确定(或取消,导致UpdateLink出错)。

因此,在调用UpdateLink(或编写公式)之前,需要在Excel线程外部运行某些东西(vbscript,exe或其他)。您将希望传递Excel实例句柄的“某些内容”以及所需的密码。我写了一个可执行文件,导致这个VBA调用exe然后调用UpdateLink:

Public Sub UpdateLinksIntoPasswordProtectedWorkbook()
Const pwd As String = "WhateverThePwdIs"
'call the EXE passing the hWnd and the pwd
Shell """c:\SomeFolders\SpyUpdateLinkPwdDialog.exe"" " & Application.hWnd & " " & pwd
'set the new formula
Range("A2").Formula ="'C:\[Book2.xlsm]Sheet1'!A1"
'or alternatively in other situations call UpdateLink
ThisWorkbook.UpdateLink "c:\Whatever\PasswordProtectedWorkbook.xlsx"
End Sub

可执行文件监视该Excel实例的子窗口的下一个30秒,该子窗口具有类'bosa_sdm_XL9'(使用Spy ++发现此名称),然后将密码填充到该对话框中并单击其OK按钮。链接已更新,然后VBA可以从那里继续。

可执行文件是使用UIAutomation(更具体地说,Windows Kit中的UIAComWrapper)编写的,首先立即将焦点设置回Excel实例,然后在接下来的30秒左右每秒查询该Excel实例的子节点:

/* this is critical: switch focus back to the Excel instance that called me */
AutomationElement aeExcel = AutomationElement.FromHandle(Program.xlwHnd);

然后用定时方法:

/* the password dialog class name is bosa_sdm_XL9 */
AutomationElementCollection aeXLPwdWindow = aeExcel.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "bosa_sdm_XL9"));
if (aeXLPwdWindow.Count > 0)
        {
            AutomationElementCollection aePwdBox = aeXLPwdWindow[0].FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "EDTBX"));
            AutomationElementCollection aeOkButton = aeXLPwdWindow[0].FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "OK"));
            if (aePwdBox.Count > 0 && aeOkButton.Count > 0)
            {
                /* UIAutomation? couldn't get it to work */
                SendMessage(new IntPtr(aePwdBox [0].Current.NativeWindowHandle), WM_SETTEXT, 0, new StringBuilder(Program.pwd));
                object vp;
                /* UIAutomation click the button */
                if (aeOkButton[0].TryGetCurrentPattern(InvokePatternIdentifiers.Pattern, out vp))
                {
                    ((InvokePattern)vp).Invoke();
                    attempts = 30; //stop trying after 30 seconds
                    return;
                }
            }
        }