2015-08-19 13 views
0

在下面定義的類中,我使用公共屬性來保存Excel.Application對象實例(這是我在單例類中的嘗試)。在完成之前在COM對象上運行例程?

每當Finalize例程運行,並調用RestoreApp(),它的一個InvalidComObjectException(下面粘貼)上訪問該Application對象的構件的第一次嘗試拋出。

我寫了這個簡單的測試程序來揣摩什麼鑼上,我覈實,我可以訪問此屬性之前被稱爲Finalize的方法,但我總是得到InvalidComObjectExceptionRetoreApp()方法試圖訪問相同的財產。

MSDN reference for Object Lifetime說:

之前釋放對象時,CLR自動調用該定義子最終確定程序對象最終確定 方法。最終化 方法可以包含需要執行的對象被銷燬 之前代碼...

然而,也許COM對象,其中該對象被部分破壞的特殊情況(RCW斷開形式基礎COM對象)在Finalize方法運行之前?我不知道 - 這似乎正在發生。

任何人都可以指示我如何確保ResoreApp()過程在我的對象與COM對象斷開連接之前運行?


測試:

Sub Main() 
    Dim ExcelTest As New MyExcel 
    Debug.Print(ExcelTest.Excel Is Nothing) 
    Debug.Print(ExcelTest.Excel.DisplayStatusBar) 
End Sub 

的例外:已從其基礎RCW分離不能用來

{「COM對象。 「} _className :沒有
_COMPlusExceptionCode:-532462766
_data:沒有
_dynamicMethods:沒有
_exceptionMethod:沒有
_exceptionMethodString:沒有
_helpURL:沒有
_HResult:-2146233049
_innerException:沒有
_ipForWatsonBuckets:0
_message:「不能使用與其基礎RCW分離的COM對象。」
_remoteStackIndex:0
_remoteStackTraceString:Nothing
_safeSerializationManager:{System.Runtime.Serialization。SafeSerializationManager}
_source:沒有
_stackTrace:{爲SByte()}
_stackTraceString:沒有
_watsonBuckets:沒有
_xcode:-532462766
_xptrs:0
數據:{System.Collections.ListDictionaryInternal}
HelpLink:Nothing
HResult:-2146233049
InnerException:Nothing
IPForWatsonBuckets:0
IsTransient:False
消息:「已與其基礎RCW分離的COM對象無法使用」。
RemoteStackTrace:沒有
s_EDILock:{對象}
來源: 「mscorlib程序」
堆棧跟蹤:「在System.StubHelpers.StubHelpers.StubRegisterRCW(對象pThis)在
Microsoft.Office.Interop.Excel.ApplicationClass.get_DisplayStatusBar ()」
TargetSite:{無效StubRegisterRCW(System.Object的)}
WatsonBuckets:沒有


的類別:

Imports Microsoft.Office 
Imports Microsoft.Office.Interop.Excel 
Imports System.Windows.Forms 


Public Class MyExcel 

    Dim CreateNew As Boolean 
    Dim Prepped As Boolean 
    Dim Prepping As Boolean 


    Dim pExcel As Microsoft.Office.Interop.Excel.Application 
    Dim pStatBar As Boolean 
    Dim pScreenUpdates As Boolean 
    Dim pEventsEnabled As Boolean 
    Dim pAlerts As Boolean 


    Private Property ScreenUpdates As Boolean 
     Get 
      Return pScreenUpdates 
     End Get 
     Set(value As Boolean) 
      pScreenUpdates = value 
     End Set 
    End Property 
    Private Property EventsEnabled As Boolean 
     Get 
      Return pEventsEnabled 
     End Get 
     Set(value As Boolean) 
      pEventsEnabled = value 
     End Set 
    End Property 
    Private Property StatBar As Boolean 
     Get 
      Return pStatBar 
     End Get 
     Set(value As Boolean) 
      pStatBar = value 
     End Set 
    End Property 

    Private Property AlertsDisplay As Boolean 
     Get 
      Return pAlerts 
     End Get 
     Set(value As Boolean) 
      pAlerts = value 
     End Set 
    End Property 

    Public ReadOnly Property Excel() As Microsoft.Office.Interop.Excel.Application 
     Get 
      Try 
       If Not CreateNew Then 
        If pExcel Is Nothing Then pExcel = GetObject([Class]:="Excel.Application") 
       End If 

       If pExcel Is Nothing Then pExcel = CreateObject("Excel.Application") 
      Catch ex As Exception 
       MessageBox.Show(ex.ToString) 
      End Try 
      Return pExcel 
     End Get 
    End Property 

    Public Sub New(Optional ByVal NewExcel As Boolean = True) 
     CreateNew = NewExcel 
     PrepApp() 
    End Sub 

    Private Sub PrepApp() 
     'Set prepping to true to avoid creating a stack overflow 
     Try 
      With Me.Excel 
       ScreenUpdates = .ScreenUpdating 
       EventsEnabled = .EnableEvents 
       StatBar = .DisplayStatusBar 
       AlertsDisplay = .DisplayAlerts 
       .DisplayStatusBar = True 
       .ScreenUpdating = False 
       .EnableEvents = False 
       .DisplayAlerts = False 
      End With 
     Catch ex As Exception 
      MessageBox.Show(ex.ToString) 
     End Try 
    End Sub 

    Private Sub RestoreApp() 
     'Restores the original values for screen updating, event triggers, and status bar display 
     Try 
      With Me.Excel 
       .DisplayStatusBar = StatBar 
       .ScreenUpdating = ScreenUpdates 
       .EnableEvents = EventsEnabled 
       .DisplayAlerts = AlertsDisplay 
      End With 
     Catch ex As Exception 
      MessageBox.Show(ex.ToString) 
     End Try 
    End Sub 

    Protected Overrides Sub Finalize() 
     RestoreApp() 
     MyBase.Finalize() 
    End Sub 
End Class 

回答

0

的VB.Net終結是undeterministic和therfore不允許安全訪問COM創建成員。 你可以使用一個確定性的處理器通過實現IDisposable接口: https://msdn.microsoft.com/en-us/library/s9bwddyx(v=vs.90).aspx

Sub Main() 
    Dim xl As New MyExcel 
    ... 
    xl.Dispose() 
End Sub 

另一種方式是在終結一個新的COM實例工作retore設置:

Private Sub RestoreApp() 
    Dim xl As Microsoft.Office.Interop.Excel.Application = pExcel 
    If Me.CreateNew Then 
     xl = CreateObject("Excel.Application") 
    Else 
     xl = GetObject(, "Excel.Application") 
    End If 

    xl.DisplayStatusBar = StatBar 
    xl.ScreenUpdating = ScreenUpdates 
    xl.EnableEvents = EventsEnabled 
    xl.DisplayAlerts = AlertsDisplay 
    xl.Quit() 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xl) 
End Sub 
+0

我會將其標記爲答案,因爲它在技術上是正確的 - 但我現在要開始另一個問題,即如何使用COM對象安全地執行此操作。看到我的問題[這裏](http://stackoverflow.com/questions/31483635/when-to-call-marshal-finalreleasecomobject-and-more)關於如何處置COM對象,以及由@HansPassant鏈接的答案。 – CBRF23

相關問題