GetObject 有时会生成新的 COM+/OLE 对象,而不是获取现有对象
GetObject sometimes spawns new COM+/OLE object instead of getting the existing one
从 Excel,我挂钩了一个 Glink OLE 对象 - 这个对象是一个 运行ning 程序,我需要与之交互,所以程序将(并且必须) 运行宁此代码之前已经打开。
由于(我假设)我无法访问的本地配置或某些我不理解的 API 行为,有时代码会创建一个新对象而不是 Get
-ing 已经打开的那个。就其本身而言,这并不是最糟糕的事情 - 它可以解决。
如果我手动 运行 一个不包含任何循环或枚举尝试的 Sub
,我可能会挂钩打开的对象(正确的)或相同的新的、不可用的对象生成类型 (false)。如果我挂错了一个,只需重新 运行 宁 Sub
给我正确的对象 - 这是一致的。
如果我 运行 一个 Sub
循环自身(试图复制手动重新 运行 子的行为),没有这样的运气 - 它给了我"same" 对象(实际上不是同一个对象 - 它每次都会产生一个新实例,但无论如何这永远不会是正确的对象,因为正确的对象 已经存在 )及以上。
我有一些代码:
Dim gl As Glink.Auto
Set gl = Nothing
Set gl = GetObject("", "Glink.Auto")
这在上面第 2 段中概述了 - 它会可靠地在我不需要/不能使用的对象和我确实想要的对象之间切换,因此发现正确的对象是微不足道的根据第一个 运行 的结果,运行 对宏执行 1 次或 2 次。
有两种方法可以区分我是否得到了正确的对象:第一种是检查Instance
属性,所以我的代码包括检查:
Debug.Print gl.Instance
如果我有正确的对象,Instance
将是 0
。相反,如果 Instance
不是 0
,我得到的东西无法使用。
第二个是Automated
。如果这是 TRUE
,则该对象是通过 OLE 生成的(因此对我来说无法使用)。反之,如果是FALSE
,我知道它指的是我手动打开的对象(这就是我想要的对象)。
最终代码
将 strict
设置为 TRUE
可启用循环。手动 运行s 和程序循环 运行s 在代码上没有区别,除了标记为手动的 运行s 有 strict = False
而其他有 strict = True
。
' Glink globals
Global gl As glink.Auto
Global scr As IAutoScreen
' Other globals
Global dbg As Boolean
Global strict As Boolean
Sub Glink_Initialize()
Dim retryCount As Integer
retryCount = 0
dbg = True
strict = False
' Start GLINK session hook
Retry:
Set gl = Nothing
Set gl = GetObject("", "Glink.Auto")
If dbg = True Then
If Err.Number <> 0 Then
GoTo Terminate:
Else
If gl.Instance <> 0 And strict = True Then
If retryCount < 5 Then
If dbg = True Then
Debug.Print "No valid instance found, retrying."
Debug.Print "Instance: " & gl.Instance & " RetryCount: " & retryCount & vbCr
End If
retryCount = retryCount + 1
GoTo Retry:
ElseIf strict = True Then
If dbg = True Then Debug.Print "RetryCount exceeded limit"
GoTo Terminate:
End If
End If
Debug.Print "Image: " & gl.Caption & vbCr & "Instance: " & gl.Instance & vbCr & "Automation: " & gl.Automated
End If
End If
' End GLINK session hook
Exit Sub
Terminate:
Debug.Print "No Glink detected! Terminating."
Set gl = Nothing
End Sub
下面是两个手册 运行 中的一些调试语句(无循环)紧接着
' Run 1
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 49 ' <-- Unusable object
Automation: True ' <-- Spawned by OLE
' Run 2
Image: GLINK - Vegard - AA90
Instance: 0 ' <-- Usable object
Automation: False ' <-- Not spawned by OLE = this is the object I want
这个过程以绝对的一致性重复着令人作呕的过程。获取正确的对象,生成新对象,获取正确的对象,生成新对象等:
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 56
Automation: True
Image: GLINK - Vegard - AA90
Instance: 0
Automation: False
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 57
Automation: True
Image: GLINK - Vegard - AA90
Instance: 0
Automation: False
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 58
Automation: True
Image: GLINK - Vegard - AA90
Instance: 0
Automation: False
这是包含循环
的代码的 1 运行 中的调试语句
No valid instance found, retrying.
Instance: 43 RetryCount: 0
No valid instance found, retrying.
Instance: 44 RetryCount: 1
No valid instance found, retrying.
Instance: 45 RetryCount: 2
No valid instance found, retrying.
Instance: 46 RetryCount: 3
No valid instance found, retrying.
Instance: 47 RetryCount: 4
所以似乎使用编程循环跳过了获取正确对象的步骤...为什么?有办法解决这个问题吗?
根据@Flephal 的评论和 MSDN,人们会认为省略 GetObject
的第一个参数是正确的方法。出于某种原因,我并没有始终如一地遇到这种情况 - 如果第一个参数不存在,有时我会收到 429 错误。
更具体地说,这是 MSDN 的摘录:
If pathname is a zero-length string (""), GetObject returns a new
object instance of the specified type. If the pathname argument is
omitted, GetObject returns a currently active object of the specified
type. If no object of the specified type exists, an error occurs.
根据此描述,我假设我收到了引用错误,因为未找到指定的对象(但我正在查看它的 window,所以我知道它在那里)。我不知道为什么会这样,但是:
解决方法
改变这个:
Set gl = Nothing
Set gl = GetObject("", "Glink.Auto")
对此:
Set gl = Nothing
Set gl = GlinkObjectHook
并添加此功能:
Function GlinkObjectHook() As glink.Auto
Dim glink As glink.Auto
On Error Resume Next
Set glink = GetObject(, "Glink.Auto")
On Error GoTo 0
If glink Is Nothing Then Set glink = GetObject("", "Glink.Auto")
Set GlinkObjectHook = glink
End Function
从 Excel,我挂钩了一个 Glink OLE 对象 - 这个对象是一个 运行ning 程序,我需要与之交互,所以程序将(并且必须) 运行宁此代码之前已经打开。
由于(我假设)我无法访问的本地配置或某些我不理解的 API 行为,有时代码会创建一个新对象而不是 Get
-ing 已经打开的那个。就其本身而言,这并不是最糟糕的事情 - 它可以解决。
如果我手动 运行 一个不包含任何循环或枚举尝试的 Sub
,我可能会挂钩打开的对象(正确的)或相同的新的、不可用的对象生成类型 (false)。如果我挂错了一个,只需重新 运行 宁 Sub
给我正确的对象 - 这是一致的。
如果我 运行 一个 Sub
循环自身(试图复制手动重新 运行 子的行为),没有这样的运气 - 它给了我"same" 对象(实际上不是同一个对象 - 它每次都会产生一个新实例,但无论如何这永远不会是正确的对象,因为正确的对象 已经存在 )及以上。
我有一些代码:
Dim gl As Glink.Auto
Set gl = Nothing
Set gl = GetObject("", "Glink.Auto")
这在上面第 2 段中概述了 - 它会可靠地在我不需要/不能使用的对象和我确实想要的对象之间切换,因此发现正确的对象是微不足道的根据第一个 运行 的结果,运行 对宏执行 1 次或 2 次。
有两种方法可以区分我是否得到了正确的对象:第一种是检查Instance
属性,所以我的代码包括检查:
Debug.Print gl.Instance
如果我有正确的对象,Instance
将是 0
。相反,如果 Instance
不是 0
,我得到的东西无法使用。
第二个是Automated
。如果这是 TRUE
,则该对象是通过 OLE 生成的(因此对我来说无法使用)。反之,如果是FALSE
,我知道它指的是我手动打开的对象(这就是我想要的对象)。
最终代码
将 strict
设置为 TRUE
可启用循环。手动 运行s 和程序循环 运行s 在代码上没有区别,除了标记为手动的 运行s 有 strict = False
而其他有 strict = True
。
' Glink globals
Global gl As glink.Auto
Global scr As IAutoScreen
' Other globals
Global dbg As Boolean
Global strict As Boolean
Sub Glink_Initialize()
Dim retryCount As Integer
retryCount = 0
dbg = True
strict = False
' Start GLINK session hook
Retry:
Set gl = Nothing
Set gl = GetObject("", "Glink.Auto")
If dbg = True Then
If Err.Number <> 0 Then
GoTo Terminate:
Else
If gl.Instance <> 0 And strict = True Then
If retryCount < 5 Then
If dbg = True Then
Debug.Print "No valid instance found, retrying."
Debug.Print "Instance: " & gl.Instance & " RetryCount: " & retryCount & vbCr
End If
retryCount = retryCount + 1
GoTo Retry:
ElseIf strict = True Then
If dbg = True Then Debug.Print "RetryCount exceeded limit"
GoTo Terminate:
End If
End If
Debug.Print "Image: " & gl.Caption & vbCr & "Instance: " & gl.Instance & vbCr & "Automation: " & gl.Automated
End If
End If
' End GLINK session hook
Exit Sub
Terminate:
Debug.Print "No Glink detected! Terminating."
Set gl = Nothing
End Sub
下面是两个手册 运行 中的一些调试语句(无循环)紧接着
' Run 1
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 49 ' <-- Unusable object
Automation: True ' <-- Spawned by OLE
' Run 2
Image: GLINK - Vegard - AA90
Instance: 0 ' <-- Usable object
Automation: False ' <-- Not spawned by OLE = this is the object I want
这个过程以绝对的一致性重复着令人作呕的过程。获取正确的对象,生成新对象,获取正确的对象,生成新对象等:
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 56
Automation: True
Image: GLINK - Vegard - AA90
Instance: 0
Automation: False
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 57
Automation: True
Image: GLINK - Vegard - AA90
Instance: 0
Automation: False
Image: GLINK - (ref.:2242.2853:ErgoIntegration)
Instance: 58
Automation: True
Image: GLINK - Vegard - AA90
Instance: 0
Automation: False
这是包含循环
的代码的 1 运行 中的调试语句No valid instance found, retrying.
Instance: 43 RetryCount: 0
No valid instance found, retrying.
Instance: 44 RetryCount: 1
No valid instance found, retrying.
Instance: 45 RetryCount: 2
No valid instance found, retrying.
Instance: 46 RetryCount: 3
No valid instance found, retrying.
Instance: 47 RetryCount: 4
所以似乎使用编程循环跳过了获取正确对象的步骤...为什么?有办法解决这个问题吗?
根据@Flephal 的评论和 MSDN,人们会认为省略 GetObject
的第一个参数是正确的方法。出于某种原因,我并没有始终如一地遇到这种情况 - 如果第一个参数不存在,有时我会收到 429 错误。
更具体地说,这是 MSDN 的摘录:
If pathname is a zero-length string (""), GetObject returns a new object instance of the specified type. If the pathname argument is omitted, GetObject returns a currently active object of the specified type. If no object of the specified type exists, an error occurs.
根据此描述,我假设我收到了引用错误,因为未找到指定的对象(但我正在查看它的 window,所以我知道它在那里)。我不知道为什么会这样,但是:
解决方法
改变这个:
Set gl = Nothing
Set gl = GetObject("", "Glink.Auto")
对此:
Set gl = Nothing
Set gl = GlinkObjectHook
并添加此功能:
Function GlinkObjectHook() As glink.Auto
Dim glink As glink.Auto
On Error Resume Next
Set glink = GetObject(, "Glink.Auto")
On Error GoTo 0
If glink Is Nothing Then Set glink = GetObject("", "Glink.Auto")
Set GlinkObjectHook = glink
End Function