【问题标题】:Runtime error 462 in regard to MSForms.DataObject关于 MSForms.DataObject 的运行时错误 462
【发布时间】:2021-01-14 22:07:42
【问题描述】:

我已经构建了一个脚本,借助该脚本,可以将多个 Word 文档的表单域中的内容一个接一个地读出并传输到一个普通的 Excel 表格中。复制功能本身工作,第一个 Word 文件的数据也正确传输,但第二个 Word 文件出现运行时错误 462。 我已经了解到这与 Word 文档的对象关系有关。当第一个 Word 文档关闭时,我的对象显然已被破坏,无法再在第二个文件中正确调用。 特别是,问题似乎与 MSForms.DataObject 有关。我已经阅读了如何通过再次调用对象来解决具有直接 Word 引用的对象的错误,但我不知道如何为 MSForms 对象执行此操作。 有人有建议吗? 我从下面的脚本中粘贴了相关代码。 如果这看起来像一个糟糕的代码,那是因为我不是程序员,必须谷歌相关的 VBA 知识。我只是想让它运行。

如果你问我为什么使用 MSForms 对象 -> 我需要它来删除人们可能在表单域中输入的段落和类似内容,这样我就可以将所有信息从一个表单域压缩到 Excel 中的一个单元格。

还设置了对 word 和 MSForms 的引用。

Sub DatenProduktion()

'Variablen definieren

'Definitionen fuer Suchpfad
Dim sPfad As String
Dim sOrdner As Integer
Dim strOrd As String
Dim sDateiPr As String
Dim vDateiPr As String
Dim vollPfadPr As String

'Definitionen fuer Zielzellen
Dim startzeile As Integer
Dim startzeilePF As Integer 'Dient zur Bestimmung der ersten Nummer der Maengelberichte
Dim sSpalte As Integer
Dim sZeile As Integer
Dim eSpalte As Integer
Dim eZeile As Integer

'Variablen fuer Uebertragung Inhalte
Dim strDateiPr As String
Dim origstr As String
Dim cleanstr As String
Dim corrstr As String
Dim checkbx As String
Dim clipbrd As MSForms.DataObject

'Variablen fuer Oeffnung Word
Dim wordApp As Word.Application
Dim wDoc As Word.Document


'___________________________________
'Erste freie Zeile finden

Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Activate

startzeile = WorksheetFunction.CountA(Range("A:A")) + 4 
'___________________________________
'Erste Zielzeile in Produktion
eZeile = startzeile
startzeilePF = startzeile - 5
'___________________________________


'Loop beginnen
Do

'Zuruecksetzen Spalte
eSpalte = 1


'Pfad zur erste noch nicht eingepflegten Word konstruieren
sPfad = "P:\Mängelbericht\Mängelberichte Word\"
sOrdner = startzeilePF
sDateiPr = "Mängelbericht Produktion.docx"
strOrd = CStr(sOrdner)
vollPfadPr = sPfad & strOrd & "_" & sDateiPr
'___________________________________

If Dir(vollPfadPr) <> "" Then

    'Namen der Datei in erste Spalte schreiben
    vDateiPr = strOrd & "_" & sDateiPr
    Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Cells(eZeile, eSpalte) = vDateiPr
    eSpalte = eSpalte + 1


    'Word Datei oeffnen
    Set wordApp = CreateObject("word.application")
    Set wDoc = wordApp.Documents.Open(vollPfadPr)
    wordApp.Visible = True
    Set clipbrd = New MSForms.DataObject
    
    'Artikelbezeichnung
    wDoc.Bookmarks("Artikelbezeichnung").Range.Copy
    clipbrd.GetFromClipboard
    origstr = clipbrd.GetText(1)
    cleanstr = CleanString(origstr)
    corrstr = Replace(cleanstr, Chr(13), Chr(32))
    Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Cells(eZeile, eSpalte) = corrstr
    eSpalte = eSpalte + 1

    [...]

    'Word-Datei schliessen
    Set clipbrd = Nothing
    wordApp.Documents.Close
    wordApp.Quit
    Set wordApp = Nothing
    Set wDoc = Nothing

'___________________________________
'Falls keine (neue) Datei gefunden werden kann
Else
    Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Protect Password:="*****"
    Exit Do
End If

eZeile = eZeile + 1
startzeilePF = startzeilePF + 1

Loop

[...]

End Sub

【问题讨论】:

  • 据我了解您链接的 makros,它们不适用于我的情况。当我只是从包含文本段落的表单字段中复制范围时,它会被粘贴到 Excel 中的多个单元格中。这对我来说是不可接受的。在将字符串粘贴到 Excel 之前,我必须对其进行修改。这就是我需要 MSForms.DataObject 的原因,我需要了解为什么它在我的情况下会损坏。
  • 这两个链接表明您不需要处理每个书签,也不需要使用剪贴板。例如:origstr = wDoc.Bookmarks("Artikelbezeichnung").Range.Text 会给你和origstr = clipbrd.GetText(1)一样的结果
  • 我尝试了origstr = wDoc.Bookmarks("Artikelbezeichnung").Range.Text,但在cleanstr = CleanString(origstr) 行上仍然遇到相同的运行时错误。我想我的对象没有为第二个单词文件正确重置,但我不明白为什么。我复制了这些部分以关闭 word 文件,并从 Stackoverflow 上的另一个脚本中将它们设置为空,这似乎可以工作。
  • 如果 Word 表单域包含多个段落,您必须在将数据插入 Excel 之前对其进行操作。看我的回答。

标签: excel vba ms-word


【解决方案1】:

您不需要使用 MSForms.DataObject、剪贴板或引用任何书签。试试下面的宏,它被编码来处理表单域和内容控件:

Sub GetFormData()
'Note: this code requires a reference to the Word object model.
'See under the VBE's Tools|References.
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String
Dim WkSht As Worksheet, i As Long, j As Long
strFolder = GetFolder
If strFolder = "" Then Exit Sub
Dim wdApp As New Word.Application, wdDoc As Word.Document
Dim FmFld As Word.FormField, CCtrl As Word.ContentControl
Set WkSht = ActiveSheet
i = WkSht.Cells(WkSht.Rows.Count, 1).End(xlUp).Row
'Disable any auto macros in the documents being processed
wdApp.WordBasic.DisableAutoMacros
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
  i = i + 1
  Set wdDoc = wdApp.Documents.Open(Filename:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
  With wdDoc
    j = 0
    For Each FmFld In .FormFields
      j = j + 1
      With FmFld
        Select Case .Type
          Case Is = wdFieldFormCheckBox
            WkSht.Cells(i, j) = .CheckBox.Value
          Case Else
            If IsNumeric(FmFld.Result) Then
              If Len(FmFld.Result) > 15 Then
                WkSht.Cells(i, j) = "'" & FmFld.Result
              Else
                WkSht.Cells(i, j) = FmFld.Result
              End If
            Else
              WkSht.Cells(i, j) = Replace(Replace(FmFld.Result, vbCr, "¶"), Chr(11), "¶")
            End If
        End Select
      End With
    Next
    For Each CCtrl In .ContentControls
      With CCtrl
        Select Case .Type
          Case Is = wdContentControlCheckBox
            j = j + 1
            WkSht.Cells(i, j) = .Checked
          Case wdContentControlDate, wdContentControlDropdownList, wdContentControlRichText, wdContentControlText
            j = j + 1
            If IsNumeric(.Range.Text) Then
              If Len(.Range.Text) > 15 Then
                WkSht.Cells(i, j).Value = "'" & .Range.Text
              Else
                WkSht.Cells(i, j).Value = .Range.Text
              End If
            Else
              WkSht.Cells(i, j) = Replace(Replace(.Range.Text, vbCr, "¶"), Chr(11), "¶")
            End If
          Case Else
        End Select
      End With
    Next
    .Close SaveChanges:=False
  End With
  strFile = Dir()
Wend
wdApp.Quit
WkSht.UsedRange.Replace What:="¶", Replacement:=Chr(10), LookAt:=xlPart, SearchOrder:=xlByRows
Set wdDoc = Nothing: Set wdApp = Nothing: Set WkSht = Nothing
Application.ScreenUpdating = True
End Sub
 
Function GetFolder() As String
    Dim oFolder As Object
    GetFolder = ""
    Set oFolder = CreateObject("Shell.Application").BrowseForFolder(0, "Choose a folder", 0)
    If (Not oFolder Is Nothing) Then GetFolder = oFolder.Items.Item.Path
    Set oFolder = Nothing
End Function

如果您想将文档的名称记录为数据的一部分,请更改:

j = 0

到:

j = 1: WkSht.Cells(i, j) = strFile

【讨论】:

  • 这很有效。有一种奇怪的行为,数据没有粘贴在第一个空行中,而是粘贴在之前没有使用过的第一行中。我想如果我足够仔细地阅读该代码,我应该能够修复它。文本中的段落也没有被删除,但也被转移到 Excel,但这也应该很容易纠正。此代码不会在每次尝试时都导致运行时错误。非常感谢。
  • 按照编码,宏将目标工作表中的第一行留空 - 因此您可以向其中添加标题。否则,它将从第一个未使用的行开始填充。与 Rich 的代码不同,我的代码显式地创建了自己的 Word 会话,并在完成后终止。
【解决方案2】:

我已经编辑了您的代码,包括检查 Word 是否已经打开并使用它的实例,而不是在您检查新 Word 文档的目录的每次迭代中创建一个新实例。我也把它移出了循环。

此例程不需要剪贴板,您可以获取书签范围的内容并将其直接分配给字符串变量。

最后,我将 Word 的退出以及 Word 的对象变量的清除移到了末尾。

Option Explicit
Sub DatenProduktion()

'Variablen definieren

'Definitionen fuer Suchpfad
Dim sPfad As String
Dim sOrdner As Integer
Dim strOrd As String
Dim sDateiPr As String
Dim vDateiPr As String
Dim vollPfadPr As String

'Definitionen fuer Zielzellen
Dim startzeile As Integer
Dim startzeilePF As Integer 'Dient zur Bestimmung der ersten Nummer der Maengelberichte
Dim sSpalte As Integer
Dim sZeile As Integer
Dim eSpalte As Integer
Dim eZeile As Integer

'Variablen fuer Uebertragung Inhalte
Dim strDateiPr As String
Dim origstr As String
Dim cleanstr As String
Dim corrstr As String
Dim checkbx As String
'Dim clipbrd As MSForms.DataObject

'Variablen fuer Oeffnung Word
Dim wordApp As Word.Application
Dim wDoc As Word.Document


'___________________________________
'Erste freie Zeile finden

Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Activate

startzeile = WorksheetFunction.CountA(Range("A:A")) + 4
'___________________________________
'Erste Zielzeile in Produktion
eZeile = startzeile
startzeilePF = startzeile - 5
'___________________________________


'Loop beginnen
Do

'Zuruecksetzen Spalte
eSpalte = 1


'Pfad zur erste noch nicht eingepflegten Word konstruieren
sPfad = "P:\Mängelbericht\Mängelberichte Word\"
sOrdner = startzeilePF
sDateiPr = "Mängelbericht Produktion.docx"
strOrd = CStr(sOrdner)
vollPfadPr = sPfad & strOrd & "_" & sDateiPr
'___________________________________

On Error Resume Next
Set wordApp = GetObject(, "Word.Application")
If Err.Number <> 0 Then
    Err.Clear
    Set wordApp = CreateObject("word.application")
End If
wordApp.Visible = True
On Error GoTo 0

If Dir(vollPfadPr) <> "" Then

    'Namen der Datei in erste Spalte schreiben
    vDateiPr = strOrd & "_" & sDateiPr
    Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Cells(eZeile, eSpalte) = vDateiPr
    eSpalte = eSpalte + 1


    'Word Datei oeffnen
'    Set wordApp = CreateObject("word.application")
    Set wDoc = wordApp.Documents.Open(vollPfadPr)
'    wordApp.Visible = True
'    Set clipbrd = New MSForms.DataObject
    
    'Artikelbezeichnung
    origstr = wDoc.Bookmarks("Artikelbezeichnung").Range.Text
'    clipbrd.GetFromClipboard
'    origstr = clipbrd.GetText(1)
    cleanstr = CleanString(origstr)
    corrstr = Replace(cleanstr, Chr(13), Chr(32))
    Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Cells(eZeile, eSpalte) = corrstr
    eSpalte = eSpalte + 1

    [...]

    'Word-Datei schliessen
'    Set clipbrd = Nothing
    wordApp.Documents.Close
'    wordApp.Quit
'    Set wordApp = Nothing
'    Set wDoc = Nothing

'___________________________________
'Falls keine (neue) Datei gefunden werden kann
Else
    Workbooks("Mangelauswertung.xlsm").Worksheets("Produktion").Protect Password:="*****"
    Exit Do
End If

eZeile = eZeile + 1
startzeilePF = startzeilePF + 1

Loop

wordApp.Quit
If Not wordApp = Nothing Then Set wordApp = Nothing
If Not wDoc = Nothing Then Set wDoc = Nothing


[...]

End Sub

【讨论】:

  • 这似乎可以解决问题。但是,如果我尝试使用 2 行 If Not wordApp = Nothing Then Set wordApp = Nothing If Not wDoc = Nothing Then Set wDoc = Nothing 运行它,Excel 会弹出一条错误消息,大致应翻译为“编译期间出错:对象的无效使用”。所以我把这两行从脚本中拿出来,它起作用了……基本上。在第一次尝试运行它时,它可以正常工作(有 13 个文件),但在每秒尝试一次时,脚本会因运行时错误 462 而停止。在错误之后的第三次尝试中,它会再次运行。猜猜为什么?
  • 将此命令 wordApp.Documents.Close 更改为 wDoc.Close。我认为这将解决问题。清除 wordApp 和 wDoc 对象的另一个错误是我应该阅读的错误,如果不是 wordApp Is Nothing 那么 ...
  • 我进行了您描述的更改,但脚本每第二次运行时仍会出现运行时错误。无论如何,我非常感谢你。
猜你喜欢
  • 2015-06-23
  • 2023-01-29
  • 1970-01-01
  • 2015-12-08
  • 1970-01-01
  • 2020-01-12
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多