让 ScriptControl 与 Excel 2010 x64 一起工作
Posted
技术标签:
【中文标题】让 ScriptControl 与 Excel 2010 x64 一起工作【英文标题】:Getting ScriptControl to work with Excel 2010 x64 【发布时间】:2012-04-01 07:46:46 【问题描述】:我正在尝试使用this 提供的解决方案,但是,每当我尝试运行最基本的任何东西时,都会收到Object not Defined
错误。我认为这是我的错(没有安装 ScriptControl)。但是,我尝试按照here 中的说明进行安装,但无济于事。
我正在运行带有 Office 2010 64 位的 Windows 7 Professional x64。
【问题讨论】:
为了有用,我们需要查看您尝试过的确切代码,以及出现错误(以及来自代码的哪一行) 蒂姆 - 我也有同样的问题。我正在使用 Codo 接受的链接问题答案中的确切代码(从这个问题的第一行链接)。运行 TestJSONAccess 子程序时,我从 InitScriptEngine 子程序的第一行(Set ScriptEnging = New ScriptControl)收到一条错误消息“运行时错误'429':ActiveX 组件无法创建对象”。我已经设置了对 msscript.ocx 文件的引用。 【参考方案1】:您可以通过 64 位 VBA 版本的 mshta x86 主机在 32 位 Office 版本上创建 ActiveX 对象,例如 ScriptControl
,这是示例(将代码放在标准 VBA 项目模块中):
Option Explicit
Sub Test()
Dim oSC As Object
Set oSC = CreateObjectx86("ScriptControl") ' create ActiveX via x86 mshta host
Debug.Print TypeName(oSC) ' ScriptControl
' do some stuff
CreateObjectx86 Empty ' close mshta host window at the end
End Sub
Function CreateObjectx86(sProgID)
Static oWnd As Object
Dim bRunning As Boolean
#If Win64 Then
bRunning = InStr(TypeName(oWnd), "htmlWindow") > 0
If IsEmpty(sProgID) Then
If bRunning Then oWnd.Close
Exit Function
End If
If Not bRunning Then
Set oWnd = CreateWindow()
oWnd.execScript "Function CreateObjectx86(sProgID): Set CreateObjectx86 = CreateObject(sProgID): End Function", "VBScript"
End If
Set CreateObjectx86 = oWnd.CreateObjectx86(sProgID)
#Else
If Not IsEmpty(sProgID) Then Set CreateObjectx86 = CreateObject(sProgID)
#End If
End Function
Function CreateWindow()
' source http://forum.script-coding.com/viewtopic.php?pid=75356#p75356
Dim sSignature, oShellWnd, oProc
On Error Resume Next
Do Until Len(sSignature) = 32
sSignature = sSignature & Hex(Int(Rnd * 16))
Loop
CreateObject("WScript.Shell").Run "%systemroot%\syswow64\mshta.exe about:""<head><script>moveTo(-32000,-32000);document.title='x86Host'</script><hta:application showintaskbar=no /><object id='shell' classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'><param name=RegisterAsBrowser value=1></object><script>shell.putproperty('" & sSignature & "',document.parentWindow);</script></head>""", 0, False
Do
For Each oShellWnd In CreateObject("Shell.Application").Windows
Set CreateWindow = oShellWnd.GetProperty(sSignature)
If Err.Number = 0 Then Exit Function
Err.Clear
Next
Loop
End Function
它有一些缺点:需要单独运行mshta.exe
进程,在任务管理器中列出,按Alt+Tab显示隐藏HTA窗口:
您还必须在代码末尾通过 CreateObjectx86 Empty
关闭该 HTA 窗口。
更新
您可以使主机窗口自动关闭:通过创建类实例或 mshta 主动跟踪。
第一种方法假设您创建一个类实例作为包装器,它使用Private Sub Class_Terminate()
关闭窗口。
注意:如果 Excel 在代码执行时崩溃,则不会终止类,因此窗口将保持在后台。
将下面的代码放在一个名为cMSHTAx86Host
的类模块中:
Option Explicit
Private oWnd As Object
Private Sub Class_Initialize()
#If Win64 Then
Set oWnd = CreateWindow()
oWnd.execScript "Function CreateObjectx86(sProgID): Set CreateObjectx86 = CreateObject(sProgID) End Function", "VBScript"
#End If
End Sub
Private Function CreateWindow()
' source http://forum.script-coding.com/viewtopic.php?pid=75356#p75356
Dim sSignature, oShellWnd, oProc
On Error Resume Next
Do Until Len(sSignature) = 32
sSignature = sSignature & Hex(Int(Rnd * 16))
Loop
CreateObject("WScript.Shell").Run "%systemroot%\syswow64\mshta.exe about:""<head><script>moveTo(-32000,-32000);document.title='x86Host'</script><hta:application showintaskbar=no /><object id='shell' classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'><param name=RegisterAsBrowser value=1></object><script>shell.putproperty('" & sSignature & "',document.parentWindow);</script></head>""", 0, False
Do
For Each oShellWnd In CreateObject("Shell.Application").Windows
Set CreateWindow = oShellWnd.GetProperty(sSignature)
If Err.Number = 0 Then Exit Function
Err.Clear
Next
Loop
End Function
Function CreateObjectx86(sProgID)
#If Win64 Then
If InStr(TypeName(oWnd), "HTMLWindow") = 0 Then Class_Initialize
Set CreateObjectx86 = oWnd.CreateObjectx86(sProgID)
#Else
Set CreateObjectx86 = CreateObject(sProgID)
#End If
End Function
Function Quit()
#If Win64 Then
If InStr(TypeName(oWnd), "HTMLWindow") > 0 Then oWnd.Close
#End If
End Function
Private Sub Class_Terminate()
Quit
End Sub
将以下代码放入标准模块中:
Option Explicit
Sub Test()
Dim oHost As New cMSHTAx86Host
Dim oSC As Object
Set oSC = oHost.CreateObjectx86("ScriptControl") ' create ActiveX via x86 mshta host
Debug.Print TypeName(oSC) ' ScriptControl
' do some stuff
' mshta window is running until oHost instance exists
' if necessary you can manually close mshta host window by oHost.Quit
End Sub
第二种方法适用于那些出于某种原因不想使用类的人。关键是 mshta 窗口每 500 毫秒通过内部 setInterval()
函数检查 VBA 的 Static oWnd
变量调用 CreateObjectx86
的状态,如果引用丢失则退出(用户在 VBA 项目窗口中按下了重置,或者工作簿已关闭(错误 1004))。
注意:VBA 断点(错误 57097)、用户编辑的工作表单元格、打开的对话框模式窗口(如打开/保存/选项)(错误 -2147418111)将暂停跟踪,因为它们会使应用程序对来自 mshta 的外部调用无响应。此类动作异常处理,完成后代码将继续工作,不会崩溃。
将以下代码放入标准模块中:
Option Explicit
Sub Test()
Dim oSC As Object
Set oSC = CreateObjectx86("ScriptControl") ' create ActiveX via x86 mshta host
Debug.Print TypeName(oSC) ' ScriptControl
' do some stuff
' mshta window is running until Static oWnd reference to window lost
' if necessary you can manually close mshta host window by CreateObjectx86 Empty
End Sub
Function CreateObjectx86(Optional sProgID)
Static oWnd As Object
Dim bRunning As Boolean
#If Win64 Then
bRunning = InStr(TypeName(oWnd), "HTMLWindow") > 0
Select Case True
Case IsMissing(sProgID)
If bRunning Then oWnd.Lost = False
Exit Function
Case IsEmpty(sProgID)
If bRunning Then oWnd.Close
Exit Function
Case Not bRunning
Set oWnd = CreateWindow()
oWnd.execScript "Function CreateObjectx86(sProgID): Set CreateObjectx86 = CreateObject(sProgID) End Function", "VBScript"
oWnd.execScript "var Lost, App;": Set oWnd.App = Application
oWnd.execScript "Sub Check(): On Error Resume Next: Lost = True: App.Run(""CreateObjectx86""): If Lost And (Err.Number = 1004 Or Err.Number = 0) Then close: End If End Sub", "VBScript"
oWnd.execScript "setInterval('Check();', 500);"
End Select
Set CreateObjectx86 = oWnd.CreateObjectx86(sProgID)
#Else
Set CreateObjectx86 = CreateObject(sProgID)
#End If
End Function
Function CreateWindow()
' source http://forum.script-coding.com/viewtopic.php?pid=75356#p75356
Dim sSignature, oShellWnd, oProc
On Error Resume Next
Do Until Len(sSignature) = 32
sSignature = sSignature & Hex(Int(Rnd * 16))
Loop
CreateObject("WScript.Shell").Run "%systemroot%\syswow64\mshta.exe about:""<head><script>moveTo(-32000,-32000);document.title='x86Host'</script><hta:application showintaskbar=no /><object id='shell' classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'><param name=RegisterAsBrowser value=1></object><script>shell.putproperty('" & sSignature & "',document.parentWindow);</script></head>""", 0, False
Do
For Each oShellWnd In CreateObject("Shell.Application").Windows
Set CreateWindow = oShellWnd.GetProperty(sSignature)
If Err.Number = 0 Then Exit Function
Err.Clear
Next
Loop
End Function
更新 2
由于注意到权限问题而拒绝Scriptlet.TypeLib
。
【讨论】:
惊人的解决方案,应该是公认的答案,你认为有没有办法在宏结束时自动关闭窗口? @gbaccetta 我发布了窗口自动关闭的解决方案。 @omegastripes 谢谢你,我会在我回到那个项目的工作后尽快尝试,但从它的外观来看,它应该像一个魅力 这应该是公认的答案,就像魅力一样 @SlowLearner 该问题是由不正确的属性名称引起的。oWnd.App
可以,oWnd.app
不行。【参考方案2】:
对于 32 位版本的控件,可提供 64 位替换。 Google for Tabalacus 脚本控制。 https://github.com/tablacus/TablacusScriptControl。如果需要,可以使用免费的 VS 版本编译控件。
【讨论】:
这很有魅力,应该是公认的答案! :) 是的,知道它很容易 :) TablacusScriptControl 在 2013 年以后的 64 位 Office 中不起作用。它甚至没有出现在“工具”->“参考”对话框中。这是在 2018 年 7 月向他们报告的,他们的反应非常令人沮丧和悲伤:Unfortunately, I don't have Excel 2016 and I'm not very familiar with Excel. 也为我工作(64 位 Office 2016)【参考方案3】:遗憾的是,scriptcontrol 只是一个 32 位组件,不会在 64 位进程中运行。
【讨论】:
以上是关于让 ScriptControl 与 Excel 2010 x64 一起工作的主要内容,如果未能解决你的问题,请参考以下文章
在 Excel VBA 代码中处理 XMLHttp 响应中的 JSON 对象
VBA研究64位系统下无法用ScriptControl控件解析JSon数据
如何让 Excel 加载项 (Excel 2007) 中的用户定义函数与自动完成功能一起使用?