我正在编写一个脚本,打开并将表格从excel复制到word,但每次运行的结果都不同。它起初做得很好,但经过几次运行后,恼人的红色文本开始出现(特别是"调用被被调用者拒绝"并且选择对象的方法如$ wordObject.Selection.TypeParagraph无法运行,因为$ wordObject.Selection成为一个空值表达式。
关闭后我尝试使用ReleaseComObject,但问题仍然存在
这是因为我在同一部分使用两个ComObject吗? 我的脚本结构如下:
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$Workbook = $excel.Workbooks.open($pathEx)
$range = $workbook.activesheet.usedrange
$cop = $range.Copy()
$wd = new-object -comObject Word.application
$wd.visible = $true
$doc = $wd.documents.open($pathWd)
$wdSelection = $wd.Selection
$a = $wdSelection.Endkey(6,0)
$wdSelection.typeparagraph()
$wd.Selection.paste()
关闭并退出:
$workbook.close($false)
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
Remove-Variable workbook, excel
$doc.saveAs()
$wd.Quit()
这是错误 enter image description here
有什么想法吗?
*更新:奇怪的是,脚本在我办公室的电脑上没有任何错误,而不是我的笔记本电脑=。=
答案 0 :(得分:0)
错误消息“呼叫被被叫方拒绝”对应于错误代码RPC_E_SERVERCALL_RETRYLATER 0x8001010A
。代码的名称已经包含解决方案的线索。 COM服务器(即Office应用程序)太忙而且此刻无法接听电话 - 但您可以稍后重试。
可以按照How to: Fix 'Application is Busy' and 'Call was Rejected By Callee' Errors中的说明实施IOleMessageFilter
来处理重试。
但是,实现此接口并不简单,因为我们在PowerShell脚本中。尽管如此,它可以完成(感谢@MarkRucker的great answer):
param([String]$pathEx, [String]$pathWd)
$source = @"
namespace EnvDteUtils
{
using System;
using System.Runtime.InteropServices;
public class MessageFilter : IOleMessageFilter
{
// Class containing the IOleMessageFilter
// thread error-handling functions.
// Start the filter.
public static void Register()
{
IOleMessageFilter newFilter = new MessageFilter();
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(newFilter, out oldFilter);
}
// Done with the filter, close it.
public static void Revoke()
{
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(null, out oldFilter);
}
//
// IOleMessageFilter functions.
// Handle incoming thread requests.
int IOleMessageFilter.HandleInComingCall(int dwCallType,
System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr
lpInterfaceInfo)
{
//Return the flag SERVERCALL_ISHANDLED.
return 0;
}
// Thread call was rejected, so try again.
int IOleMessageFilter.RetryRejectedCall(System.IntPtr
hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == 2)
// flag = SERVERCALL_RETRYLATER.
{
// Retry the thread call immediately if return >=0 &
// <100.
return 99;
}
// Too busy; cancel call.
return -1;
}
int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee,
int dwTickCount, int dwPendingType)
{
//Return the flag PENDINGMSG_WAITDEFPROCESS.
return 2;
}
// Implement the IOleMessageFilter interface.
[DllImport("Ole32.dll")]
private static extern int
CoRegisterMessageFilter(IOleMessageFilter newFilter, out
IOleMessageFilter oldFilter);
}
[ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(
int dwCallType,
IntPtr hTaskCaller,
int dwTickCount,
IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(
IntPtr hTaskCallee,
int dwTickCount,
int dwRejectType);
[PreserveSig]
int MessagePending(
IntPtr hTaskCallee,
int dwTickCount,
int dwPendingType);
}
}
"@
Add-Type -TypeDefinition $source
[EnvDTEUtils.MessageFilter]::Register()
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$Workbook = $excel.Workbooks.open($pathEx)
$range = $workbook.activesheet.usedrange
$cop = $range.Copy()
$wd = new-object -comObject Word.application
$wd.visible = $true
$doc = $wd.documents.open($pathWd)
$wdSelection = $wd.Selection
$a = $wdSelection.Endkey(6,0)
$wdSelection.typeparagraph()
$wd.Selection.paste()