質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

[VB.NET]Excelのタスクの消し方

解決済

回答 5

投稿

  • 評価
  • クリップ 2
  • VIEW 2,707

reeeo

score 38

visual studio2012 でwindowsフォームアプリを作成します。
データグリッドビューのデータをExcelに出力するようにしています。
ですが、Excelを閉じてもタスクが残ってしまいます。
調べながら色々と試してみましたが、全然だめでした。
ソースは以下の通りです。

 '出力ボタン
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        Dim app As Excel.Application = Nothing
        Dim book As Excel.Workbook = Nothing
        Dim sheet As Excel.Worksheet = Nothing
        Dim books As Excel.Workbooks = Nothing

        Try
            'Excelを開く
            app = New Excel.Application()

            'Bookを開く
            books = app.Workbooks
            book = books.Open("C:\form3\Book1.xlsx")

            'シートの指定
            sheet = book.Worksheets(1)

            'Excelに出力する
            For i As Integer = 0 To DataGridView1.Rows.Count - 1
          sheet.Range("A" & i + 2 & "").Value = DataGridView1.Rows(i).Cells(1).Value
                sheet.Range("B" & i + 2 & "").Value = DataGridView1.Rows(i).Cells(4).Value
                sheet.Range("C" & i + 2 & "").Value = DataGridView1.Rows(i).Cells(5).Value
                sheet.Range("D" & i + 2 & "").Value = DataGridView1.Rows(i).Cells(6).Value
                sheet.Range("E" & i + 2 & "").Value = DataGridView1.Rows(i).Cells(7).Value
            Next

            'Excelの表示
            app.Visible = True

            '5秒だけ表示する
            System.Threading.Thread.Sleep(5000)

            '保存する
            book.Save()

            '閉じる
            app.Quit()

        Catch ex As Exception
            Throw ex

        Finally

            Marshal.ReleaseComObject(sheet)
            Marshal.ReleaseComObject(books)
            Marshal.ReleaseComObject(book)
            Marshal.ReleaseComObject(app)

        End Try

    End Sub
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • sazi

    2017/08/09 22:59

    「Excelを閉じてもタスクが残ってしまいます。」 とありますが、ここでいう「タスク」って何ですか?

    キャンセル

回答 5

checkベストアンサー

+1

私はC#の方を書く事が多いので読み替えてもらえると助かるのですが。。。
以下のように、エクセルを開く場合以下のようにTry構文の階層を作って確実にリリースすることをお勧めします。

Microsoft.Office.Interop.Excel.Application();
try
{
    Workbooks workbooks = excelApplication.Workbooks;
    try
    {
        Workbook workbook = workbooks.Open("d:\\Book1.xlsx");
        try
        {
            Sheets worksheets = workbook.Sheets;
            try
            {
                Worksheet worksheet = worksheets[1];
                try
                {
          処理
                }
                finally { Marshal.ReleaseComObject(worksheet); }
            }
            finally { Marshal.ReleaseComObject(worksheets); }
        }
        finally
        {
            if (workbook != null)
            {
                workbook.Close(false);
            }
            Marshal.ReleaseComObject(workbook);
        }
    }
    finally { Marshal.ReleaseComObject(workbooks); }
}
finally
{
    if (excelApplication != null)
    {
        excelApplication.Quit();
    }
    Marshal.ReleaseComObject(excelApplication);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/10 10:00

    申し訳ございません。上記のエラーはデータ型が間違っていた為起きたエラーでした。
    現状、for文をコメントアウトして動かしたところタスクは残らず正常に終了できていました。あと解放するのはrangeだけでよろしいのでしょうか?

    キャンセル

  • 2017/08/10 10:13

    上記のFor内のrangeは値にアクセスするだけなので解放は恐らく不要かと思います。
    うまくいかない様なら入れてあげてください。

    キャンセル

  • 2017/08/12 23:33

    無事できました。また何かありましたらお願いします。

    キャンセル

0

環境がなくて試していませんが、処理の最後にオブジェクトを明示的に解放してみてはいかがでしょうか。

app = Nothing
book = Nothing
sheet = Nothing
books = Nothing

下記リンク先に似たような話があります。
詳しくは読んでないですし、結構古い話なので今とは違うかもしれませんが、参考まで。
https://qa.atmarkit.co.jp/q/1227

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/09 15:25

    コメントありがとうございます。
    すいません。リンク先を読んでもあまりよく理解できませんでした。
    ちなみにsheetをコメントアウトして行ったところタスクはちゃんと閉じられていたのでsheetがおかしいんではないかと思いました。。。

    キャンセル

  • 2017/08/09 15:28

    リンク先は回答のネタ元にした話なので、参考程度に見てもらえれば良いです。
    要は全部のオブジェクトを解放しないとダメなんじゃないの、ってことを言いたいだけです。
    Yuki_Sさんの回答にあるように、解放の順番は考慮しないとダメかもしれないですね。

    キャンセル

0

app→books→book→sheetの順でアクセスしているのでリリースするのはこの逆の順でリリースする必要があります。

パッと見た感じ

Marshal.ReleaseComObject(***)

のbookとbooksが逆になっているので順番を変えてみてください。
またttyp03さんのリンクにあるようにリリース前にチェックをしておいた方がいいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/09 15:25

    コメントありがとうございます。
    順番を変えてもだめでした。
    ちなみにsheetをコメントアウトして行ったところタスクはちゃんと閉じられていたのでsheetがおかしいんではないかと思いました。。。

    キャンセル

  • 2017/08/09 15:43

    状況があまりわかりませんが、一度アプリを閉じる前にbook.close()でブック自体を閉じる処理を入れてみたらどうなりますかね?

    キャンセル

0

'シートの指定
sheet = book.Worksheets(1)

Worksheets はメソッドではなくプロパティなので、変数で受けて開放する必要がありますね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/09 17:09

    Range オブジェクトも同様に解放する必要があるのかも知れませんね。
    また、セキュリティソフトなどでリアルタイム監視している場合は、 book.Save() と app.Quit() の間にも適当にSleepをいれると解放されたなどの話を聞いたことがあります。

    キャンセル

  • 2017/08/09 17:12

    とりあえずはRangeを使用している箇所はコメントアウトして実行しているのですが、使用していなくても解放しなくてはいけないのですか??

    キャンセル

  • 2017/08/09 17:15

    使ってないものは解放できません。

    キャンセル

0

WorksheetsとRangeの解放が必要ですね。以下サンプルコードです。

'参照設定はCOM(Microsoft Excel 16.0 Object Library)ではなく
'.NETアセンブリ(Microsoft.Office.Interop.Excel)を使用。

Imports Microsoft.Office.Interop

Public Class Form1

    '自分で解放版
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Using coms As New ComStack
            Dim app As New Excel.Application : coms.Push(app)
            Dim books = app.Workbooks : coms.Push(books)
            Dim book = books.Open("C:\Users\(user)\Documents\Book1.xlsx") : coms.Push(book)
            Dim sheets = book.Worksheets : coms.Push(sheets)
            Dim sheet = DirectCast(sheets(1), Excel.Worksheet) : coms.Push(sheet)
            Dim range = sheet.Range("A1") : coms.Push(range) : range.Value = "abc"
            range = sheet.Range("B2") : coms.Push(range) : range.Value = "def"
            app.Visible = True
            System.Threading.Thread.Sleep(5000)
            book.Save()
            app.Quit()
        End Using
    End Sub

    'GCで解放版
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        DoExcelTask()
        GC.Collect()
        'メモ:Excel操作とGC.Collectは別プロシージャに書く。
    End Sub

    Private Sub DoExcelTask()
        Dim app As New Excel.Application
        Dim book = app.Workbooks.Open("C:\Users\(user)\Documents\Book1.xlsx")
        Dim sheet = DirectCast(book.Worksheets(1), Excel.Worksheet)
        sheet.Range("A1").Value = "abc"
        sheet.Range("B2").Value = "def"
        app.Visible = True
        System.Threading.Thread.Sleep(5000)
        book.Save()
        app.Quit()
    End Sub

End Class

'COM解放用ヘルパークラス
Class ComStack
    Inherits Stack(Of Object)
    Implements IDisposable

    Sub Dispose() Implements IDisposable.Dispose
        Do Until Count = 0
            System.Runtime.InteropServices.Marshal.ReleaseComObject(Pop())
        Loop
        GC.SuppressFinalize(Me)
    End Sub
End Class

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる