.net 发布Excel互操作com对象的最佳方法
专家们,请让我知道我能做到这一点的最好方法 我正在开发一个VB.Net应用程序,它使用Microsoft.Office.Interop.Excel对象库在工作簿中创建工作表,并在这些工作表中创建透视表 我的代码如下所示:.net 发布Excel互操作com对象的最佳方法,.net,vb.net,interop,.net,Vb.net,Interop,专家们,请让我知道我能做到这一点的最好方法 我正在开发一个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
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
我知道有很多解决这类问题的方法,但我迷失在所有不同的方法中,想知道什么最适合我目前的情况…
这是一种很好的方法吗?如果不是,还有什么更有效的方法
谢谢 我的答案不是最好的,但它很有效:(杀死应用程序使用的Excel进程)
我过去遇到过excel无法正确关闭的问题 以下是我的工作:
- 请确保先.Close()和.Dispose()保存所有工作簿,然后保存所有应用程序
- 也封送.ReleaseComObject(),但只封送一次。我从来没有像你那样做过for循环
- 然后是GC.Collect()和GC.WaitForPendingFinalizers()
- 通常在开始时将DisplayAlerts和Interactive设置为false。确保没有弹出窗口在后台运行
我从未使用interop创建过pivot表。不要手动搜索和调用release。如果应用程序发生灾难性崩溃,互操作过程仍可能松散运行 我将通过向操作系统注册互操作过程 这里有一个解决方案:我共享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
导入System.Runtime.InteropServices
命名空间作业
公开课工作
实现IDisposable
',
CallingConvention:=CallingConvention.Cdecl)>
共享函数CreateJobObject(a作为IntPtr,lpName作为字符串)作为IntPtr
端函数
公共共享函数SetInformationJobObject(hJob作为IntPtr,infoType作为
JobObjectInfo类型,lpJobObjectInfo作为IntPtr,CBJobObjectInfo长度作为UInteger)作为布尔值
端函数
公共共享函数CloseHandle(标记为IntPtr)为布尔值
端函数
公共共享函数AssignProcessToJobObject(作业为IntPtr,进程为IntPtr)为布尔值
端函数
作为IntPtr的专用m_句柄
私有m_被处理为布尔值=False
公共分新()
m_handle=CreateJobObject(IntPtr.Zero,Nothing)
作为作业对象\基本\限制\信息的尺寸信息=新作业对象\基本\限制\信息()
info.LimitFlags=&H2000
Dim extendedInfo=新作业对象\扩展\限制\信息()
extendedInfo.BasicLimitInformation=info
作为整数的Dim长度=Marshal.SizeOf(GetType(JOBOBJECT\u EXTENDED\u LIMIT\u INFORMATION))
Dim extendedInfoPtr作为IntPtr=Marshal.AllocHGlobal(长度)
Marshal.StructureToPtr(extendedInfo、extendedInfoPtr、False)
如果(不是SetInformationJobObject(m_句柄,JobObjectInfo类型。ExtendedLimitInformation,extendedInfoPtr,长度)),则
抛出新异常(String.Format(“无法设置信息。错误:{0}”,Marshal.GetLastWin32Error()))
如果结束
端接头
#区域“IDisposablembers”
Public Sub Dispose()实现IDisposable.Dispose
处置(真实)
总干事(Me)
端接头
#末端区域
私有子处置(作为布尔值处置)
如果你愿意的话
返回
如果结束
如果是这样的话
如果结束
关闭()
m_=True
端接头
公开分户结算()
闭合手柄(m_手柄)
m_handle=IntPtr.Zero
端接头
公共函数AddProcess(句柄为IntPtr)为布尔值
返回AssignProcessToJobObject(m_句柄,句柄)
端函数
末级
公共枚举JobObjectInfo类型
AssociateCompletionPortInformation=7
基本信息=2
基本限制=4
EndOfJobTimeInformation=6
ExtendedLimitInformation=9
SecurityLimitInformation=5
组信息=11
结束枚举
公共结构安全属性
公共长度为整数
公共lpSecurityDescriptor作为IntPtr
作为整数的公共bInheritHandle
端部结构
结构作业对象\基本\限制\信息
公共PerProcessUserTimeLimit作为Int64
公共PerJobUserTimeLimit As Int64
公共标志为Int16
公共最小工作集尺寸为UInt32
公共最大工作集大小为UInt32
公共ActiveProcessLimit作为Int16
公共亲和力为Int64
公共优先级类As Int16
公共调度类为Int16
端部结构
结构IO_计数器
公共读取操作计数为UInt64
公共写入操作计数为UInt64
公共其他操作计数为UInt64
公共ReadTransferCount为UInt64
公共WriteTransferCount为UInt64
公共OtherTransferCount为UInt64
端部结构
结构作业对象\u扩展\u限制\u信息
公共基本信息作为作业对象\基本\限制\信息
作为IO_计数器的公共IoInfo
公共进程MemoryLimit作为UInt32
公共工作记忆限制为UInt32
公共峰值过程被存储为UInt32
公共峰值工作记忆为UInt32
端部结构
结束命名空间
在您计划实施的课程中:
<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()
公共共享函数GetWindowThreadProcessId(hWnd作为IntPtr,ByRef lpdwProcessId作为UInteger)作为UInteger
端函数
"工具",
Dim oExcelApp=新的Microsoft.Office.Interop.Excel.Application
将作业设置为作业。作业=新作业。作业()
尺寸pid为UInteger=0
GetWindowThreadProcessId(新的IntPtr(oExcelApp.Hwnd),pid)
job.AddProcess(Process.GetProcessById(pid.Handle)
oExcelApp.Workbooks.Open(RutaArchivoExcel)
'在这里输入工作代码
oExcelApp.Workbook(1.Close)()
oExcelApp.Quit()
'然后正确地处理excel应用程序和windows发行版并适当地分配该进程
job.Dispose()
我用Microsoft Excel 2016对此进行了测试。我已确保所有对象都是通过使用后期绑定进行单独声明、使用和发布的,并小心地用“一点”声明每个对象。确保