■No35251に返信(たこさんの記事) > 問題は無い様に思えるのですが… Friend Sub WorkSheet_Select には、もう一つ問題点がありそうです。
> If Not check Then > _xlsWorkSheet = CType(xlsSheets.Add(), Excel.Worksheet) > xlsWorkSheet.Name = strSheetName > Else > _xlsWorkSheet = CType(xlsSheets(strSheetName), Excel.Worksheet) > End If これだと、「以前に _xlsWorkSheet が参照していた COM オブジェクト」が 解放されなくなってしまいます。
No35247 において、解説の最後に >> Dim y As Excel.Workbooks = x.Workbooks >> Dim z As Excel.Workbooks = x.Workbooks という実験コードを書いていますが、この場合、VBA や VBS とは異なり、 .NET においては y と z が別インスタンスとなることに注意が必要です。
この場合、COM の参照カウントは y と z それぞれに対して減じねばなりません。 y と z の両方を RelaseComObject した場合と、どちらか一方しか 解放しなかった場合とで、Excel の残存性を確認してみてください。
■No35252に返信(魔界の仮面弁士さんの記事) >> Private _xlsApplication As Excel.Application = Nothing >> Friend ReadOnly Property xlsApplication As Excel.Application >> Get >> Return _xlsApplication >> End Get >> End Property > これではあまり意味が無いと思いますよ。結局のところ、 > Friend ReadOnly xlsApplication As Excel.Application > な読み取り専用フィールドと、さほど変わらないように見えます。 > > > COM オブジェクトを直接公開してしまうと、ExcelEx の外部で > ExEx1.xlsApplication.Workbooks.Add() > などと書かれてしまえば、COM オブジェクトの解放漏れに繋がります。 > > IDisposable としてカプセル化するのであれば、Excel の COM オブジェクトは > 外部からは直接操作できないようにして、すべてクラス内に隠蔽します。 > 戻り値と返すのも COM オブジェクトではなく、.NET のマネージオブジェクトにします。
全てをクラス内でやってしまう…と言う考え方で良いのでしょうか… 例えば… ----------------------------------------------------------------- Private _xlsApplication as Excel.Application = Nothing
Private _ExcelVisible As Boolean = True Public Property ExcelVisible As Boolean Set(Value as Boolean) _ExcelVisible = Value If value then _xlsApplication.Visible = True Else _xlsApplication.Visible = False End If End Set Get Return _ExcelVisible End Get End Property ----------------------------------------------------------------- …の様な感じで…
> Dim obj1 = 対象ワークブック.Sheets 'これは Sheets 型 …と言う事は Dim obj1 As Excel.Sheets > Dim obj2 = obj1(strSheetName) 'これは Object 型となることに注意 …と言う事は Dim obj2 As Object …で合ってますかね^^? ここの理解はまだ追い付いていません(>_<)
…と言う事は… ------------------------------------------------------------------------------------- Friend Sub WorkSheet_Select(strSheetName As String) Dim check As Boolean = False For x As Integer = 1 to _xlsSheets.Count If _xlsSheets(x) Is Excel.Worksheet then '← 怒られました^^; If CType(_xlsSheets (x), Excel.Worksheet).Name = strSheetName Then check = True Exit For End If End If Next If Not check Then _xlsWorkSheet = CType(_xlsSheets.Add(), Excel.Worksheet) _xlsWorkSheet.Name = strSheetName Else _xlsWorkSheet = CType(_xlsSheets(strSheetName), Excel.Worksheet) End If If SheetVisible Then _xlsWorkSheet.Select() End Sub -------------------------------------------------------------------------------------
下の方に書いてありました^^; > Dim ws = DirectCast(xlsSheets(n), Excel.Worksheet) これだと『WorkSheet』以外はNothingになるのでしょうか…
(DirectCastは明示的な型変換と書いてありました… http://vb.navi-ch.net/2015/07/18/post-118/ ------------------------------------------------------------------------------------- サンプルソース Dim a As Object = 3.14 Dim b As Integer = DirectCast(a, Integer) MsgBox(b) End Sub End Class 実行結果 メッセージーボックスも表示されません。 -------------------------------------------------------------------------------------
ちょっとした実験をしてみました。 -------------------------------------------------------------------- Dim w As Excel.Worksheets Dim s = w.Item(1) '←WorkSheetオブジェクトのItemなので、当然WorkSheet型だと思っている Dim n = CType(s, Excel.Worksheets).name '←怒られる… --------------------------------------------------------------------
Dim s As Excel.Worksheets = w.Item(1) '←やっぱり怒られる… 'Option Strict On では'Object'から'Worksheets'への暗黙的な変換は許可されていません。 'ReadOnly Property Excel.Wroksheets.Item(Index As Object) As Object
Dim s As Object = w.Item(1) 'これが正解の様だ… 'ここは戻り値がObjectなので理解出来る。
Dim n = CType(s, Object).name '←怒られる… 'Option Strict On では、遅延バインディングを使用できません。 一体何の型にキャストすればシート名が取得できるのだろう…
>『.』の連続」が見えにくくなる .を分解するのも苦労します(>_<)
あ…そう言えばと思い。。。
Dim w As Excel.Worksheets Dim s As Object = w.Item(1) Dim sh As Excel.Worksheet = CType(s, Excel.Worksheet) Dim n As String = sh.Name