2013-09-26 109 views
4

我有一个小工具功能于一体PowerShell脚本:PowerShell中释放COM对象

function Unzip-File{ 
    param(
     [Parameter(Mandatory=$true)] 
     [string]$ZipFile, 
     [Parameter(Mandatory=$true)] 
     [string]$Path 
    ) 

    $shell=New-Object -ComObject shell.application 

    $zip = $shell.namespace($ZipFile) 
    $target = $shell.NameSpace($Path) 
    $target.CopyHere($zip.Items()) 
} 

我应该清理脚本中的COM对象?还是PowerShell足够智能地自动垃圾COM对象?

我读过Getting Rid of a COM Object (Once and For All)盲目应用:

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($zip) 
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($target) 
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell) 

但我不知道这是否需要。

在本地函数中使用COM对象的正确模式是什么?

+0

我认为你找到的文章可能是正确的。对“Remove-Variable”的注释进一步阅读以释放对变量的任何其他引用,然后GC可能会处理其余的部分。如果你的对象有一个'Dispose()'方法,你也可以调用它(在释放之前)。 – alroc

回答

1

我通常使用此功能:

function Release-Ref ($ref) { 

[System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) | out-null 
[System.GC]::Collect() 
[System.GC]::WaitForPendingFinalizers() 

} 

,因为我已经注意到,我的comobject始终保持活着,我觉得PowerShell 2.0中是不是能不再被使用删除comobject。

[System.Runtime.InteropServices.Marshal]::ReleaseComObject($ref) 

(见here)返回与对象相关联的RCW的引用计数的新值。该值通常为零,因为RCW只保留对被包装的COM对象的一个​​引用,而不管被调用的被管理客户端的数量。 我注意到,对于shell.application,您需要调用它直到此值变为0.

要测试是否所有引用都已释放,您可以尝试在值为0时读取$ shell的值:它返回一个错误..

+0

如果我的对象被正确清除,有没有办法“监视”? –

+0

通常我使用办公自动化,我只是看相对过程(即excel.exe),如果不再存在,但与shell.application我有一些怀疑它的工作... –

+1

我相信'ReleaseComObject'是键。我也相信另外两条线不是强制性的。对于C#,我总是读到最好在决定时让GC工作。我会在PS中保留这个建议。 –