Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
VBA文档中链接对象的文件路径列表_Vba_Excel_Ms Word - Fatal编程技术网

VBA文档中链接对象的文件路径列表

VBA文档中链接对象的文件路径列表,vba,excel,ms-word,Vba,Excel,Ms Word,我有许多大型Microsoft Word文档,其中包含许多Microsoft Excel电子表格中的链接文件。打开Word文档时,即使未选中“打开时更新链接文件”选项: Word仍然通过打开和关闭每个链接的相关excel电子表格来检查每个链接的来源(因此对于x个链接,即使来自同一电子表格,Word也会打开和关闭电子表格x次)。这意味着打开文档需要很长的时间 我发现,如果包含链接对象源的电子表格已经打开,文档打开得更快,因此Word不会一直打开、关闭或重新打开它们 到目前为止,我的一个解决方案是

我有许多大型Microsoft Word文档,其中包含许多Microsoft Excel电子表格中的链接文件。打开Word文档时,即使未选中“打开时更新链接文件”选项:

Word仍然通过打开和关闭每个链接的相关excel电子表格来检查每个链接的来源(因此对于x个链接,即使来自同一电子表格,Word也会打开和关闭电子表格x次)。这意味着打开文档需要很长的时间

我发现,如果包含链接对象源的电子表格已经打开,文档打开得更快,因此Word不会一直打开、关闭或重新打开它们

到目前为止,我的一个解决方案是创建链接对象的所有文件路径的列表,通过以下VBA代码完成:

Sub TypeArray()

Dim List(), Path As String
Dim i, x As Integer
Dim s As InlineShape
Dim fso As FileSystemObject, ts As TextStream

Set fso = New FileSystemObject
Set ts = fso.OpenTextFile("C:\MyFolder\List.txt", 8, True)

With ts
    .WriteLine (ActiveDocument.InlineShapes.Count)
End With

For Each s In ActiveDocument.InlineShapes
        Path = s.LinkFormat.SourcePath & "\" _
        & s.LinkFormat.SourceName
        With ts
            .WriteLine (Path)
        End With
Next s
End Sub

'--------------------------------------------------------------------------------------
Private Sub WriteStringToFile(pFileName As String, pString As String)

    Dim intFileNum As Integer

    intFileNum = FreeFile

    Open pFileName For Append As intFileNum
    Print #intFileNum, pString
    Close intFileNum

End Sub
'--------------------------------------------------------------------------------------
Private Sub SendFileToNotePad(pFileName As String)

    Dim lngReturn As Long

    lngReturn = Shell("NOTEPAD.EXE " & pFileName, vbNormalFocus)

End Sub
它工作得很好,但只能在文档打开后使用,这违背了它的目的

最后,我的问题是:

1) 在打开Word文档并等待检查每个链接的源代码的漫长过程之前,是否有方法运行此代码(或任何更好、更高效的代码-欢迎您提供建议)

2) 当我打开文档时,有没有办法避免所有这些,让Word不要检查链接


很抱歉问了这么长的问题,谢谢你的帮助

如果我没有错,根据msdn应该会有事件发生。这实际上应该是一个打开之前的文档,并且应该在更新链接之前激发(至少在excel中,它是在计算之前激发的)

尝试打开文档打开时的文件。然后,您将面临另一个问题,因此何时关闭文件,但这是一件容易得多的事情。(可能是文件关闭事件…)

编辑:

正如评论所说,这已经太晚了。您可以创建一个word opener(作为单个应用程序或加载项)。基本逻辑是:

'1) on something_open run GetOpenFileName dialog
'2) before opening the real thing, open all files accompanied
'3) open the document itself
'4) close all files
'5) close the opener itself

这不是最简单的方法,但我使用这种逻辑来确保我的应用程序总是在excel等的新副本中运行。但我知道这是一种解决方法,而不是解决方案。

如果您仍在寻找这方面的东西,我将VBA和VB.NET结合起来创建了以下内容(在VS 2010中)展示使用该系统可以很容易地完成的操作。如果VB.NET对你没有用,很抱歉,但是我有理由不想花时间在纯VBA方法上

目前,它是一个“控制台”应用程序,这意味着当它运行时,你可能会看到一个方框闪烁,但也意味着如果你必须的话,你更有可能在没有VS的情况下创建这个应用程序(AFAICR-the-VB.NET/compiler/实际上是免费的)。它只是获取链接信息。(即,目前没有修改链接的工具)

总而言之,您有一小块VBA(比如,在普通模板中),需要一个打开的文档。VBA启动Windows Shell,运行VB.NET程序,并将要打开的文档的完整路径名传递给它

VB.NET程序打开.docx(或其他任何文件)并查看从主文档部分引用的所有类型为“oleObject”的关系(因此,现在,代码忽略页眉、页脚、脚注、尾注以及可能有链接的任何其他位置)

VB.NET程序自动运行Word(我们知道它正在运行),并将每个链接URL写入活动文档中的文档变量序列中。这些变量称为“Link1”、“Link2”,等等。如果没有链接(我实际上没有正确测试该路径),或者程序找不到文件,“Link0”应该设置为“0”。否则,应将其设置为链接计数

shell同步执行,因此完成后VBA将恢复。然后,您要么有0个链接,要么有一组可以处理的链接

VBA是这样的:

Sub getLinkInfo()
' the full path name of the program, quoted if there are any spaces in it
' You would need to modify this
Const theProgram As String = """C:\VBNET\getmaindocumentolelinks.exe"""
' You will need a VBA reference to the "Windows Script Host Object Model"
Dim oShell As WshShell

Set oShell = CreateObject("WScript.Shell")
' plug your document name in here (again, notice the double quotes)
If oShell.Run(theProgram & " ""c:\a\testdocexplorer.docx""", , True) = 0 Then
  With ActiveDocument.Variables
    For i = 1 To CInt(.Item("Link0").Value)
      Debug.Print .Item("Link" & CStr(i))
    Next
  End With
Else
  MsgBox "Attempt to retrieve links failed"
End If
End Sub
对于VB.NET,您需要Office Open XML SDK(我认为它是2.5版)。您需要引用它,以及Microsoft.Office.Interop.Word

代码如下:

Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.IO
Imports System.Xml
Imports System.Xml.Linq
Imports DocumentFormat.OpenXml.Packaging
Imports Word = Microsoft.Office.Interop.Word


Module Module1
  Const OLEOBJECT As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject"

  Sub Main()
    Dim s() As String = System.Environment.GetCommandLineArgs()
    If UBound(s) > 0 Then
      Dim wordApp As Word.Application
      Try
        wordApp = GetObject(, "Word.Application")
        Dim targetDoc As Word.Document = wordApp.ActiveDocument
        Try
          Dim OOXMLDoc As WordprocessingDocument = WordprocessingDocument.Open(path:=s(1), isEditable:=False)
          Dim linkUris As IEnumerable(Of System.Uri) = From rel In OOXMLDoc.MainDocumentPart.ExternalRelationships _
                                                       Where rel.RelationshipType = OLEOBJECT _
                                                       Select rel.Uri
          For link As Integer = 0 To linkUris.Count - 1
            targetDoc.Variables("Link" & CStr(link + 1)).Value = linkUris(link).ToString
          Next
          targetDoc.Variables("Link0").Value = CStr(linkUris.Count)
          OOXMLDoc.Close()
        Catch ex As Exception
          targetDoc.Variables("Link0").Value = "0"
        End Try
      Finally
        wordApp = Nothing
      End Try
    End If
  End Sub

End Module
我最初将.NET代码作为COM对象编写,从VBA中使用会稍微容易一些,但在.NET端设置要困难得多,而且(坦率地说)修改和调试要困难得多,因为您必须不断关闭Word以释放对COM DLL的引用


如果您真的想修复链接路径,据我所知,在关系记录中修改链接路径就足以让Word在打开Word时更新相关链接字段,这样就不必修改链接字段的XML代码。但这是另一个故事…

我刚刚发现,您可以设置/修改DelayOleSrvParseDisplayName注册表项和NoActivateOleLinkObjAtOpen注册表项来修改全局行为:


参见我还发现activedocument.fields可以包含指向外部对象的链接(在我的例子中,是Excel工作表)

使用以下代码分析它们:

for each f in activedocument.fields
  debug.print f.code
next
并使用activedocument.fields(FIELDNUMBER)选择每个对象,以确定它在文档中的位置


也可能activedocument.Variablesactivedocument.Hyperlinks可以包含指向外部对象的链接吗?(对我来说不是。)

+1个非常有趣的问题,你能发布一个示例文件吗?如果必要的话,可以发布一个示例文件吗?@brettdj你是指示例word文档吗?检查此链接-最后一个答案:@Maciej谢谢,但我只是在一些文档中尝试过,它没有改变任何东西,我怀疑这与我在问题中禁用“打开时更新自动链接”的效果相同。这里的问题不是自动或手动更新链接,而是Word在开始时自动检查链接。@Born,Hmmm…,您确定要将更新更改为manu吗