web-dev-qa-db-ja.com

quitを呼び出した後にアプリケーションが終了しない

ちょっとみんな私にはわからないように見える小さな問題があります。 DataGridView(その内容)をxlsファイルに保存しています。タスクマネージャーで実行中であることを示す以外は、問題なく実行できます。私は電話した:

  xlApp.Application.Quit() 

これは次のように宣言されます:

  Dim xlApp As New Excel.Application

これは機能しないように見えますが、これはユーザーにWord文書へのエクスポートを選択させたときに終了するのと同じ方法です。私はどこが間違っているのか分かりません...

ここに私の完全なコードがあります

Imports Word = Microsoft.Office.Interop.Word
 Imports Excel = Microsoft.Office.Interop.Excel

 Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    For x As Integer = 1 To 3500
        DataGridView1.Rows.Add(New Object() {"r" & x.ToString & "c1", "r" & x.ToString & "c2", "r" & x.ToString & "c3", "r" & x.ToString & "c4", "r" & x.ToString & "c5"})
    Next
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    exportToWord (DataGridView1)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim xlApp As New Excel.Application
    Dim xlWorkBook As Excel.Workbook
    Dim xlWorkSheet As Excel.Worksheet
    'Dim misValue As Object = System.Reflection.Missing.Value


    xlWorkBook = xlApp.Workbooks.Add
    xlWorkSheet = DirectCast(xlWorkBook.Sheets("sheet1"), Excel.Worksheet)

    xlApp.Visible = True

    Dim headers = (From ch In DataGridView1.Columns _
                  Let header = DirectCast(DirectCast(ch, DataGridViewColumn).HeaderCell, DataGridViewColumnHeaderCell) _
                  Select header.Value).ToArray()
    Dim headerText() As String = Array.ConvertAll(headers, Function(v) v.ToString)

    Dim items() = (From r In DataGridView1.Rows _
          Let row = DirectCast(r, DataGridViewRow) _
          Where Not row.IsNewRow _
          Select (From cell In row.Cells _
              Let c = DirectCast(cell, DataGridViewCell) _
              Select c.Value).ToArray()).ToArray()

    Dim table As String = String.Join(vbTab, headerText) & Environment.NewLine
    For Each a In items
        Dim t() As String = Array.ConvertAll(a, Function(v) v.ToString)
        table &= String.Join(vbTab, t) & Environment.NewLine
    Next
    table = table.TrimEnd(CChar(Environment.NewLine))
    Clipboard.SetText (table)

    Dim alphabet() As Char = "abcdefghijklmnopqrstuvwxyz".ToUpper.ToCharArray

    Dim range As Excel.Range = xlWorkSheet.Range("B2:" & alphabet(headerText.Length) & (items.Length + 2).ToString)

    range.Select()
    xlWorkSheet.Paste()

    range.Borders(Excel.XlBordersIndex.xlDiagonalDown).LineStyle = Excel.XlLineStyle.xlLineStyleNone
    range.Borders(Excel.XlBordersIndex.xlDiagonalUp).LineStyle = Excel.XlLineStyle.xlLineStyleNone
    With range.Borders(Excel.XlBordersIndex.xlEdgeLeft)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With range.Borders(Excel.XlBordersIndex.xlEdgeTop)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With range.Borders(Excel.XlBordersIndex.xlEdgeBottom)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With range.Borders(Excel.XlBordersIndex.xlEdgeRight)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With range.Borders(Excel.XlBordersIndex.xlInsideVertical)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlThin
    End With
    With range.Borders(Excel.XlBordersIndex.xlInsideHorizontal)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlThin
    End With

    'xlApp.Visible = True

    xlWorkBook.SaveAs("C:\Users\CoDeXeR\Desktop\Word1.xls", True)
    xlWorkBook.Close()
    xlApp.Application.Quit()

    ReleaseObject(xlWorkSheet) '<~~~ Added as per comment from deleted post
    ReleaseObject (xlWorkBook)
    ReleaseObject (xlApp)


End Sub

Public Sub exportToWord(ByVal dgv As DataGridView)
    ' Create Word Application
    Dim oWord As Word.Application = DirectCast(CreateObject("Word.Application"), Word.Application)

    ' Create new Word document
    Dim oDoc As Word.Document = oWord.Documents.Add()


    Dim headers = (From ch In dgv.Columns _
                  Let header = DirectCast(DirectCast(ch, DataGridViewColumn).HeaderCell, DataGridViewColumnHeaderCell) _
                  Select header.Value).ToArray()
    Dim headerText() As String = Array.ConvertAll(headers, Function(v) v.ToString)

    Dim items() = (From r In dgv.Rows _
          Let row = DirectCast(r, DataGridViewRow) _
          Where Not row.IsNewRow _
          Select (From cell In row.Cells _
              Let c = DirectCast(cell, DataGridViewCell) _
              Select c.Value).ToArray()).ToArray()

    Dim table As String = String.Join(vbTab, headerText) & Environment.NewLine
    For Each a In items
        Dim t() As String = Array.ConvertAll(a, Function(v) v.ToString)
        table &= String.Join(vbTab, t) & Environment.NewLine
    Next
    table = table.TrimEnd(CChar(Environment.NewLine))
    Clipboard.SetText (table)

    Dim oTable As Word.Table = oDoc.Tables.Add(oDoc.Bookmarks.Item("\endofdoc").Range, items.Count + 1, headers.Count)

    oTable.Range.Paste()

    'make the first row bold, fs 14 + change textcolor
    oTable.Rows.Item(1).range.Font.Bold = &H98967E
    oTable.Rows.Item(1).range.Font.Size = 14
    oTable.Rows.Item(1).range.Font.Color = Word.WdColor.wdColorWhite

    'change backcolor of first row
    oTable.Rows.Item(1).range.Shading.Texture = Word.WdTextureIndex.wdTextureNone
    oTable.Rows.Item(1).range.Shading.ForegroundPatternColor = Word.WdColor.wdColorAutomatic
    oTable.Rows.Item(1).range.Shading.BackgroundPatternColor = Word.WdColor.wdColorLightBlue

    ''set table borders
    'With oTable.Range.Tables(1)
    '    With .Borders(Word.WdBorderType.wdBorderLeft)
    '        .LineStyle = Word.WdLineStyle.wdLineStyleSingle
    '        .LineWidth = Word.WdLineWidth.wdLineWidth100pt
    '        .Color = Word.WdColor.wdColorAutomatic
    '    End With
    '    With .Borders(Word.WdBorderType.wdBorderRight)
    '        .LineStyle = Word.WdLineStyle.wdLineStyleSingle
    '        .LineWidth = Word.WdLineWidth.wdLineWidth100pt
    '        .Color = Word.WdColor.wdColorAutomatic
    '    End With
    '    With .Borders(Word.WdBorderType.wdBorderTop)
    '        .LineStyle = Word.WdLineStyle.wdLineStyleSingle
    '        .LineWidth = Word.WdLineWidth.wdLineWidth100pt
    '        .Color = Word.WdColor.wdColorAutomatic
    '    End With
    '    With .Borders(Word.WdBorderType.wdBorderBottom)
    '        .LineStyle = Word.WdLineStyle.wdLineStyleSingle
    '        .LineWidth = Word.WdLineWidth.wdLineWidth100pt
    '        .Color = Word.WdColor.wdColorAutomatic
    '    End With
    '    With .Borders(Word.WdBorderType.wdBorderHorizontal)
    '        .LineStyle = Word.WdLineStyle.wdLineStyleSingle
    '        .LineWidth = Word.WdLineWidth.wdLineWidth050pt
    '        .Color = Word.WdColor.wdColorAutomatic
    '    End With
    '    With .Borders(Word.WdBorderType.wdBorderVertical)
    '        .LineStyle = Word.WdLineStyle.wdLineStyleSingle
    '        .LineWidth = Word.WdLineWidth.wdLineWidth050pt
    '        .Color = Word.WdColor.wdColorAutomatic
    '    End With
    '    .Borders(Word.WdBorderType.wdBorderDiagonalDown).LineStyle = Word.WdLineStyle.wdLineStyleNone
    '    .Borders(Word.WdBorderType.wdBorderDiagonalUp).LineStyle = Word.WdLineStyle.wdLineStyleNone
    '    .Borders.Shadow = False
    'End With
    ' Save this Word document
    oDoc.SaveAs("C:\Users\CoDeXeR\Desktop\Word1.doc", True)
    oDoc.Close()
    oWord.Application.Quit()
    'oWord.Visible = True

End Sub

Public Sub exportToExcel(ByVal dgv As DataGridView)

End Sub

Private Sub ReleaseObject(ByVal obj As Object)
    Try
        System.Runtime.InteropServices.Marshal.ReleaseComObject (obj)
        obj = Nothing
    Catch ex As Exception
        obj = Nothing
    Finally
        GC.Collect()
    End Try
End Sub

 End Class
15
Çöđěxěŕ

.Quit()を呼び出すだけでは、アプリケーションはメモリから削除されません。コーディングが完了したら、オブジェクトを閉じることが非常に重要です。これにより、すべてのオブジェクトが適切に解放され、メモリに何も残りません。

この例をご覧ください

_Imports Excel = Microsoft.Office.Interop.Excel

Public Class Form1
    '~~> Define your Excel Objects
    Dim xlApp As New Excel.Application
    Dim xlWorkBook As Excel.Workbook

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        '~~> Add a New Workbook
        xlWorkBook = xlApp.Workbooks.Add

        '~~> Display Excel
        xlApp.Visible = True

        '~~> Do some stuff Here

        '~~> Save the file
        xlWorkBook.SaveAs(Filename:="C:\Tutorial\SampleNew.xlsx", FileFormat:=51)

        '~~> Close the File
        xlWorkBook.Close()

        '~~> Quit the Excel Application
        xlApp.Quit()

        '~~> Clean Up
        releaseObject (xlApp)
        releaseObject (xlWorkBook)
    End Sub

    '~~> Release the objects
    Private Sub releaseObject(ByVal obj As Object)
        Try
            System.Runtime.InteropServices.Marshal.ReleaseComObject (obj)
            obj = Nothing
        Catch ex As Exception
            obj = Nothing
        Finally
            GC.Collect()
        End Try
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Me.Close()
    End Sub
End Class
_

また、言及する価値があるのは 2 DOTルール です。

VB.NetからExcelを自動化するのが好きなら、この link もご覧ください。

[〜#〜] followup [〜#〜]

問題は、前述の2 DOTルールです。 2 DOTルール(例:_Excel.XlBordersIndex.xlDiagonalDown_)を使用する場合、GC.Collect()を使用してガベージコレクションを実行する必要があります。この部分を追加するだけです

_    Finally
        GC.Collect()
_

Private Sub ReleaseObject(ByVal obj As Object)

_Private Sub ReleaseObject(ByVal obj As Object)
    Try
        Dim intRel As Integer = 0
        Do
            intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
        Loop While intRel > 0
        MsgBox("Final Released obj # " & intRel)
    Catch ex As Exception
        MsgBox("Error releasing object" & ex.ToString)
        obj = Nothing
    Finally
        GC.Collect()
    End Try
End Sub
_

最終コード(試行およびテスト済み)

_Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim xlApp As New Excel.Application
    Dim xlWorkBook As Excel.Workbook
    Dim xlWorkSheet As Excel.Worksheet
    Dim xlRange As Excel.Range
    'Dim misValue As Object = System.Reflection.Missing.Value

    xlWorkBook = xlApp.Workbooks.Add
    xlWorkSheet = DirectCast(xlWorkBook.Sheets("sheet1"), Excel.Worksheet)

    xlApp.Visible = True

    Dim headers = (From ch In DataGridView1.Columns _
                  Let header = DirectCast(DirectCast(ch, DataGridViewColumn).HeaderCell, DataGridViewColumnHeaderCell) _
                  Select header.Value).ToArray()
    Dim headerText() As String = Array.ConvertAll(headers, Function(v) v.ToString)

    Dim items() = (From r In DataGridView1.Rows _
          Let row = DirectCast(r, DataGridViewRow) _
          Where Not row.IsNewRow _
          Select (From cell In row.Cells _
              Let c = DirectCast(cell, DataGridViewCell) _
              Select c.Value).ToArray()).ToArray()

    Dim table As String = String.Join(vbTab, headerText) & Environment.NewLine
    For Each a In items
        Dim t() As String = Array.ConvertAll(a, Function(v) v.ToString)
        table &= String.Join(vbTab, t) & Environment.NewLine
    Next
    table = table.TrimEnd(CChar(Environment.NewLine))
    Clipboard.SetText(table)

    Dim alphabet() As Char = "abcdefghijklmnopqrstuvwxyz".ToUpper.ToCharArray

    xlRange = xlWorkSheet.Range("B2:" & alphabet(headerText.Length) & (items.Length + 2).ToString)

    xlRange.Select()
    xlWorkSheet.Paste()

    xlRange.Borders(Excel.XlBordersIndex.xlDiagonalDown).LineStyle = Excel.XlLineStyle.xlLineStyleNone
    xlRange.Borders(Excel.XlBordersIndex.xlDiagonalUp).LineStyle = Excel.XlLineStyle.xlLineStyleNone

    With xlRange.Borders(Excel.XlBordersIndex.xlEdgeLeft)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With xlRange.Borders(Excel.XlBordersIndex.xlEdgeTop)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With xlRange.Borders(Excel.XlBordersIndex.xlEdgeBottom)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With xlRange.Borders(Excel.XlBordersIndex.xlEdgeRight)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlMedium
    End With
    With xlRange.Borders(Excel.XlBordersIndex.xlInsideVertical)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlThin
    End With
    With xlRange.Borders(Excel.XlBordersIndex.xlInsideHorizontal)
        .LineStyle = Excel.XlLineStyle.xlContinuous
        .ColorIndex = 1 'black
        .TintAndShade = 0
        .Weight = Excel.XlBorderWeight.xlThin
    End With

    xlWorkBook.SaveAs(Filename:="C:\Users\Siddharth Rout\Desktop\Word1.xls", FileFormat:=56)
    xlWorkBook.Close()
    xlApp.Quit()

    ReleaseObject(xlRange)
    ReleaseObject(xlWorkSheet)
    ReleaseObject(xlWorkBook)
    ReleaseObject(xlApp)
End Sub


Private Sub ReleaseObject(ByVal obj As Object)
    Try
        Dim intRel As Integer = 0
        Do
            intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
        Loop While intRel > 0
        MsgBox("Final Released obj # " & intRel)
    Catch ex As Exception
        MsgBox("Error releasing object" & ex.ToString)
        obj = Nothing
    Finally
        GC.Collect()
    End Try
End Sub
_
31
Siddharth Rout

上記の@SiddharthRoutのコメントに従うまで、上記の推奨事項はどれも役に立ちませんでした。 " 今日現在、COMオブジェクトを操作する正しい方法は何ですか? "

Comオブジェクト参照は、デバッガーの下で維持されていることが指摘されています。回避策は、comプロシージャを呼び出すプロシージャからGCを呼び出すことです。それは私のために働いた。

TRY Catchブロックで、FinallyからGCを実行します。

コピー元:post by "Govert" on what is the right way to work with COM objects?

using System;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

namespace TestCsCom
{
        Class Program
    {
        static void Main(string[] args)
        {
            // NOTE: Don't call Excel objects in here... 
            //       Debugger would keep alive until end, preventing GC cleanup

            // Call a separate function that talks to Excel
            DoTheWork();

            // Now let the GC clean up (repeat, until no more)
            do
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
            while (Marshal.AreComObjectsAvailableForCleanup());
        }

        static void DoTheWork()
        {
            Application app = new Application();
            Workbook book = app.Workbooks.Add();
            Worksheet worksheet = book.Worksheets["Sheet1"];
            app.Visible = true;
            for (int i = 1; i <= 10; i++) {
                worksheet.Cells.Range["A" + i].Value = "Hello";
            }
            book.Save();
            book.Close();
            app.Quit();

            // NOTE: No calls the Marshal.ReleaseComObject() are ever needed
        }
    }
}
2
ppete3

スクリプトでExcelドキュメントを閉じる機能を何度も使用し、非表示にして表示し、開いている唯一のブックである場合は閉じ、それ以外の場合はこのワークシートを閉じます。これが私の

Sub ExitWorkBook()
Dim wb As Workbook
Dim c As Integer
    c = 0       
    For Each wb In Application.Workbooks
        c = c + 1
    Next wb
    If c = 1 Then
        Application.Quit   '--Quit this worksheet but keep Excel open.
    Else
        Workbooks("(Excel workbook name).xls").Close    '-- Close Excel
    End If
'
End Sub
1
Michael Edmison

私は以下を使用して問題を解決しました:

Set xlApp = Nothing

監視TaskManagerを確認できます。

0
farope

Excelオブジェクトへの参照のすべてのインスタンスを明示的に解放する必要があることがわかりました。

        xlApp = New Excel.Application
        xlWorkBooks = xlApp.Workbooks
        xlWorkBook = xlWorkBooks.Open(Me.txtFilePath.Text)
        xlWorkSheets = xlWorkBook.Worksheets
        xlWorkSheet = CType(xlWorkSheets(1), Excel.Worksheet)

        xlWorkBook.Close()
        xlWorkBooks.Close()
        xlApp.Quit()

        releaseObject(xlWorkSheet)
        xlWorkSheet = Nothing
        releaseObject(xlWorkSheets)
        xlWorkSheets = Nothing
        releaseObject(xlWorkBook)
        xlWorkBook = Nothing
        releaseObject(xlWorkBooks)
        xlWorkBooks = Nothing
        releaseObject(xlApp)
        xlApp = Nothing

    Private Sub releaseObject(ByVal obj As Object)
        Try
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj)
            obj = Nothing
        Catch ex As Exception
            obj = Nothing
        Finally
            GC.Collect()
        End Try
    End Sub
0
user8233562

同じ問題がありました。ただし、問題はデバッグ中にのみ持続しました。あなたがする必要があるのは

xlWorkBook.Close
xlApp.Quit

次に、コードを実行します。 Button1_Clickが終了した後にガベージコレクターを呼び出す必要があるかもしれませんが、私もそれを必要としませんでした。コードをステップスルーするか、コードを完全に完全に終了させないと、物事がスローされ、Excelが開いたままになるようです。

VB.netで閉じられないExcelプロセス を参照してください

0
Jon

私はこの関数を仕事の後、最初のXlApp呼び出しで使用し、now()日付をFirstDateに設定します

Private Sub End_Excel_App_After_Work(ByVal DateStart As Date, ByVal DateEnd As Date)
    Dim xlp() As Process = Process.GetProcessesByName("Excel")
    For Each Process As Process In xlp
        If Process.StartTime >= DateStart Then
            If Process.StartTime <= DateEnd Then

                Process.Kill()
                Exit For
            End If
        End If
    Next
    xlp = Process.GetProcessesByName("Microsoft Excel")
    For Each Process As Process In xlp
        If Process.StartTime >= DateStart Then
            If Process.StartTime <= DateEnd Then

                Process.Kill()
                Exit For
            End If
        End If
    Next
    xlp = Process.GetProcessesByName("Excel.EXE")
    For Each Process As Process In xlp
        If Process.StartTime >= DateStart Then
            If Process.StartTime <= DateEnd Then

                Process.Kill()
                Exit For
            End If
        End If
    Next
End Sub

そして、プロセスの後、この関数を呼び出します。次のようなもの:

 Dim FromDT As Date = Now
    Dim xlApp As New Excel.Application
    xlApp = New Excel.Application()
          Dim xlWorkBook As Excel.Workbook
    Dim xlWorkSheet As Excel.Worksheet
     Microsoft.Office.Interop.Excel.Application()

    'End Using
    Try

        xlWorkBook = xlApp.Workbooks.Open("d:\"FIle NAME".xlsX")
        xlWorkSheet = xlWorkBook.Worksheets("WORKSHEET")
      ...CODE BE IN HERE
                   xlWorkBook.Close()
        xlApp.Quit()
        xlApp = Nothing
        ReleaseObject(xlApp)
        ReleaseObject(xlWorkBook)
        ReleaseObject(xlWorkSheet)

        End_Excel_App_After_Work(FromDT, Now)
    Catch ex As Exception
        xlApp.Application.Quit()
        End_Excel_App_After_Work(FromDT, Now)
    End Try
0
hamid khp

For Each w In Application.Workbooks w.Save Next w Application.Quit

http://msdn.Microsoft.com/en-us/library/office/ff839269.aspx

0
user1796855