プロセスが残る

タグの編集
投稿者 熊造  (社会人) 投稿日時 2009/12/5 21:34:44
VB2008を使っています。
Accessのレポートをプレビュー表示して閉じるとプロセスが残ってしまいます。
        Dim acCon As New Access.Application
        acCon.OpenCurrentDatabase("****")
        acCon.Visible = True

        acCon.DoCmd.OpenReport("****", Access.AcView.acViewDesign)
        acCon.Reports("****").RecordSource = _
            "SELECT 省略
        acCon.DoCmd.OpenReport("****", Access.AcView.acViewPreview)

        acCon.DoCmd.Maximize()
 
プロセスを残さない方法はありませんでしょうか
宜しくおねがいします
投稿者 熊造  (社会人) 投稿日時 2009/12/5 21:38:13
説明がぬかっていました
印刷が終わりmdbを閉じるとプロセスが残ってしまいます。
投稿者 daive  (社会人) 投稿日時 2009/12/5 23:43:53
プロセスの開放を行っていないので、
プロセスが残るのは、当然かと。

Google
検索ワード:VB.NET プロセス開放

Accessの情報は少ないので、EXCELの情報を参考にされるのが良いかと。
プロセスの開放に関する考え方は、一緒のはずです。

サイト:EXCELでお仕事
Excelがプロセスに居座ってしまう!?その2
辺りが参考になるかもしれません。

投稿者 熊造  (社会人) 投稿日時 2009/12/6 08:26:54
daiveさん ありがとうございます。

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(acCon)
これかなと思ってやってみたのですがやはり残ってしまいます。

もう少し調べてみます
投稿者 葉月  (社会人) 投稿日時 2009/12/6 10:42:45
データベース絡みだったのでスルーしていましたが、
プロセスが残ったままというなら、Closeができていないと思われます。

>>>System.Runtime.InteropServices.Marshal.FinalReleaseComObject(acCon)
その解放の仕方はかなり難解です。
私は概要しか理解できてません。
そのやり方でやるなら、過去に私が投稿したこちらのサンプルを見てください。
最後が私で、そこにFinalReleaseComObjectを利用した解放が載っています。
http://rucio.groupsite.jp/commu/ThreadDetail.aspx?ThreadId=79

もう、一年以上前の話なので、こんなサンプル作ったなぁぐらいの認識しかありませんが(マテ


投稿者 熊造  (社会人) 投稿日時 2009/12/6 21:11:53
葉月さんありがとうございます。
参考にさせていただきます

投稿者 neptune  (社会人) 投稿日時 2009/12/6 21:40:25
こんにちは。

検証なしで書いてますので見当違いかもしれませんが、思いついたので書いてみます。

・・・Excelではの話ですが、魔界の仮面弁士さんがどこかでおっしゃってましたが、
acCon.DoCmd.OpenReport(・・・・
のように「.」が2つ入っていれば、暗黙の参照が行われインスタンスが全部開放無いとの事。

Accessでもその点では同じだと思うので幽霊が残ってしまい、
結果プロセスが正常に終了されないのではないでしょうか?

DoCmdオブジェクトの参照を明示的に作成してみては如何?
投稿者 葉月  (社会人) 投稿日時 2009/12/6 23:03:29
このページを見るのを推奨します。
http://support.microsoft.com/kb/317113/ja

ページのサンプルコードにある以下の部分は調べといた方がいいですね。
oAccess.Quit(Option:=Access.AcQuitOption.acQuitSaveNone)
System.Runtime.InteropServices.Marshal.ReleaseComObject(oAccess)
oAccess = Nothing

>>>のように「.」が2つ入っていれば、暗黙の参照が行われインスタンスが全部開放無いとの事。
知りませんでした。
全部解放されないとなると、大量のシートを開くケースなんかは酷いことになりそうですね。
Excelは稀に使う機会があるので、気をつけないといけませんね。
投稿者 熊造  (社会人) 投稿日時 2009/12/6 23:48:02
ありがとうございます
EXEにして実行すると EXEを閉じたときにプロセスが消えます。
実行中はmdbを閉じても残っています(プレビュー表示なので直接mdbを閉じます プログラムからは閉じません)

印刷プレビュー表示だからいけないんですね 直接印刷するようにして
acCon.Quit
System.Runtime.InteropServices.Marshal.ReleaseComObject(acCon)
これなら消えます

投稿者 neptune  (社会人) 投稿日時 2009/12/7 02:48:47
葉月さん>
>全部解放されないとなると、大量のシートを開くケースなんかは酷いことになりそうですね。
すみません。打ち間違えしてました。

>暗黙の参照が行われインスタンスが全部開放無いとの事。

「暗黙の参照が行われインスタンスが全部は開放され無いとの事。」
と打つつもりだったんです。
で、これでもまだおかしいんですが、

要するに、
・暗黙の参照が行われて、暗黙の参照のインスタンスは残ってしまう
→Excelのインスタンスは残ってしまう。

という旨で理解ください。

お騒がせしました。m(_ _)m
投稿者 cupid  (社会人) 投稿日時 2009/12/7 05:05:40
以前の言い方で言えば、Automationですね。
であれば、Access側で終了メソッドを用意しているはずです。
「Access.Application 終了」で検索すればすぐ見つかりました。
その見つかったサイトによれば、下記で良いそうですよ。
acCon.Quit

ところで、VBからmdbファイルを扱う場合、Accessを使わない方が
分かり易いと思いますね。あくまでも個人的感想ですが。
投稿者 葉月  (社会人) 投稿日時 2009/12/7 07:03:18
>neptuneさん
 解説ありがとうございます。
 あんまり私は好きじゃないですが、C風にいうと格納しているメモリの番地が不明になり、
結果正しく処理されないんでしょうね。
 ただ、「説明的には正しく解放されない可能性がある」のがいいかも知れません。
 解放漏れがあった場合もCOMラッパーを通してガベージコレクタの解放対象には設定される
ようです。
 (解放処理を、そもそも入れてなかったら残ったままになります)
 スクリプトなど自動終了する類のものであれば、ツールのプロセスが終了したらExcelプロ
セスもそのうちに消えてくれると思います。
 ただ、これは保険で処理してくれるだけに過ぎないので、neptuneさんの言うように確実な
解放処理を心がけて、参照カウントを取り対応した方がいいんでしょうね。
 (使う頃に忘れてないといいんですが)

http://msdn.microsoft.com/ja-jp/library/5dxz80y2.aspx

投稿者 熊造  (社会人) 投稿日時 2009/12/9 01:57:37
いろいろ教えていただきありがとうございます。

>ところで、VBからmdbファイルを扱う場合、Accessを使わない方が
>分かり易いと思いますね。

これはAccessを使わずにレポートを印刷できるということでしょうか
そうだとすればなんとかその方法でやりたいのですがさっぱりわかりません

ご存知のかた教えていただけないでしょうか

投稿者 daive  (社会人) 投稿日時 2009/12/9 02:12:51
Accessのレポートを、そのまま印刷できるわけでは、無いです。
Accessのレポートを、そのまま印刷する場合は、Accessを使うか、
コントロールがあれば、それを使うとか。

印刷物は、印刷物として、別途作成して
mdb のデータのみを使用するということです。
EXCELでも、クリスタルレポートでも、
Drawオブジェクトでも、
印刷品質が悪くてもよければ、フォームの印刷でも
印刷は可能という、ことです。
投稿者 熊造  (社会人) 投稿日時 2009/12/9 02:49:13
daiveさんありがとうございます。

Accessのレポートになれているので使っていましたが、VBレポートでやってみようと
思います。

投稿者 cupid  (社会人) 投稿日時 2009/12/9 19:58:03
Access2000系アプリを使わないという意味は、
ADOを使って、Jetあるいは、ODBCで接続し、テーブルデータを取得。
レコード内容が表形式で欲しいなら、Grid系コントロールに入れたり、
あるいは帳票ようなFormを自分で作って、自由にLayoutできるという意味です。
しかしその上、Print機能も組み立てる必要あるから、面倒と言えば面倒。
結局、取り組む気持ちの問題に帰結するかもしれません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 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風にいうと格納しているメモリの番地が不明になり、
> 結果正しく処理されないんでしょうね。
そういう訳では無いのですが、中々ややこしい話が絡んできますので、
最初のうちはそういうイメージで捉えておいても良いかも知れません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/12/9 21:03:00
> Access2000系アプリを使わないという意味は、
これは、Jet のデータベース機能のみを利用するようにし、
帳票機能やフォーム画面などの(アプリケーション製品としての)Access は
利用しないという選択肢ですね。

> ADOを使って、Jetあるいは、ODBCで接続し、テーブルデータを取得。
接続レイヤーが増えてしまいますので、ODBC からの接続はやめた方が良いと思います。

また、ADO もできれば避けるべきとされています。
VB.NET から mdb を扱うなら、ADO.NET を用いることを検討してみてください。

もし、ADO.NET では扱えない、JET のより細かな制御が必要なのだとしても、
ADO を使うぐらいなら、DAO を用いた方が良いかと思います。


なお、Jet は 64bit 環境では動作しない点にも注意してください。

32 bit OS でしか動作させないのであれば、さほど気にする必要はありませんが、
64 bit OS でも動作させたいなら、構成マネージャのプラットフォーム指定を
"Any CPU" ではなく "x86" に変更しておくなどの対処が必要となります。
投稿者 熊造  (社会人) 投稿日時 2009/12/10 01:43:22
cupidさん
ありがとうございます。
VBレポートにしたいのですがまだまだ勉強不足で変更できないでいます。
徐々に変えていきたいと思っています。
しかしレポートの数が大量なのでめげるかも・・・・

魔界の仮面弁士さん
ありがとうございます
ご教授いただいたようにプログラムの変更をしました。
今まではプレビュー表示でmdbを閉じた時はプロセスが残ってしまいましたが
問題なくプロセスが終了するようになりました。

しかし皆さんの知識はすごいな 本当にありがとうございました。

投稿者 葉月  (社会人) 投稿日時 2009/12/10 04:20:16
魔界の仮面弁士さん、丁寧なご解説ありがとうございます。
変数が既にメソッドやプロパティとして受けた場合に、
メソッドやプロパティを受けてはいけないということがわかりました。

× 変数名.メソッド(もしくはプロパティ).メソッド(もしくはプロパティ)

×の場合は、COMオブジェクトを別変数に受ける説明なども理解できました。

ご指摘があったおかげで、リアルで恥をかかずに済んだことも含めて感謝しています。
なぜ、そうしなきゃいけないのか理解できていませんが将来の課題にします。
重ねてありがとうございました。