如何从Excel VBA中释放进程中的COM服务器对象

如何强制Excel(2007)VBA释放对COM服务器对象的引用?

我已经在Visual Foxpro 9 SP2中编写了一个inprocess(单实例DLL)COM服务器,它是从我的开发机器上的Excel 2007 VBA代码实例化的。 Excel似乎是持有一个COM对象/ DLL的引用,即使我设置=无。 这可以防止由于“文件访问被拒绝TestCOM.dll”消息重buildDLL,直到我退出Excel,每次我想要进行更改和testing时都很痛苦。

我已经把代码编译成了一个非常简单的testing设置:VFP9项目(TestCOM)只有一个.prg文件,内容如下

DEFINE CLASS TestClass As Session OLEPUBLIC ENDDEFINE 

VBA代码如下:

 Sub Test() Set objTest = CreateObject("TestCOM.TestClass") Set objTest = Nothing End Sub 

我已经尝试删除在VBA项目中的COM服务器库的引用,但这没有任何区别。 我已经试过,没有DIMing的对象variables,它没有任何区别。 我曾尝试创build一个新的VFP DLL项目,但问题依然存在。

如果我作为一个INPROCESS / DLL生成VFP应用程序/ DLL并运行VBA代码,我得到这个问题,但如果我build立它作为一个OUTOFPROCESS / EXE并运行VBA代码,我不会得到这个问题。

我在COM对象清理中发现了一个非常类似的问题,只不过我的COM服务器是用Visual Foxpro 9 SP2编写的,而与C#相关,而OP没有详细解释他们是如何解决问题的,所以我不知道如何解决它; 如果这是可能的。

用于从DLL中的代码实例化COM类的过程是,Excel调用COM库层以使用ProgID或ClassID查找您的实现。 当你有一个inproc服务器,这意味着它find你的DLL的path,并使用LoadLibrary将它加载到客户端进程,然后创build类工厂并调用DLL中的方法。 所以最终的结果是,Excel调用DLL上的LoadLibrary,并locking文件,直到Excel调用句柄上的FreeLibrary。

使用COM接口,你不能控制这个。 您可以调用CoCreateInstance()(或者从VBA中使用New或CreateObject来创build对象,该对象将在下面调用此Win32 API)。 这个实现处理LoadLibrary和其他的东西,直到你拿到一个接口指针来处理。 某些应用程序将定期调用CoFreeUnusedLibraries()来尝试释放当前未使用的已加载的COM dll。 默认的类工厂实现维护一个创build的对象的计数器,可以用来确定一个DLL是否正在使用 – 但是这并不总是可靠的,因为COM类的作者可能不遵守规则。 退出Excel显然会释放该文件的locking。

当你创build你的COM类作为一个进程外的服务器 – 它住在一个单独的可执行文件或DLL的生命周期pipe理不同。 Excel不再拥有对DLL的locking,释放COM实例可能允许主机进程退出。

您可以将DLL作为本地服务器(进程外),通过安排由DllHost托pipe。 如果您使用OleView实用程序并find您的类ProgId,那么您可以在代理进程(dllhost)中启用托pipe。 自从我这样做以来已经有一段时间了,但是networking上应该有关于使用代理托pipe的信息。 很显然,在进程外托pipe一个COM对象会使得一切都变慢,并引入各种编组问题的可能性。 如果你保持oleautomation兼容接口应该没问题。

添加一个较短的答案….

释放DLL是一个棘手的问题,也是开发人员在Excel使用的进程COM组件中很熟悉的一个问题。

有两个条件需要满足

1)不要使用早期绑定库引用(Tools-> Reference),而是使用后期绑定。 早期的绑定工具参考将持有一个锁。

2)调用CoFreeUnusedLibraries卸载不再有客户端的COM服务器。

从你的示例代码你已经晚了绑定,但请检查您的参考。 虽然点2)在payyhoyts答案中提到,没有给出代码。

这是一个复制和可粘贴的声明

 Private Declare Sub CoFreeUnusedLibraries Lib "ole32.dll" ()