エクセルのプロセス


se  2004-12-10 19:19:05  No: 118212  IP: [192.*.*.*]

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

編集 削除
魔界の仮面弁士  2004-12-10 23:31:10  No: 118213  IP: [192.*.*.*]

> 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されていないので、
やはり問題が発生するかと思います。

編集 削除
se  2004-12-17 16:56:36  No: 118214  IP: [192.*.*.*]

返信ありがとうございます。

魔界の仮面弁士さんの指摘通り、
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

===============================================================
すみません、よろしくお願いします。

編集 削除
特攻隊長まるるう  2004-12-20 14:07:16  No: 118215  IP: [192.*.*.*]

よろしくお願いしないで、0行のプログラムから
1行ずつ順に加えていって、どの時点で開放され
なくなるか自分で調べるようにして下さい。

それがデバッグというものです。

編集 削除
魔界の仮面弁士  2004-12-20 23:24:29  No: 118216  IP: [192.*.*.*]

.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)
というイメージになります。

編集 削除
特攻隊長まるるう  2004-12-21 09:58:32  No: 118217  IP: [192.*.*.*]

厳密な型定義の使用を強くお勧めします。
変数の暗黙的なデータ型変換を制限する
Option Strict On
と共に使われる事を強く望みます。

http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200408/04080020.txt

編集 削除
se  2004-12-27 10:14:03  No: 118218  IP: [192.*.*.*]

未熟な私に丁寧に教えてくださりほんとにありがとうございますm(__)m
魔界の仮面弁士の通りに変数の宣言をそろえ、1回1回RangeオブジェクトのValueプロパティにセットして開放の繰り返しに変えました。(objCells(x, x)とobjRows(x:x))
それでもなぜかまだプロセスが残ってしまいます・・・(><)
まだ何か代入し足りない又は解放してないものがあるのかもしれないです。
もう少し調べてみたいと思いますm(__)m

編集 削除