Copying sheets while preserving digital signatures

前端 未结 1 1983
说谎
说谎 2020-12-17 23:40

-- Edit: this is now part of the bigger question of how to reliably move sheets about in this question\'s context --

(Note: during preparing this post and testing so

相关标签:
1条回答
  • 2020-12-18 00:28

    It's a lot to take in, and I do not pretnd this will answer will solve all your problems. But I once wrote a function called SoftLink which would take up to 4 parameters (i) Boolean: CellRef (or NamedRange) (ii) String: Range (iii) String: WorksheetName (iv) String: WorkbookName which would break any link with any cells and then you resolve the string parameters in VBA code.

    There no doubt a performance hit with this approach but it is one way to solve Link hell.

    Example calling formulas

    =softlink(FALSE,"Foo")
    =softlink(TRUE,"C4","Sheet1","Book2")
    =softlink(TRUE,"D5","Sheet2")
    

    and I have knocked up from memory an implementation. I have a phobia of On Errors .... so forgive some strange loopings in the subroutines.

    Option Explicit
    
    Function SoftLink(ByVal bIsCell As Boolean, ByVal sRangeName As String, _
                        Optional sSheetName As String, Optional sBookName As String) As Variant
    
        Dim vRet As Variant
        If Len(sRangeName) = 0 Then vRet = "#Cannot resolve null range name!": GoTo SingleExit '* fast fail
    
    
        Dim rngCaller As Excel.Range
        Set rngCaller = Application.Caller
    
        Dim wsCaller As Excel.Worksheet
        Set wsCaller = rngCaller.Parent
    
        Dim wbCaller As Excel.Workbook
        Set wbCaller = wsCaller.Parent
    
        Dim wb As Excel.Workbook
    
        If Len(sBookName) > 0 Then
            vRet = FindWorkbookWithoutOnErrorResumeNext(sBookName, wb)
            If Len(vRet) > 0 Then GoTo ErrorMessageExit
        Else
            Set wb = wbCaller
        End If
        Debug.Assert Not wb Is Nothing
        Dim ws As Excel.Worksheet
        If Len(sSheetName) > 0 Then
            vRet = FindWorksheetWithoutOnErrorResumeNext(wb, sSheetName, ws)
            If Len(vRet) > 0 Then GoTo ErrorMessageExit
    
        Else
            Set ws = wsCaller
        End If
    
        Dim rng As Excel.Range
        If bIsCell Then
            vRet = AcquireCellRange(ws, sRangeName, rng)
            If Len(vRet) > 0 Then GoTo ErrorMessageExit
        Else
            vRet = AcquireNamedRangeWithoutOERN(ws, sRangeName, rng)
            If Len(vRet) > 0 Then GoTo ErrorMessageExit
        End If
    
        SoftLink = rng.Value2
    SingleExit:
        Exit Function
    ErrorMessageExit:
        SoftLink = vRet
        GoTo SingleExit
    End Function
    
    Function AcquireCellRange(ByVal ws As Excel.Worksheet, ByVal sRangeName As String, ByRef prng As Excel.Range) As String
    
        On Error GoTo FailedCellRef
        Set prng = ws.Range(sRangeName)
    
    SingleExit:
        Exit Function
    FailedCellRef:
        AcquireCellRange = "#Could not resolve range name '" & sRangeName & "' on worksheet name '" & ws.Name & "' in workbook '" & ws.Parent.Name & "'!"
    
    End Function
    
    
    Function AcquireNamedRangeWithoutOERN(ByVal ws As Excel.Worksheet, ByVal sRangeName As String, ByRef prng As Excel.Range) As String
    
        '* because I do not like OERN
        Dim oNames As Excel.Names
    
        Dim bSheetScope As Long
        For bSheetScope = True To False
    
            Set oNames = VBA.IIf(bSheetScope, ws.Names, ws.Parent.Names)
    
            Dim namLoop As Excel.Name
            For Each namLoop In oNames
                If VBA.StrComp(namLoop.Name, sRangeName, vbTextCompare) = 0 Then
    
                    Set prng = ws.Range(sRangeName)
                    GoTo SingleExit
                End If
    
            Next
        Next
    
    ErrorMessageExit:
        AcquireNamedRangeWithoutOERN = "#Could not resolve range name '" & sRangeName & "' on worksheet name '" & ws.Name & "' in workbook '" & ws.Parent.Name & "'!"
    SingleExit:
        Exit Function
    
    End Function
    
    Function FindWorksheetWithoutOnErrorResumeNext(ByVal wb As Excel.Workbook, ByVal sSheetName As String, ByRef pws As Excel.Worksheet) As String
        '* because I do not like OERN
        Dim wsLoop As Excel.Worksheet
        For Each wsLoop In wb.Worksheets
            If VBA.StrComp(wsLoop.Name, sSheetName, vbTextCompare) = 0 Then
                Set pws = wsLoop
    
                GoTo SingleExit
            End If
    
        Next wsLoop
    ErrorMessageExit:
        FindWorksheetWithoutOnErrorResumeNext = "#Could not resolve worksheet name '" & sSheetName & "' in workbook '" & wb.Name & "'!"
    SingleExit:
        Exit Function
    End Function
    
    
    Function FindWorkbookWithoutOnErrorResumeNext(ByVal sBookName As String, ByRef pwb As Excel.Workbook) As String
        '* because I do not like OERN
        Dim wbLoop As Excel.Workbook
        For Each wbLoop In Application.Workbooks
            If VBA.StrComp(wbLoop.Name, sBookName, vbTextCompare) = 0 Then
                Set pwb = wbLoop
    
                GoTo SingleExit
            End If
    
        Next wbLoop
    ErrorMessageExit:
        FindWorkbookWithoutOnErrorResumeNext = "#Could not resolve workbook name '" & sBookName & "'!"
    SingleExit:
        Exit Function
    End Function
    
    0 讨论(0)
提交回复
热议问题