来自VBA DataObject的奇怪行为。 GetText返回剪贴板上当前的内容

我之前发布了一个关于从Microsoft Office Excel 2013 VBA访问的MSForms DataObject引发的错误的问题。 当我写这篇文章的时候,我发现了其他更奇怪的行为。

也许我对DataObject的看法是错误的,但如果是这样的话,MS Office文档是非常具有误导性的。 我的期望是这样的:

如果我创build一个DataObject并使用GetFromClipboard方法,它应该加载剪贴板上的任何内容到对象中。 存储在对象中的数据应该改变,直到我对对象执行一些其他操作(例如调用Clear,SetText等)

所以如果我执行以下操作:

  1. 手动将一些文本复制到Windows剪贴板上。
  2. 创build一个DataObject并调用GetFromClipboard
  3. 执行一些更改Windows剪贴板的VBA操作(但不要访问数据对象)
  4. 在DataObject上调用GetText

希望在第4步中检索到的文本与我在#2中放置的文本相同。

但是,情况并非如此,如下面的示例代码所示。

testing说明:

  1. 将此代码复制到办公室应用程序中的标准代码模块。
  2. 复制一些文本(例如从记事本)
  3. 运行方法“TestDataObject”
  4. 出现提示时,复制一些不同的文本。
  5. 当第二次提示时,复制一些其他不同的文本。

(您可能需要添加一个对“Microsoft Forms 2.0对象库”的引用,通过简单地将用户窗体添加到您的VBA项目中,您可以快速完成此操作,因为这会自动添加引用)

'Copy some text before running this. Public Sub TestDataObject() Dim oData As DataObject Set oData = New DataObject 'This is BEFORE GetFromClipboard is called, so ' the DataObject currently has NO text in it. If oData.GetFormat(1) Then Debug.Print "1) Contents: " & oData.GetText(1) Else 'This line will be printed. Debug.Print "1) Contents: (NONE)" End If oData.GetFromClipboard 'Now the DataObject has some text, and it will be printed below. If oData.GetFormat(1) Then Debug.Print "2) Contents: " & oData.GetText(1) MsgBox "Copy some Text" 'If you copied NEW text, then it will be shown below (instead of the original data) If oData.GetFormat(1) Then Debug.Print "3) Contents: " & oData.GetText(1) MsgBox "Copy some different Text" 'If you copied other NEW text, then it will be shown below (instead of the original data) If oData.GetFormat(1) Then Debug.Print "4) Contents: " & oData.GetText(1) End Sub 

假设我在运行sub之前复制的文本是“Hellow”,我希望这将打印出以下内容, 无论我在方法运行时手动复制:

 1) Contents: (NONE) 2) Contents: Hello 3) Contents: Hello 4) Contents: Hello 

但实际产出是这样的:

 1) Contents: (NONE) 2) Contents: Hello 3) Contents: World 4) Contents: Goodbye 

(假设我第一次提示时复制了“世界”,第二次提示时我复制了“再见”)。

请注意,Msgbox不会导致此行为。 如果你喜欢,你可以使用DoEvents-Loop几秒钟。 或者使用Range对象或其他Excel对象执行复制/粘贴操作,如下所示:

 Public Sub TestDataObject() Dim oData As DataObject: Set oData = New DataObject ThisWorkbook.ActiveSheet.Range("A1").Select Selection.Value = "Hello" Selection.Copy If oData.GetFormat(1) Then Debug.Print "1) Contents: " & oData.GetText(1) Else Debug.Print "1) Contents: (NONE)" End If oData.GetFromClipboard If oData.GetFormat(1) Then Debug.Print "2) Contents: " & oData.GetText(1) Selection.Value = "World" Selection.Copy If oData.GetFormat(1) Then Debug.Print "3) Contents: " & oData.GetText(1) Selection.Value = "Goodbye" Selection.Copy If oData.GetFormat(1) Then Debug.Print "4) Contents: " & oData.GetText(1) End Sub 

这不是特定于Excel。 在Word中相同的代码工作,除了你必须改变select/复制代码(例如):

 ' Code to copy text in Word Selection.Text = "World" Selection.Copy 

所以我的问题是:这是行为预期还是它的错误? 我正在使用Office 2014 64位。 这是否也发生在32位Office? 也许这只是一个64位的错误。

谢谢!

我可以复制(32位Office 2010,Win7)

 Sub Tester() Dim d As New DataObject, d2 As New DataObject d2.SetText "first" d2.PutInClipboard d.GetFromClipboard Debug.Print d.GetText '--> "first" d2.SetText "second" d2.PutInClipboard Debug.Print d.GetText '--> "second" d2.SetText "third" d2.PutInClipboard Debug.Print d.GetText '--> "third" End Sub 

我不得不猜测, GetFromClipboard只build立一个通过引用剪贴板的链接,而不是价值。 所以每当你调用GetText它实际上是直接从剪贴板中取出,而不是从DataObject中保存的复制caching中取出。

如果您需要剪贴板内容的稳定副本,而不受后续复制操作的影响,则必须将其存储在(例如)stringvariables中。