Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/27.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
如何从Excel 2007 VBA模块中调用System.Runtime.InteropServices.Marshal.ReleaseComObject_Com_Excel_Com Interop_Excel Interop_Vba - Fatal编程技术网

如何从Excel 2007 VBA模块中调用System.Runtime.InteropServices.Marshal.ReleaseComObject

如何从Excel 2007 VBA模块中调用System.Runtime.InteropServices.Marshal.ReleaseComObject,com,excel,com-interop,excel-interop,vba,Com,Excel,Com Interop,Excel Interop,Vba,我想调用System.Runtime.InteropServices.Marshal.ReleaseComObject(obj),调用我在VBA代码中从工作簿关闭事件中实例化的某些第三方COM对象,如下所示: Public Sub disconnect(obj As Variant) Dim refs As Long refs = 0 If Not obj Is Nothing Then Do

我想调用System.Runtime.InteropServices.Marshal.ReleaseComObject(obj),调用我在VBA代码中从工作簿关闭事件中实例化的某些第三方COM对象,如下所示:

    Public Sub disconnect(obj As Variant)
        Dim refs As Long
        refs = 0

        If Not obj Is Nothing Then
            Do
                refs = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
            Loop While (refs > 0)
        End If
    End Sub
但是,我得到了一个
编译错误:使用上面代码突出显示的
系统的
限定符无效。搜索似乎不会返回任何从VBA宏调用System.Runtime方法的VBA代码-我只能找到VB.Net自动化Excel。我甚至不确定这是否可能


我试图解决这个问题:通过确保在Excel退出之前正确处理这些第三方COM对象

我没有使用VBA,但我不认为它是.NET语言,因此自然不能在VBA中使用System.Runtime.InteropServices.Marshal之类的.NET Framework类

确实要退出Excel时删除对COM对象的所有引用吗?对于COM对象的每个引用,请确保按如下方式放置线:

obj = Nothing ' Where "obj" is a reference to the COM object
如果这不能解决问题,那么问题也可能是循环引用。COM对象是否存储对您的VBA对象的引用,而VBA对象又保存对COM对象的引用?如果是这样,将创建一个循环引用,并且永远不会释放对象。我在搜索其他内容,发现了一篇与你非常相似的帖子:

如果这就是问题所在,那么您确实需要一种手动释放COM对象的方法(并多次释放,直到引用计数为零),类似于Marshal.ReleaseComObject,但我不知道如何在VBA中做到这一点

两个其他类似的线程:


我没有使用VBA,但我认为它不是.NET语言,因此自然不能在VBA中使用System.Runtime.InteropServices.Marshall之类的.NET Framework类

确实要退出Excel时删除对COM对象的所有引用吗?对于COM对象的每个引用,请确保按如下方式放置线:

obj = Nothing ' Where "obj" is a reference to the COM object
如果这不能解决问题,那么问题也可能是循环引用。COM对象是否存储对您的VBA对象的引用,而VBA对象又保存对COM对象的引用?如果是这样,将创建一个循环引用,并且永远不会释放对象。我在搜索其他内容,发现了一篇与你非常相似的帖子:

如果这就是问题所在,那么您确实需要一种手动释放COM对象的方法(并多次释放,直到引用计数为零),类似于Marshal.ReleaseComObject,但我不知道如何在VBA中做到这一点

两个其他类似的线程:


即使在仔细检查和删除循环引用之后,我也无法使用推荐的仅使用VBA的方法解决僵尸问题

额外的搜索找到了一种调用
ReleaseCom
方法的方法

使用本教程和新安装的VS2010 Express副本,我能够创建一个可从VBA调用的COM可见dll

以下是经过轻微修改的包装器以及如何构建dll:

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.EnterpriseServices;


    namespace ComDisposerLib
    {
        [ClassInterface(ClassInterfaceType.None)]
        [ComponentAccessControl(false)]
        public class ComDisposer : System.EnterpriseServices.ServicedComponent, IDisposable, ComDisposerLib.IComDispose
        {
            private List<Object> _comObjs;

            public ComDisposer()
            {
                _comObjs = new List<Object>();
            }

            ~ComDisposer()
            {
                Dispose(false);
            }

            public Object Add(Object o)
            {
                if (o != null && o.GetType().IsCOMObject)
                    _comObjs.Add(o);
                return o;
            }

            public void Clear()
            {
                Dispose(true);
            }

            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    for (int i = _comObjs.Count - 1; i >= 0; --i)
                        Marshal.FinalReleaseComObject(_comObjs[i]);
                    _comObjs.Clear();
                }
            }

            void IDisposable.Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
    }
要生成、创建新的类库项目,请添加对
System.Runtime.InteropServices
System.enterpriseseservices
的引用,启用“对程序集进行签名”(在“项目/属性/签名”下的菜单中),然后选择或创建密钥文件。添加类和接口代码文件。在AssemblyInfo.cs文件(位于“属性”下)中,添加

建造。如果一切顺利,您可以按如下方式注册dll:

regsvcs "C:\Documents and Settings\username\My Documents\Visual Studio 2010\Projects\ComDispose\ComDispose\obj\Release\ComDisposer.dll"
Sub disposeGlobalComObjects()
' global scope objects used only to simplify example 

    Dim cd As ComDisposer
    Set cd = New ComDisposer

    If Not SomeGlobalComObject Is Nothing Then
        cd.Add SomeGlobalComObject
        Set SomeGlobalComObject = Nothing
    End If
    If Not AnotherGlobalComObject Is Nothing Then
        cd.Add AnotherGlobalComObject
        Set AnotherGlobalComObject = Nothing
    End If
    cd.Dispose
End Sub
在VBA中,添加对新COM库的引用后,按如下方式使用它:

regsvcs "C:\Documents and Settings\username\My Documents\Visual Studio 2010\Projects\ComDispose\ComDispose\obj\Release\ComDisposer.dll"
Sub disposeGlobalComObjects()
' global scope objects used only to simplify example 

    Dim cd As ComDisposer
    Set cd = New ComDisposer

    If Not SomeGlobalComObject Is Nothing Then
        cd.Add SomeGlobalComObject
        Set SomeGlobalComObject = Nothing
    End If
    If Not AnotherGlobalComObject Is Nothing Then
        cd.Add AnotherGlobalComObject
        Set AnotherGlobalComObject = Nothing
    End If
    cd.Dispose
End Sub
早期测试表明它正在工作,即Excel干净地关闭,不再创建僵尸进程


有趣的是,我刚刚遇到了这个问题,如果您无法访问客户端计算机上的注册表,它可能会很有用。

即使在仔细检查和删除循环引用之后,我也无法使用推荐的仅VBA的方法解决僵尸问题

额外的搜索找到了一种调用
ReleaseCom
方法的方法

使用本教程和新安装的VS2010 Express副本,我能够创建一个可从VBA调用的COM可见dll

以下是经过轻微修改的包装器以及如何构建dll:

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.EnterpriseServices;


    namespace ComDisposerLib
    {
        [ClassInterface(ClassInterfaceType.None)]
        [ComponentAccessControl(false)]
        public class ComDisposer : System.EnterpriseServices.ServicedComponent, IDisposable, ComDisposerLib.IComDispose
        {
            private List<Object> _comObjs;

            public ComDisposer()
            {
                _comObjs = new List<Object>();
            }

            ~ComDisposer()
            {
                Dispose(false);
            }

            public Object Add(Object o)
            {
                if (o != null && o.GetType().IsCOMObject)
                    _comObjs.Add(o);
                return o;
            }

            public void Clear()
            {
                Dispose(true);
            }

            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    for (int i = _comObjs.Count - 1; i >= 0; --i)
                        Marshal.FinalReleaseComObject(_comObjs[i]);
                    _comObjs.Clear();
                }
            }

            void IDisposable.Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
    }
要生成、创建新的类库项目,请添加对
System.Runtime.InteropServices
System.enterpriseseservices
的引用,启用“对程序集进行签名”(在“项目/属性/签名”下的菜单中),然后选择或创建密钥文件。添加类和接口代码文件。在AssemblyInfo.cs文件(位于“属性”下)中,添加

建造。如果一切顺利,您可以按如下方式注册dll:

regsvcs "C:\Documents and Settings\username\My Documents\Visual Studio 2010\Projects\ComDispose\ComDispose\obj\Release\ComDisposer.dll"
Sub disposeGlobalComObjects()
' global scope objects used only to simplify example 

    Dim cd As ComDisposer
    Set cd = New ComDisposer

    If Not SomeGlobalComObject Is Nothing Then
        cd.Add SomeGlobalComObject
        Set SomeGlobalComObject = Nothing
    End If
    If Not AnotherGlobalComObject Is Nothing Then
        cd.Add AnotherGlobalComObject
        Set AnotherGlobalComObject = Nothing
    End If
    cd.Dispose
End Sub
在VBA中,添加对新COM库的引用后,按如下方式使用它:

regsvcs "C:\Documents and Settings\username\My Documents\Visual Studio 2010\Projects\ComDispose\ComDispose\obj\Release\ComDisposer.dll"
Sub disposeGlobalComObjects()
' global scope objects used only to simplify example 

    Dim cd As ComDisposer
    Set cd = New ComDisposer

    If Not SomeGlobalComObject Is Nothing Then
        cd.Add SomeGlobalComObject
        Set SomeGlobalComObject = Nothing
    End If
    If Not AnotherGlobalComObject Is Nothing Then
        cd.Add AnotherGlobalComObject
        Set AnotherGlobalComObject = Nothing
    End If
    cd.Dispose
End Sub
早期测试表明它正在工作,即Excel干净地关闭,不再创建僵尸进程


有趣的是,我刚刚遇到了这个问题,如果您无法访问客户端计算机上的注册表,它可能会很有用。

谢谢。我将寻找循环引用,因为它是最有可能的罪魁祸首。顺便说一句,你需要一个相邻的URL之间的空行,否则只有第一个将被转换为一个实时链接。(我会为您修复它,但还没有必要的编辑权限。)不得不求助于创建COM包装。我发布了我的解决方案并移动了“接受”标志。谢谢。我将寻找循环引用,因为它是最有可能的罪魁祸首。顺便说一句,你需要一个相邻的URL之间的空行,否则只有第一个将被转换为一个实时链接。(我会为您修复它,但还没有必要的编辑权限。)不得不求助于创建COM包装。我发布了我的解决方案并移动了“接受”标志。