Experts, Please let me know the best way I can do this...
I am working on a VB.Net application that uses the Microsoft.Office.Interop.Excel Object Library to create
I share VB.net code:
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
And, in the class where you plan to implement:
<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()
i test this with Microsoft Excel 2016.
Don't search and call release manually. The Interop process could still run loose if the application crashes catastrophically.
I would register the Interop process to the OS via Job Objects.
Here is a solution: https://stackoverflow.com/a/1307180/160146
My answer is not the best but it works: (Kill Excel processes used by your app)
How do I properly clean up Excel interop objects?
I have insured that all objects are individually declared, used and released by using late binding and carefully declared every object with "ONE DOT". Insured that Excel ranges, sheets, workbooks and the application are all created as objects and closed or quit in the reverse order, being careful that no unanswered dialogs can stop the close or the quit. Used InteropServices.Marshal.FinalReleaseComObject and also put ReleaseComObject in a while loop waiting for count to go to zero in an effort to release every little thing. Always set the object to nothing in the Finally clause of a try/catch block. Done garbage collection and waited for the finalizers. Made sure that I was testing with compiled code and not in the debugger. In other words I have read every expert opinion and tried every expert recommendation. Still have orphaned Excel processes in the task manager that NEVER get cleaned up until the PC is rebooted. The only thing that really works is to KILL THE PROCESS when I am done. I don't kill it until I have done everything else to quit, release and garbage collect.But I cannot afford to have orphaned excel processes hanging around waiting for .NET garbage collection that never gets done.
I had trouble in the past with excel not closing properly.
Here is what I do:
I never did pivot table using the interop.