|
Albert Siagian
Guest
|
Hello,
I am trying to use ReleaseComObjects, but the results are very confusing, sometimes it works and sometimes it doesn't. I guess probably because I don't know when it is creating new objects (increment the counter) and when it is referencing. Appreciate more detail information about this.
2 scenarios:
Scenario 1: Procedure1 calls Procedure2, and Procedure3 calls Procedure3. Where should I use ReleaseComObjects ?
Sub Procedure1()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
ExcelApp.Workbooks.Open("file1.xlsx")
wb = ExcelApp.ActiveWorkbook
ws = TryCast(wb.ActiveSheet, Excel.Worksheet)
ws.Cells.Range("A1").Value = 123
Procedure2()
End Sub
Sub Procedure2()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
ExcelApp.Workbooks.Open("file2.xlsx")
wb = ExcelApp.ActiveWorkbook
ws = TryCast(wb.ActiveSheet, Excel.Worksheet)
ws.Cells.Range("A2").Value = 456
Procedure3()
End Sub
Sub Procedure3()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
ExcelApp.Workbooks.Open("file3.xlsx")
wb = ExcelApp.ActiveWorkbook
ws = TryCast(wb.ActiveSheet, Excel.Worksheet)
ws.Cells.Range("A3").Value = 789
End Sub
Scenario 2: Procedure11 calls Procedure22 followed by Procedure33. Where should I use ReleaseComObjects ?
Sub Procedure11()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
ExcelApp.Workbooks.Open("file1.xlsx")
wb = ExcelApp.ActiveWorkbook
ws = TryCast(wb.ActiveSheet, Excel.Worksheet)
ws.Cells.Range("A1").Value = 123
Procedure22()
Procedure33()
End Sub
Sub Procedure22()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
ExcelApp.Workbooks.Open("file2.xlsx")
wb = ExcelApp.ActiveWorkbook
ws = TryCast(wb.ActiveSheet, Excel.Worksheet)
ws.Cells.Range("A2").Value = 456
End Sub
Sub Procedure33()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
ExcelApp.Workbooks.Open("file3.xlsx")
wb = ExcelApp.ActiveWorkbook
ws = TryCast(wb.ActiveSheet, Excel.Worksheet)
ws.Cells.Range("A3").Value = 789
End Sub
Thanks
Albert |
|
Posted 20 Jul, 2016 23:19:37
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 19138
Joined: 2006-05-11
|
Hello Albert,
Actually, these are the very same scenario: each procedure creates COM object on its own. You need to release a COM object after use. since every procedure creates wb = ExcelApp.ActiveWorkbook, every procedure should release it after use. "After use" in your case is "after retrieving wb.ActiveSheet".
In https://www.add-in-express.com/docs/net-office-tips.php#releasing, we give this rule:
Don't chain COM calls like in OutlookApp.Explorers.Count, ExcelApp.Workbooks[1] (C#) or PowerPointApp.Presentations.Item(1) (VB.NET).
This rule is broken in these constructs "ExcelApp.Workbooks.Open()" and "ws.Cells.Range().Value".
"ws = TryCast(wb.ActiveSheet, Excel.Worksheet)" leaves a COM object non-released if the ActiveSheet property returns a Chart.
Also, Workbooks.Open() returns a COM object.
Below is a variant of rewriting such a procedure:
Sub Procedure33()
Dim ci = AddinModule.CurrentInstance
Dim ExcelApp = ci.ExcelApp
Dim wbs As Excel.Workbooks = ExcelApp.Workbooks
Dim wb As Excel.Workbook = wbs.Open("file3.xlsx")
Marshal.ReleaseComObject(wbs): wbs = Nothing
dim sheet as Object = wb.ActiveSheet
Marshal.ReleaseComObject(wb): wb = Nothing
if (TypeOf sheet Is Excel.Worksheet) Then
Dim ws As Excel.Worksheet = CType(wb.ActiveSheet, Excel.Worksheet)
Dim cells as Excel.Range = ws.Cells
dim r as Excel.Range = cells.Range("A3")
Marshal.ReleaseComObject(cells): cells= Nothing
r.Value = 789
Marshal.ReleaseComObject(r): r= Nothing
end if
Marshal.ReleaseComObject(sheet ): sheet = Nothing
End Sub
Andrei Smolin
Add-in Express Team Leader |
|
Posted 21 Jul, 2016 01:18:03
|
|
Top
|
|
Albert Siagian
Guest
|
Andrei Smolin writes:
"ExcelApp.Workbooks.Open()" and "ws.Cells.Range().Value"
Hello Andrei,
Thanks. I use these quite a lot. Will re-think about it.
On the other hand, will this incorrect use of creating objects and release com objects, causing issue with Visual Studio registering the add-in ? For some random reason and non-replicated steps, Visual Studio crashes and restarting automatically many times. At the bottom left, it says "registering xxx.dll". I always thought this is due to unreleased com objects, but never figure it out why/how it happens. |
|
Posted 21 Jul, 2016 01:36:20
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 19138
Joined: 2006-05-11
|
Albert Siagian writes:
I always thought this is due to unreleased com objects
This isn't so. When the constructor is run, the Excel object model isn't used. At least, it shouldn't be used.
Move all custom code from the constructor of the add-in module to the AddinInitialize or OnRibbonBeforeCreate event handler. The same applies to initializers of all complex-type variable declared on the class level in the add-in module.
Andrei Smolin
Add-in Express Team Leader |
|
Posted 21 Jul, 2016 01:41:01
|
|
Top
|
|
Albert Siagian
Guest
|
Hello Andrei,
By "custom code" in the constructor, do you mean like below (at top of AddinModule.vb) ?
Private test1 as String = "ABC"
Public test2 as Integer = "123"
Regards
Albert |
|
Posted 21 Jul, 2016 01:49:07
|
|
Top
|
|
Andrei Smolin
Add-in Express team
Posts: 19138
Joined: 2006-05-11
|
These are initializers of simple-type variables. Custom code is any code *you* add to the constructor of the add-in module.
Andrei Smolin
Add-in Express Team Leader |
|
Posted 21 Jul, 2016 01:54:42
|
|
Top
|
|
Albert Siagian
Guest
|
Ok, will check it more detail. My constructor in add-in module is using default one.
Thanks
Albert |
|
Posted 21 Jul, 2016 02:11:38
|
|
Top
|
|