VB.NETで開発を行っています。
エクセルを開いてデータや書式をセットして保存、印刷、エクセル終了を行っているのですが、プロセスが残ってしまいます。ソースは以下のソースなんですが、この中の
「xlbook.Close(False)」「xlapp.Quit()」をはずして手動でエクセルを閉じるとプロセスは終了するのですが、プログラムでエクセルを終了するとプロセスが終了しません。
なにか足りないものがあるのでしょうか?
====================================================
Dim xlapp As System.Object
Dim xlbooks As System.Object
Dim xlbook As System.Object
Dim xlsheets As System.Object
Dim xlsheet1 As System.Object
Dim xlsheet2 As System.Object
Dim xlsheet3 As System.Object
Dim xlsheet4 As System.Object
''エクセル開く
xlapp = CreateObject("Excel.Application")
xlbooks = xlapp.Workbooks
xlbook = xlbooks.Open(strFilePathName)
xlsheets = xlbook.Worksheets
xlsheet1 = xlsheets(1)
xlsheet2 = xlsheets(2)
xlsheet3 = xlsheets(3)
''原紙の列ヘッダーを編集
xlsheet1.Cells(10, 2) = C1FlexGrid1(0, 0) ''営業所又は課
xlsheet2.Cells(5, 2) = C1FlexGrid1(0, 0) ''営業所又は課
xlsheet1.Cells(1, 8) = "Print : " & strPrintDate ''日付
xlsheet2.Cells(1, 8) = "Print : " & strPrintDate ''日付
''販売計画シートを作成
xlsheet1.Select()
xlsheet1.Copy(Before:=xlsheet1)
xlsheet1.Select()
xlsheet1.Name = "計画入力"
'シートをコピーしたので変数にセットしなおす
xlsheet1 = xlsheets(1)
xlsheet2 = xlsheets(2)
xlsheet3 = xlsheets(3)
xlsheet4 = xlsheets(4)
''条件の欄をセットする
xlsheet1.Cells(3, 3) = ": " & C1FlexGrid1(1, 15) ''計画単位
xlsheet1.Cells(3, 7) = ": " & Mid(C1FlexGrid1(1, 6), 1, 4) & "/" & Mid(C1FlexGrid1(1, 6), 5, 2) & "〜" & _
Mid(C1FlexGrid1(1, 7), 1, 4) & "/" & Mid(C1FlexGrid1(1, 7), 5, 2) ''期間
xlsheet1.Cells(5, 3) = ": " & C1FlexGrid1(1, 8) & " " & C1FlexGrid1(1, 16) ''支店
''営業所、課
xlsheet1.Cells(6, 3) = ": "
xlsheet1.Cells(7, 3) = ": "
If ("課").Equals(C1FlexGrid1(1, 14)) Then
xlsheet1.Cells(6, 3) = ": " & C1FlexGrid1(1, 9) & " " & C1FlexGrid1(1, 17) ''営業所
ElseIf ("課指定").Equals(C1FlexGrid1(1, 14)) Then
xlsheet1.Cells(6, 3) = ": " & C1FlexGrid1(1, 9) & " " & C1FlexGrid1(1, 17) ''営業所
xlsheet1.Cells(7, 3) = ": " & IIf(("--").Equals(C1FlexGrid1(1, 10)), "", C1FlexGrid1(1, 10) & " " & C1FlexGrid1(1, 18)) ''課
End If
xlsheet1.Cells(5, 7) = ": " & C1FlexGrid1(1, 11) & " " & C1FlexGrid1(1, 19) ''メーカ
xlsheet1.Cells(6, 7) = ": " & IIf(("------").Equals(C1FlexGrid1(1, 12)), "", C1FlexGrid1(1, 12) & " " & C1FlexGrid1(1, 20)) ''品目
xlsheet1.Cells(7, 7) = ": " & C1FlexGrid1(1, 21) ''メーカ販路
''データを件数分貼り付ける
For intRowPos = 1 To C1FlexGrid1.Rows.Count - 1
''最終行(合計行)でない場合、データ行の書式を原紙からコピーペーストする
If intRowPos <> C1FlexGrid1.Rows.Count - 1 Then
xlsheet4.Select()
xlsheet4.Rows("1:1").Select()
xlapp.Selection.Copy()
xlsheet1.Select()
xlsheet1.Rows(intRowPos + intExlPos & ":" & intRowPos + intExlPos).Select()
xlbook.ActiveSheet.Paste()
End If
''データをセットする
xlsheet1.Cells(intRowPos + intExlPos, 2) = C1FlexGrid1(intRowPos, 0) ''営業所
xlsheet1.Cells(intRowPos + intExlPos, 4) = C1FlexGrid1(intRowPos, 1) ''金額
xlsheet1.Cells(intRowPos + intExlPos, 5) = C1FlexGrid1(intRowPos, 2) ''軒数
xlsheet1.Cells(intRowPos + intExlPos, 6) = C1FlexGrid1(intRowPos, 3) ''本数
''最終行でない場合
If intRowPos <> C1FlexGrid1.Rows.Count - 1 Then
If ((1).Equals(intNextPage) AndAlso (50).Equals((intRowPos + intExlPos))) OrElse _
(Not (1).Equals(intNextPage) AndAlso (intOnePageRow * intNextPage - 5).Equals((intRowPos + intExlPos))) Then
''2ページ以降のスタイルをコピーペーストする
xlsheet3.Select()
xlapp.Rows("1:55").Select()
xlapp.Selection.Copy()
xlsheet1.Select()
xlapp.Rows((intOnePageRow * intNextPage + 1) & ":" & (intOnePageRow * intNextPage + 1)).Select()
xlbook.ActiveSheet.Paste()
xlbook.ActiveSheet.HPageBreaks(intNextPage).Location = xlapp.Range("A" & intOnePageRow * intNextPage + 1)
intNextPage += 1
intExlPos += 10
End If
End If
Next
''合計行もコピーペーストする
xlsheet4.Select()
xlapp.Rows("2:2").Select()
xlapp.CutCopyMode = False
xlapp.Selection.Copy()
xlsheet1.Select()
xlsheet1.Rows(intRowPos + intExlPos - 1 & ":" & intRowPos + intExlPos - 1).Select()
xlapp.Selection.PasteSpecial(Paste:=-4122, Operation:=-4142, SkipBlanks:=False, Transpose:=False)
'''COM オブジェクトの解放
xlbook.Save() ''販売計画保存
xlsheet1.Cells(1, 1).Select()
xlapp.Visible = True
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheets)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet1)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet2)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet3)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet4)
xlsheet1 = Nothing
xlsheet2 = Nothing
xlsheet3 = Nothing
xlsheet4 = Nothing
xlsheets = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlbooks)
xlbooks = Nothing
xlbook.Close(False)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlbook)
xlbook = Nothing
xlapp.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlapp)
xlapp = Nothing
====================================================
なかなか解決しません。
すみません、よろしくお願いしますm()m
> xlsheet1.Cells(3, 3) = ": " & C1FlexGrid1(1, 15)
この部分がいろいろとマズイです。
まず、Cellsプロパティから返されるのは、Rangeオブジェクトです。
ここに直接値を入力してはいけません。
RangeオブジェクトのValueプロパティに代入するようにして下さい。
次に…Cellsプロパティは引数を取らない仕様です。
実際には、Cells自体がRangeオブジェクトを返しますので、
xlsheet1.Cells(3, 3)
というコードは、実際には
xlsheet1.Cells._Default(3, 3)
を意味する事になります。
つまり、このままのコードですと、
.Cells が返す物は、Rangeオブジェクト。
._Default が返す物も、Rangeオブジェクト。
であるにも関わらず、これらのRangeがReleaseComObjectされていないという
事になります。各Rangeを変数に受け、使用後に解放してください。
なお、このことは Cells以外のプロパティ、たとえば
> xlsheet1.Rows(intRowPos ……
などについても言える事です。
また、
> xlapp.Selection.Copy()
についても、Selection部分がReleaseComObjectされていないので、
やはり問題が発生するかと思います。
返信ありがとうございます。
魔界の仮面弁士さんの指摘通り、
Cellsプロパティ、Rowsプロパティ、SelectionをRangeオブジェクトに入れ直してみましたが、やはり結果同じになってしまいました。
エクセルを手動で閉じればまくいくのですが、プログラムでエクセルを閉じると残ってしまいます。
まだ足りないものがあるのでしょうか?
=========================================================
Dim xlapp As System.Object
Dim xlbooks As System.Object
Dim xlbook As System.Object
Dim xlsheets As System.Object
Dim xlsheet1 As System.Object
Dim xlsheet2 As System.Object
Dim xlsheet3 As System.Object
Dim xlsheet4 As System.Object
''エクセル開く
xlapp = CreateObject("Excel.Application")
xlbooks = xlapp.Workbooks
xlbook = xlbooks.Open(strFilePathName)
xlsheets = xlbook.Worksheets
xlsheet1 = xlsheets(1)
xlsheet2 = xlsheets(2)
xlsheet3 = xlsheets(3)
Dim objCells As Excel.Range
Dim objRows4 As Excel.Range
Dim objRows1 As Excel.Range
Dim objRows3 As Excel.Range
''原紙の列ヘッダーを編集
objCells = xlsheet1.Cells
objCells(10, 2) = C1FlexGrid1(0, 0) ''営業所又は課
objCells(1, 8) = "Print : " & strPrintDate ''日付
objCells = xlsheet2.Cells
objCells(5, 2) = C1FlexGrid1(0, 0) ''営業所又は課
objCells(1, 8) = "Print : " & strPrintDate ''日付
''販売計画シートを作成
xlsheet1.Select()
xlsheet1.Copy(Before:=xlsheet1)
xlsheet1.Select()
xlsheet1.Name = "計画入力"
'シートをコピーしたので変数にセットしなおす
xlsheet1 = xlsheets(1)
xlsheet2 = xlsheets(2)
xlsheet3 = xlsheets(3)
xlsheet4 = xlsheets(4)
objCells = xlsheet1.Cells
objRows1 = xlsheet1.Rows
objRows3 = xlsheet3.Rows
objRows4 = xlsheet4.Rows
''条件の欄をセットする
objCells(3, 3) = ": " & C1FlexGrid1(1, 15) ''計画単位
objCells(3, 7) = ": " & Mid(C1FlexGrid1(1, 6), 1, 4) & "/" & Mid(C1FlexGrid1(1, 6), 5, 2) & "〜" & _
Mid(C1FlexGrid1(1, 7), 1, 4) & "/" & Mid(C1FlexGrid1(1, 7), 5, 2) ''期間
objCells(5, 3) = ": " & C1FlexGrid1(1, 8) & " " & C1FlexGrid1(1, 16) ''支店
''営業所、課
objCells(6, 3) = ": "
objCells(7, 3) = ": "
If ("課").Equals(C1FlexGrid1(1, 14)) Then
objCells(6, 3) = ": " & C1FlexGrid1(1, 9) & " " & C1FlexGrid1(1, 17) ''営業所
ElseIf ("課指定").Equals(C1FlexGrid1(1, 14)) Then
objCells(6, 3) = ": " & C1FlexGrid1(1, 9) & " " & C1FlexGrid1(1, 17) ''営業所
objCells(7, 3) = ": " & IIf(("--").Equals(C1FlexGrid1(1, 10)), "", C1FlexGrid1(1, 10) & " " & C1FlexGrid1(1, 18)) ''課
End If
objCells(5, 7) = ": " & C1FlexGrid1(1, 11) & " " & C1FlexGrid1(1, 19) ''メーカ
objCells(6, 7) = ": " & IIf(("------").Equals(C1FlexGrid1(1, 12)), "", C1FlexGrid1(1, 12) & " " & C1FlexGrid1(1, 20)) ''品目
objCells(7, 7) = ": " & C1FlexGrid1(1, 21) ''メーカ販路
''データを件数分貼り付ける
For intRowPos = 1 To C1FlexGrid1.Rows.Count - 1
''最終行(合計行)でない場合、データ行の書式を原紙からコピーペーストする
If intRowPos <> C1FlexGrid1.Rows.Count - 1 Then
xlsheet4.Select()
objRows4("1:1").Select()
objRows4("1:1").Copy()
xlsheet1.Select()
objRows1(intRowPos + intExlPos & ":" & intRowPos + intExlPos).Select()
xlbook.ActiveSheet.Paste()
End If
''データをセットする
objCells(intRowPos + intExlPos, 2) = C1FlexGrid1(intRowPos, 0) ''営業所
objCells(intRowPos + intExlPos, 4) = C1FlexGrid1(intRowPos, 1) ''金額
objCells(intRowPos + intExlPos, 5) = C1FlexGrid1(intRowPos, 2) ''軒数
objCells(intRowPos + intExlPos, 6) = C1FlexGrid1(intRowPos, 3) ''本数
''最終行でない場合
If intRowPos <> C1FlexGrid1.Rows.Count - 1 Then
If ((1).Equals(intNextPage) AndAlso (50).Equals((intRowPos + intExlPos))) OrElse _
(Not (1).Equals(intNextPage) AndAlso (intOnePageRow * intNextPage - 5).Equals((intRowPos + intExlPos))) Then
''2ページ以降のスタイルをコピーペーストする
xlsheet3.Select()
objRows3("1:55").Select()
objRows3("1:55").Copy()
xlsheet1.Select()
objRows1((intOnePageRow * intNextPage + 1) & ":" & (intOnePageRow * intNextPage + 1)).Select()
xlbook.ActiveSheet.Paste()
xlbook.ActiveSheet.HPageBreaks(intNextPage).Location = xlapp.Range("A" & intOnePageRow * intNextPage + 1)
intNextPage += 1
intExlPos += 10
End If
End If
Next
''合計行もコピーペーストする
xlsheet4.Select()
objRows4("2:2").Select()
xlapp.CutCopyMode = False
objRows4("2:2").Copy()
xlsheet1.Select()
objRows1(intRowPos + intExlPos - 1 & ":" & intRowPos + intExlPos - 1).Select()
objRows1(intRowPos + intExlPos - 1 & ":" & intRowPos + intExlPos - 1).PasteSpecial(Paste:=-4122, Operation:=-4142, SkipBlanks:=False, Transpose:=False)
xlbook.Save() ''保存
objCells(1, 1).Select()
xlapp.Visible = True
'''COM オブジェクトの解放
System.Runtime.InteropServices.Marshal.ReleaseComObject(objCells)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRows1)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRows4)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRows3)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheets)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet1)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet2)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet3)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsheet4)
xlsheet1 = Nothing
xlsheet2 = Nothing
xlsheet3 = Nothing
xlsheet4 = Nothing
xlsheets = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlbooks)
xlbooks = Nothing
xlbook.Close(False)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlbook)
xlbook = Nothing
xlapp.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlapp)
xlapp = Nothing
===============================================================
すみません、よろしくお願いします。
よろしくお願いしないで、0行のプログラムから
1行ずつ順に加えていって、どの時点で開放され
なくなるか自分で調べるようにして下さい。
それがデバッグというものです。
.NETからのCOM操作は、結構面倒なんですよね。
前提知識が無いと、確かにつらいかも。(^^;
> Dim xlapp As System.Object
> Dim objCells As Excel.Range
厳密な型付け(As Excel.〜) と、そうでないもの(As System.Object)が
混じっていますね。どちらかに統一された方が良いですよ。
前者に統一するなら、こんな感じです。
Dim xlapp As Excel.Application 'As System.Object
Dim xlbooks As Excel.Workbooks 'As System.Object
Dim xlbook As Excel.Workbook 'As System.Object
Dim xlsheets As Excel.Sheets 'As System.Object
Dim xlsheet1 As Excel.Worksheet 'As System.Object
Dim xlsheet2 As Excel.Worksheet 'As System.Object
Dim xlsheet3 As Excel.Worksheet 'As System.Object
Dim xlsheet4 As Excel.Worksheet 'As System.Object
xlapp = New Excel.ApplicationClass
xlbook = xlbooks.Open(strFilePathName)
xlsheets = xlbook.Sheets
xlsheet1 = DirectCast(xlsheets(1), Excel.Worksheet)
xlsheet2 = DirectCast(xlsheets(2), Excel.Worksheet)
xlsheet3 = DirectCast(xlsheets(3), Excel.Worksheet)
もし、DirectCastするのが面倒なら、逆に全てを As Object にしてしまい、
参照設定も外してしまいましょう。中途半端は良くないです。
> objCells = xlsheet1.Cells
> objCells(10, 2) = C1FlexGrid1(0, 0) ''営業所又は課
> objCells(1, 8) = "Print : " & strPrintDate ''日付
ここにまた、最初と同じミスがあります。
私は、最初の回答の冒頭部に、
》 まず、Cellsプロパティから返されるのは、Rangeオブジェクトです。
》 ここに直接値を入力してはいけません。
》 RangeオブジェクトのValueプロパティに代入するようにして下さい。
と記述していますよね。これはつまり、
objCells = xlsheet1.Cells
objRange1 = objCells(10, 2)
objRange1.Value = "(営業所名)" '★★ Range オブジェクトのValueプロパティ ★★
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRange1) '使い終わったら、すぐ解放
objRange1 = objCells(1, 8)
objRange1.Value = "Print : " & strPrintDate '★★ Range オブジェクトのValueプロパティ ★★
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRange1) '使い終わったら、すぐ解放
:
:
System.Runtime.InteropServices.Marshal.ReleaseComObject(objCells)
のように、『Valueプロパティ』に代入する必要がある、という意味なのです。
ちなみに、これはVBAやVB6でも同じ事です。
Rangeに直接代入するのは、正しい記述ではありません。
特に .NET においては、上記の objCells(10, 2) などから返される物も、
COMオブジェクトの一種である「Excel.Range オブジェクト」である事に
注意してください。
COMのオブジェクトである以上、.NET からの利用時には、使用後に
Marshal.ReleaseComObject()が必要になってくるわけです。
とっても面倒ですけどね。(^_^;)
# なお、上記のコードにおいて、 MessageBox.Show(TypeName(objRange1)) を
# 実行すると、このデータ型が「Range」型である事を確認できるかと思います。
> objRows4("1:1").Select()
この部分にも同じ事が言えます。
『objRows4("1:1")』が返す物を変数に受けて、使用後に解放しましょう。
> objCells(intRowPos + intExlPos, 2) = C1FlexGrid1(intRowPos, 0) ''営業所
そして、ここも同様。
objRange1 = objCells(intRowPos + intExlPos, 2)
objRange1.Value = "(営業所情報)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRange1)
というイメージになります。
厳密な型定義の使用を強くお勧めします。
変数の暗黙的なデータ型変換を制限する
Option Strict On
と共に使われる事を強く望みます。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200408/04080020.txt
未熟な私に丁寧に教えてくださりほんとにありがとうございますm(__)m
魔界の仮面弁士の通りに変数の宣言をそろえ、1回1回RangeオブジェクトのValueプロパティにセットして開放の繰り返しに変えました。(objCells(x, x)とobjRows(x:x))
それでもなぜかまだプロセスが残ってしまいます・・・(><)
まだ何か代入し足りない又は解放してないものがあるのかもしれないです。
もう少し調べてみたいと思いますm(__)m