C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: Excelのプロセスが一つだけ残ってしまいます


(過去ログ 20 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■8685 / inTopicNo.1)  Excelのプロセスが一つだけ残ってしまいます
  
□投稿者/ 大阪人 (1回)-(2007/10/06(Sat) 21:09:44)

分類:[ASP.NET (C#)] 

開発環境:ASP.net2005
     Windows2003サーバ

現在、Webサービスで内部的にExcelテンプレートを読み込み、ExcelファイルをTempフォルダに作成し、作成したExcelをバイト配列としてクライアントに返すというアプリケーションを開発中なのですが、Excelのプロセスが一つだけ残ってしまい困っています。
クライアントからWebサービスを呼ぶとサーバにExcelのプロセスが残るのですが、プロセスが残った状態で再度、同じWebサービスを呼ぶと、もう一つプロセスが起動しますが、すぐに消えてくれます。
ソースは以下のように記述しています。

//MicroSoftExcelのCOMオブジェクト
Excel.Application appExcel = null;
Excel._Workbook excelBook = null;
Excel._Worksheet excelSheet = null;
//Excel.Sheets sheets = null;
Excel.Range excelRange = null;

//一時ファイルの保存先パス
string WorkFilePath = String.Copy(Path.GetTempPath() + "\\" + Guid.NewGuid() + ".xls");
//テンプレートパス
string execDllPath = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; //実行中DLL取得
Uri wkUri = new Uri(execDllPath);
string execDirName = Path.GetDirectoryName(wkUri.LocalPath); //実行中DLLディレクトリ
string TemplatePath = execDirName + "\\template.xlt";

try
{
appExcel = new Excel.Application();
appExcel.DisplayAlerts = false;
appExcel.Visible = false;
excelBook = appExcel.Workbooks.Add(Path.GetFullPath(TemplatePath));
int idx;

for (int i = 1; i <= excelBook.Sheets.Count; i++)
{
if (excelSheet != null) Marshal.ReleaseComObject(excelSheet);
excelSheet = excelBook.Sheets[i] as Excel.Worksheet;
if (excelRange != null) Marshal.ReleaseComObject(excelRange);
excelRange = excelSheet.Cells;
switch (i)
{
case 1:
excelRange[2, 7] = DateTime.Today;
excelRange[5, 2] = 12345;
excelSheet.Protect(Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
break;
case 2:
break;
case 3:
excelSheet.Protect(Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
break;
case 4:
excelSheet.get_Range("B15", "B24").Validation.Delete();
excelSheet.get_Range("B15", "B24").Validation.Add(Excel.XlDVType.xlValidateList, Excel.XlDVAlertStyle.xlValidAlertStop,
Excel.XlFormatConditionOperator.xlEqual, "=$AA$1:$AA$" + idx, Type.Missing);
excelSheet.get_Range("B15", "B24").Validation.IgnoreBlank = false;
//HIDDEN列を非表示化
excelSheet.get_Range("AA1", "AF1").EntireColumn.Hidden = true;

excelSheet.Protect(Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
break;
}
}
Excel.Worksheet select_Sheet = excelBook.Sheets[1] as Excel.Worksheet;
select_Sheet.Select(Type.Missing);
Marshal.ReleaseComObject(select_Sheet);
select_Sheet = null;
//Bookの保護
excelBook.Protect(Type.Missing, Type.Missing, Type.Missing);

}
finally
{
if (excelRange != null)
Marshal.ReleaseComObject(excelRange);
excelRange = null;
if (excelSheet != null)
Marshal.ReleaseComObject(excelSheet);
excelSheet = null;
if (excelBook != null)
try
{
excelBook.Close(true, Path.GetFullPath(WorkFilePath), false);
}
finally
{
Marshal.ReleaseComObject(excelBook);
excelBook = null;
}
if (appExcel != null)
{
try
{
appExcel.Quit();
}
finally
{
Marshal.ReleaseComObject(appExcel);
appExcel = null;
}
}
System.GC.Collect();
}

finally内のGC.Collectはあまり使用したくないのですが、この記述を外した場合、同画面で同操作を行った場合にプロセスがどんどん増えていってしまいます。
ここ数日、色々なサイトを調べているのですが、どうしても解決できません。

お手数ですが、ご教授お願い致します。
引用返信 編集キー/
■8693 / inTopicNo.2)  Re[1]: Excelのプロセスが一つだけ残ってしまいます
□投稿者/ じゃんぬねっと (531回)-(2007/10/07(Sun) 00:47:49)
ちょっと誤解をしているように見受けられます。
まずはひととまりこちらをご覧ください。
http://jeanne.wankuma.com/tips/programing/releasecom.html

これを見てなにがダメなのかわからない場合はまたその旨を書き込んでください。
一言申し上げますと GC は今回の事情とは直接関係しません。
参照カウントがすべてです。
引用返信 編集キー/
■8700 / inTopicNo.3)  Re[2]: Excelのプロセスが一つだけ残ってしまいます
□投稿者/ 大阪人 (3回)-(2007/10/07(Sun) 14:14:37)
ご返信ありがとうございます。

> ちょっと誤解をしているように見受けられます。
> まずはひととまりこちらをご覧ください。
> http://jeanne.wankuma.com/tips/programing/releasecom.html
>

ご指定頂いたサイトは今回、Comオブジェクトを使用するにあたり大いに参考にさせて頂きました。

そのうえで以下の点を気を付けるようにしてみたつもりです。

@Marshal.ReleaseComObjectで全てのCOMオブジェクトを解放する。
A変数を使いまわさない(excelRangeは複数個所で使っていますが、Worksheet.Cellsを参照しているので使いまわしにはあたりませんよね?)。
B型のCastは行わない。
CApplicationをquitする前にはWorkbookをCloseする。

> 一言申し上げますと GC は今回の事情とは直接関係しません。
> 参照カウントがすべてです。

やはりそうですか。
別のサイトでじゃんぬねっとさんが「GC.Collectはコストが高いので使用しない方が良い」と発言してらっしゃるのを拝見しましたので、私のソースが何か間違っているのだろうと思っておりました。

申し訳ありませんが、私が誤解している点をご指摘頂けないでしょうか。


引用返信 編集キー/
■8702 / inTopicNo.4)  Re[3]: Excelのプロセスが一つだけ残ってしまいます
□投稿者/ じゃんぬねっと (532回)-(2007/10/07(Sun) 16:51:54)
No8700 (大阪人 さん) に返信
> 申し訳ありませんが、私が誤解している点をご指摘頂けないでしょうか。

了解しました。

No8685 (大阪人 さん) に返信
> Excel._Workbook excelBook = null;
> Excel._Worksheet excelSheet = null;

これといって間違いとは言いませんが、アンダーバー付の型を敢えて使っているのはなぜでしょうか?

> excelSheet = excelBook.Sheets[i] as Excel.Worksheet;

変数を使いまわさないようにするという話が守られていないように思えます。
残りは誤っている箇所を列挙します。

> excelBook = appExcel.Workbooks.Add(Path.GetFullPath(TemplatePath));

> for (int i = 1; i <= excelBook.Sheets.Count; i++)

> excelRange[2, 7] = DateTime.Today;
> excelRange[5, 2] = 12345;

> excelSheet.get_Range("B15", "B24").Validation.Delete();
> excelSheet.get_Range("B15", "B24").Validation.Add(Excel.XlDVType.xlValidateList, Excel.XlDVAlertStyle.xlValidAlertStop, Excel.XlFormatConditionOperator.xlEqual, "=$AA$1:$AA$" + idx, Type.Missing);
> excelSheet.get_Range("B15", "B24").Validation.IgnoreBlank = false;
> excelSheet.get_Range("AA1", "AF1").EntireColumn.Hidden = true;
> Excel.Worksheet select_Sheet = excelBook.Sheets[1] as Excel.Worksheet;

これらはすべて COM ラッパ オブジェクトへの暗黙の参照があります。
その参照を取っていない時点で参照カウントをデクリメントする機会 (ReleaseComObject メソッドを実行できる機会) を失うので NG です。
引用返信 編集キー/
■8721 / inTopicNo.5)  Re[4]: Excelのプロセスが一つだけ残ってしまいます
□投稿者/ 大阪人 (4回)-(2007/10/09(Tue) 10:07:20)
解決しました。
参照カウントについて完全に勘違いしてました。

ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -