投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/12/9 20:51:17
可能であれば、Access VBA を用いて処理する事も検討してみてください。
VB.NET から制御するよりも、VBA の方が COM オブジェクト解放が容易です。

あるいは、Access のレポート機能を用いるのではなく、Visual Studio の Reporting Service など、
.NET からの利用が想定された帳票ツールなどを用いるのも手かと思います。

―――まぁ、今更変更するわけにも行かないとは思いますけれども。


> Dim acCon As New Access.Application
既に他の方も説明されていますが、この変数 acCon を、最後に Quit した後、
Marshal.ReleaseComObject メソッドで解放せねばなりません。

また、Access のレポート機能を使うだけなら、無料の Access ランタイムだけで動作しますが、
New して利用する構文を使うと、Access のランタイムだけでは実行できないため、
実行環境に、有償の Access 製品版が必要になってしまう点にも注意してください。


> acCon.OpenCurrentDatabase("****")
> acCon.Visible = True
ここは問題ありません。

> acCon.DoCmd.OpenReport("****", Access.AcView.acViewDesign)
一度、DoCmd オブジェクトを変数に受けるようにしてください。
 Dim cmd As Access.DoCmd = acCon.DoCmd
 cmd.OpenReport("****", Access.AcView.acViewDesign)

なお、acViewDesign で開くためには、Access のランタイムでは対応できません。
Access のデザインタイムが必要となります。

初期化パラメータを指定するのであれば、デザインモードで開く代わりに、
OpenReport の OpenArgs 引数で指定し、Report の Open イベントで、
レポート側が Me.OpenArgs プロパティ経由で受け取るという手もあります。

なお、レポートの OpenArgs は、Access 2003 以上の機能です。
Access 2000 にはありませんので、注意してください。


> acCon.Reports("****").RecordSource = "SELECT 省略
RecordSource への代入を VBA 側で行う場合は、その記述で構いませんが、
VB.NET 側から行う場合は、Reports コレクションへの参照と、
Report オブジェクトへの参照を変数に受ける必要があります。
 Dim reports As Access.Reports = acCon.Reports
 Dim report As Access.Report = reports("****")
 report.RecordSource = "SELECT …

また、先の DoCmd と同様、これらの変数についても、最後に
Marshal.ReleaseComObject メソッドで解放処理が必要となります。



> acCon.DoCmd.OpenReport("****", Access.AcView.acViewPreview)
> acCon.DoCmd.Maximize()
先ほど取得した DoCmd オブジェクト変数を利用して、
 cmd.OpenReport("****", Access.AcView.acViewPreview)
 cmd.Maximize()
のようにします。
(変数 cmd は、DoCmd が不要になった時点で、
 Marshal.ReleaseComObject してください)


>>> のように「.」が2つ入っていれば、暗黙の参照が行われインスタンスが全部開放無いとの事。
> 知りませんでした。
「.」の前にあるのが“名前空間”であれば問題ありませんが、
「.」の前にあるのが“プロパティ”や“メソッド”だと問題となります。

たとえば、『Access.AcView.acViewPreview』という表記の場合、「.」が 2 つありますが
ここでいう Access は名前空間ですし、acView も型名に過ぎないため、この表記は問題ありません。

一方、『acCon.DoCmd.Maximize()』という表記は「.」が 2 つあり、しかも
DoCmd が「acCon の DoCmd プロパティ」を意味するため、問題があります。この場合は
Dim cmd As Access.DoCmd = acCon.DoCmd
cmd.Maximize()
Marshal.ReleaseComObject(cmd)
のようにして、一度、COM オブジェクトを変数に受け、最後に解放する必要があるわけです。


>  あんまり私は好きじゃないですが、C風にいうと格納しているメモリの番地が不明になり、
> 結果正しく処理されないんでしょうね。
そういう訳では無いのですが、中々ややこしい話が絡んできますので、
最初のうちはそういうイメージで捉えておいても良いかも知れません。