专家,请让我知道我能做到这一点的最好方法......
我正在开发一个VB.Net应用程序,该应用程序使用Microsoft.Office.Interop.Excel对象库在工作簿中创建工作表,并在这些工作表中创建数据透视表。
我的代码看起来像这样:
Dim ExcelApp As New Microsoft.Office.Interop.Excel.Application
Dim wbk As Microsoft.Office.Interop.Excel.Workbook = Nothing
Dim wksRawData As Microsoft.Office.Interop.Excel.Worksheet = Nothing
Dim wksPvtTbl As Microsoft.Office.Interop.Excel.Worksheet = Nothing
Dim pvtCache As Microsoft.Office.Interop.Excel.PivotCache = Nothing
Dim pvtTables As Microsoft.Office.Interop.Excel.PivotTables = Nothing
Dim pvtTable As Microsoft.Office.Interop.Excel.PivotTable = Nothing
Dim r1 As Microsoft.Office.Interop.Excel.PivotField = Nothing
Dim r2 As Microsoft.Office.Interop.Excel.PivotField = Nothing
Dim df1 As Microsoft.Office.Interop.Excel.PivotField = Nothing
Try
... Create the objects, put in the information
Catch ex As Exception
MessageBox.Show("There was an error creating the Excel file", "Error Creating File", MessageBoxButtons.OK)
Finally
ReleaseObject(r1)
ReleaseObject(r2)
ReleaseObject(df1)
ReleaseObject(pvtTable)
ReleaseObject(pvtTables)
ReleaseObject(pvtCache)
ReleaseObject(wksRawData)
ReleaseObject(wksPvtTbl)
ReleaseObject(wbk)
ExcelApp.DisplayAlerts = True
ExcelApp.Quit()
ReleaseObject(ExcelApp)
ExcelApp = Nothing
wbk = Nothing
wksRawData = Nothing
GC.Collect()
End Try
然后,我的发布对象的代码如下所示:
Public Sub ReleaseObject(ByRef Reference As Microsoft.Office.Interop.Excel.Application)
Dim i As Integer
If Reference IsNot Nothing Then
i = System.Runtime.InteropServices.Marshal.ReleaseComObject(Reference)
While i > 0
i = System.Runtime.InteropServices.Marshal.ReleaseComObject(Reference)
End While
Reference = Nothing
End If
End Sub
Public Sub ReleaseObject(ByRef Reference As Microsoft.Office.Interop.Excel.Workbook)
Dim i As Integer
If Reference IsNot Nothing Then
i = System.Runtime.InteropServices.Marshal.ReleaseComObject(Reference)
While i > 0
i = System.Runtime.InteropServices.Marshal.ReleaseComObject(Reference)
End While
Reference = Nothing
End If
End Sub
... etc
我知道有很多解决方案可以解决这类问题,但是我迷失在所有不同的问题中,知道什么最适合我目前的情况...... 这是一个很好的方法吗,如果不是,那么什么是更有效的方法?
感谢!!!
答案 0 :(得分:2)
不要手动搜索和呼叫释放。如果应用程序灾难性地崩溃,Interop进程仍然可能会松动。
我会通过Job Objects向操作系统注册Interop流程。
答案 1 :(得分:0)
我的答案不是最好的,但它有效:(杀死你的应用程序使用的Excel进程)
答案 2 :(得分:0)
过去我遇到麻烦没有正常关闭。
以下是我的工作:
我从来没有使用互操作数据表。
答案 3 :(得分:0)
我共享VB.net代码:
Imports System.Runtime.InteropServices
Namespace Jobs
Public Class Job
Implements IDisposable
<DllImport("kernel32.dll", CharSet:=CharSet.Unicode)>',
CallingConvention:=CallingConvention.Cdecl)>
Shared Function CreateJobObject(a As IntPtr, lpName As String) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function SetInformationJobObject(hJob As IntPtr, infoType As
JobObjectInfoType, lpJobObjectInfo As IntPtr, cbJobObjectInfoLength As UInteger) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)>
Public Shared Function CloseHandle(Token As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)>
Public Shared Function AssignProcessToJobObject(job As IntPtr, process As IntPtr) as Boolean
End Function
Private m_handle As IntPtr
Private m_disposed As Boolean = False
Public Sub New()
m_handle = CreateJobObject(IntPtr.Zero, Nothing)
Dim info As JOBOBJECT_BASIC_LIMIT_INFORMATION = New JOBOBJECT_BASIC_LIMIT_INFORMATION()
info.LimitFlags = &H2000
Dim extendedInfo = New JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
extendedInfo.BasicLimitInformation = info
Dim length As Integer = Marshal.SizeOf(GetType(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))
Dim extendedInfoPtr As IntPtr = Marshal.AllocHGlobal(length)
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, False)
If (Not SetInformationJobObject(m_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, length)) Then
Throw New Exception(String.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error()))
End If
End Sub
#Region "IDisposableMembers"
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
Private Sub Dispose(disposing As Boolean)
If m_disposed Then
Return
End If
If disposing Then
End If
Close()
m_disposed = True
End Sub
Public Sub Close()
CloseHandle(m_handle)
m_handle = IntPtr.Zero
End Sub
Public Function AddProcess(handle As IntPtr) As Boolean
Return AssignProcessToJobObject(m_handle, handle)
End Function
End Class
Public Enum JobObjectInfoType
AssociateCompletionPortInformation = 7
BasicLimitInformation = 2
BasicUIRestrictions = 4
EndOfJobTimeInformation = 6
ExtendedLimitInformation = 9
SecurityLimitInformation = 5
GroupInformation = 11
End Enum
<StructLayout(LayoutKind.Sequential)>
Public Structure SECURITY_ATTRIBUTES
Public nLength As Integer
Public lpSecurityDescriptor As IntPtr
Public bInheritHandle As Integer
End Structure
<StructLayout(LayoutKind.Sequential)>
Structure JOBOBJECT_BASIC_LIMIT_INFORMATION
Public PerProcessUserTimeLimit As Int64
Public PerJobUserTimeLimit As Int64
Public LimitFlags As Int16
Public MinimumWorkingSetSize As UInt32
Public MaximumWorkingSetSize As UInt32
Public ActiveProcessLimit As Int16
Public Affinity As Int64
Public PriorityClass As Int16
Public SchedulingClass As Int16
End Structure
<StructLayout(LayoutKind.Sequential)>
Structure IO_COUNTERS
Public ReadOperationCount As UInt64
Public WriteOperationCount As UInt64
Public OtherOperationCount As UInt64
Public ReadTransferCount As UInt64
Public WriteTransferCount As UInt64
Public OtherTransferCount As UInt64
End Structure
<StructLayout(LayoutKind.Sequential)>
Structure JOBOBJECT_EXTENDED_LIMIT_INFORMATION
Public BasicLimitInformation As JOBOBJECT_BASIC_LIMIT_INFORMATION
Public IoInfo As IO_COUNTERS
Public ProcessMemoryLimit As UInt32
Public JobMemoryLimit As UInt32
Public PeakProcessMemoryUsed As UInt32
Public PeakJobMemoryUsed As UInt32
End Structure
End Namespace
并且,在您计划实现的类中:
<DllImport("user32.dll", SetLastError:=True)>
Public Shared Function GetWindowThreadProcessId(hWnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger
End Function
'Implements
Dim oExcelApp = New Microsoft.Office.Interop.Excel.Application
Dim job As Jobs.Job = New Jobs.Job()
Dim pid As UInteger = 0
GetWindowThreadProcessId(New IntPtr(oExcelApp.Hwnd), pid)
job.AddProcess(Process.GetProcessById(pid).Handle)
oExcelApp.Workbooks.Open(RutaArchivoExcel)
'Code work code here
oExcelApp.Workbooks(1).Close()
oExcelApp.Quit()
'Then Dispose correctly the excel app and windows distroy appropiately the process
job.Dispose()
我使用Microsoft Excel 2016对此进行了测试。
答案 4 :(得分:0)
我确保所有对象都是通过后期绑定单独声明,使用和释放的,并使用“ ONE DOT”仔细声明了每个对象。确保将Excel范围,工作表,工作簿和应用程序都创建为对象,并以相反的顺序关闭或退出,请注意,任何未回答的对话框都不能停止关闭或退出。使用InteropServices.Marshal.FinalReleaseComObject,并将ReleaseComObject放入while循环中,等待计数变为零,以释放所有小物件。在try / catch块的Final子句中,始终将对象设置为空。完成垃圾收集并等待终结器。确保我正在使用编译的代码而不是在调试器中进行测试。换句话说,我已经阅读了每位专家的意见并尝试了每位专家的建议。在任务管理器中仍然有孤立的Excel进程,除非重新启动PC,否则永远不会清理它们。唯一有效的方法是在完成后杀死进程。在完成其他所有退出,释放和垃圾收集的工作之前,我不会杀死它。但是我无法承受孤立的excel进程徘徊,等待无法完成的.NET垃圾收集。