1

我正在编写一个脚本,打开一个表格并将其从 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()

这是错误 在此处输入图像描述

任何想法?

*更新:奇怪的是,脚本在我办公室的电脑上运行没有任何错误,但在我的笔记本电脑上却没有 =.=

4

1 回答 1

0

错误消息“Call was denied by callee”对应于错误代码RPC_E_SERVERCALL_RETRYLATER 0x8001010A。代码的名称已经包含了解决方案的线索。COM 服务器(即 Office 应用程序)太忙,目前无法接听电话 - 但您可以稍后重试。

重试可以通过实施如何处理:修复“应用程序忙”和“呼叫被被呼叫者拒绝”错误IOleMessageFilter中的描述来处理。

然而,实现这个接口并不简单,因为我们在一个 PowerShell 脚本中。尽管如此,还是可以做到的(感谢@MarkRucker 的出色回答):

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()
于 2015-12-08T08:37:08.497 回答