9

Microsoft.Office.Interop.Excel.Application オブジェクトを介して Excel スプレッドシートを開く Windows サービスがあります。

Application xlApp = new Application();
Workbook workbook = xlApp.Workbooks.Open(fileName, 2, false);
...
...
workbook.Close();
xlApp.Quit();

ワークブックでの作業が完了した後も実行されている EXCEL.exe プロセスを強制終了したいと考えています。

私は成功せずに次のことを試しました...

// This returns a processId of 0
IntPtr processId;
GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), out processId);
Process p = Process.GetProcessById(processId.ToInt32());   
p.Kill();

Windowsサービスを介してこれを行う方法について、誰かアイデアがありますか?

4

13 に答える 13

11

開いている Excel ブックを適切に閉じて、アプリを終了するのは非常に困難です。リンクが見つかったら投稿しますが、基本的には、作成したCOM オブジェクトへのすべての参照をクリーンアップする必要があります。これには、ODBCConnections (データ接続)、ワークシート、ワークブック、および Excel アプリケーションのすべてが含まれます。私が取り組むようになった組み合わせには、ガベージ コレクションとSystem.Runtime.InteropServices.Marshalオブジェクトが含まれていました。

// Garbage collecting
GC.Collect();
GC.WaitForPendingFinalizers();
// Clean up references to all COM objects
// As per above, you're just using a Workbook and Excel Application instance, so release them:
workbook.Close(false, Missing.Value, Missing.Value);
xlApp.Quit();
Marshal.FinalReleaseComObject(workbook);
Marshal.FinalReleaseComObject(xlApp);

前述のように、各 Excel プロセスをループして強制終了することは、通常はお勧めできません。これを Windows アプリとして実行している場合は、ユーザーの Excel を閉じたり、サービスで実行中の Excel のインスタンスを閉じたりする可能性があるためです。他のプログラムを介して。

編集: 詳細については、この質問を参照してください。

于 2011-04-12T13:52:07.473 に答える
8

プロセスによって開かれているファイルハンドルを確認してPIDを取得し、それを強制終了する必要があります。それは私のために働いた。

private void genExcel(
{
   int pid = -1;
   //Get PID
   xlApp = new Excel.Application();
   HandleRef hwnd = new HandleRef(xlApp, (IntPtr)xlApp.Hwnd);
   GetWindowThreadProcessId(hwnd, out pid);
   .
   .
   .
   .
   //Finally
   KillProcess(pid,"EXCEL");
}

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);

private void KillProcess(int pid, string processName)
{
    // to kill current process of excel
    System.Diagnostics.Process[] AllProcesses = System.Diagnostics.Process.GetProcessesByName(processName);
    foreach (System.Diagnostics.Process process in AllProcesses)
    {
       if (process.Id == pid)
       {
         process.Kill();
       }
    }
    AllProcesses = null;
}
于 2012-10-06T09:20:24.863 に答える
6

多くの読書と欲求不満の後、私は解決策を見つけました!

この投稿のソリューションについては、 dotNetkownightcoderMike Rosenblumにすべての功績があります。Excel相互運用オブジェクトを適切にクリーンアップするにはどうすればよいですか?

これが私がしたことです...
1。プロジェクトのビルドモードを「リリース」に変更しました(DEBUGモードでは、COMオブジェクトは参照を破棄するのに苦労します
。2。すべての二重ドット式を削除しました(すべてのCOMオブジェクトは結合する必要があります)解放できるように変数に変換します
)3。finallyブロックでGC.Collect()、GC.WaitForPendingFinalizers()、およびMarshal.FinalReleaseComObject()を明示的に呼び出します。

これが私が使用している実際のコードです:

Application xlApp = null;
Workbooks workbooks = null;
Workbook workbook = null;
Worksheet sheet = null;
Range r = null;
object obj = null;

try
{
    xlApp = new Application();
    xlApp.DisplayAlerts = false;
    xlApp.AskToUpdateLinks = false;
    workbooks = xlApp.Workbooks;
    workbook = workbooks.Open(fileName, 2, false);
    sheet = workbook.Worksheets[1];

    r = sheet.get_Range("F19");
    obj = r.get_Value(XlRangeValueDataType.xlRangeValueDefault);
}
finally
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    if (value != null) Marshal.FinalReleaseComObject(value);
    if (r != null) Marshal.FinalReleaseComObject(r);
    if (sheet != null) Marshal.FinalReleaseComObject(sheet);
    if (workbooks != null) Marshal.FinalReleaseComObject(workbooks);
    if (workbook != null)
    {
        workbook.Close(Type.Missing, Type.Missing, Type.Missing);
        Marshal.FinalReleaseComObject(workbook);
    }
    if (xlApp != null)
    {
        xlApp.Quit();
        Marshal.FinalReleaseComObject(xlApp);
    }
}
于 2011-04-12T15:34:51.843 に答える
3

私の答えがあなたが探しているものではないかどうかわかりません...もしそうなら教えてください、そして私はそれを削除するつもりです。とにかく私はこれを使用しました:

Application xlApp = new Application();
xlApp.DisplayAlerts = false;
xlApp.Visible = true; // Only for debug purposes
Workbook workbook = xlApp.Workbooks.Open(filename, 2, false);
...
...
workbook.Close();
xlApp.Quit();

ブックを閉じてxlAppを終了すると、PCのメモリからEXCEL.EXEが削除されます。
WindowsXP32ビットとMicrosoftOffice2007を使用しています。

また、このテストアプリを使用する前に、別のExcelファイルを開こうとしました。2番目のEXCEL.EXEが開かれ、最後に(Quitを使用して)閉じられ、最初のインスタンスは変更されません。

于 2011-04-11T21:20:09.617 に答える
3

シンプルだが効果的なソリューションを使用しました

finally   { 
GC.Collect();
GC.WaitForPendingFinalizers();           
        if (xlApp != null)
            {
                xlApp .Quit();
                int hWnd = xlApp .Application.Hwnd;
                uint processID;GetWindowThreadProcessId((IntPtr)hWnd, out processID);
                Process[] procs = Process.GetProcessesByName("EXCEL");
                foreach (Process p in procs)
                {
                    if (p.Id == processID)
                        p.Kill();
                }
                Marshal.FinalReleaseComObject(xlApp );
            } 
        }

すべてのExcell.exeプロセスを検索します。次に、excelApplicationのプロセスIDを取得します。IDが一致するプロセスのみを強制終了します。クラスでGetWindowThreadProcessIdを宣言するために使用します。

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
于 2011-11-19T09:39:03.733 に答える
2

私の解決策

[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

private void GenerateExcel()
{
    var excel = new Microsoft.Office.Interop.Excel.Application();
    int id;
    // Find the Process Id
    GetWindowThreadProcessId(excel.Hwnd, out id);
    Process excelProcess = Process.GetProcessById(id);

try
{
    // Your code
}
finally
{
    excel.Quit();

    // Kill him !
    excelProcess.Kill();
}
于 2014-06-18T09:22:42.183 に答える
1

以下は、Excel インスタンスを開いて削除するコードです。Excel に関連するすべてのオブジェクトが閉じていることを確認するだけです。

    string strFilePath = @"C:\Sample.xlsx";
        try
        {
            Excel.Application excelApp = null;
        Excel.Workbook excelWorkbook = null;
        Excel.Sheets excelSheets = null;
        Excel.Worksheet excelWorksheet = null;
        Excel.Workbooks excelWorkbooks = null;
        Excel.Range excelUsedRange = null;



            excelApp = new Microsoft.Office.Interop.Excel.Application();
            int nData = excelApp.Hwnd;
            // excelApp = new Excel.ApplicationClass();
            //excelApp.Visible = true;
            excelWorkbooks = excelApp.Workbooks;
            excelWorkbook = excelWorkbooks.Add(System.Reflection.Missing.Value);

            excelWorkbook = excelApp.Workbooks.Open(strFilePath, 2, false);
            //excelWorkbook = excelApp.Workbooks.Open(strFilePath,
            //                                                                                       
               Type.Missing, Type.Missing,
            //                                                                                    
               Type.Missing, Type.Missing,
            //                                                                                    
               Type.Missing, Type.Missing,
            //                                                                                    
               Type.Missing, Type.Missing,
            //                                                                                    
               Type.Missing, Type.Missing,
            //                                                                                    
               Type.Missing, Type.Missing,
            //                                                                                    
               Type.Missing, Type.Missing);


            excelSheets = excelWorkbook.Worksheets;
           // excelWorksheet = (Excel.Worksheet)excelSheets.get_Item(1);
            excelWorksheet = (Excel.Worksheet)excelWorkbook.Worksheets["Dem0_1"];



            excelUsedRange = excelWorksheet.UsedRange;


            //Excel.Range lastCell = usedRange.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
            //int lastRow = lastCell.Row;
            //int lastCol = lastCell.Column;
            //int rowMin = lastRow + 1;
            //int colMin = lastCol + 1;

            int nRowsCount = excelUsedRange.Rows.Count;
            int nColCount = excelUsedRange.Columns.Count;



             int N_Quality_Header = -1;
             int N_Measurement_Name = -1;
             int N_Lower_Tolerance = -1;
             int N_Upper_Tolerance = -1;


             //Read the Columns Index 
             for (int nColIndex = 1; nColIndex <= nColCount; nColIndex++)
             {
                 Excel.Range cell = usedRange.Cells[1, nColIndex] as Excel.Range;
                 String strCellValue = cell.Value2.ToString();
                 if (strCellValue == "Quality Header")
                     N_Quality_Header = nColIndex;

                 else if (strCellValue.IndexOf("Measurement Name", StringComparison.OrdinalIgnoreCase) > -1)
                     N_Measurement_Name = nColIndex;
                 else if (strCellValue.IndexOf("Lower Tolerance", StringComparison.OrdinalIgnoreCase) > -1)
                     N_Lower_Tolerance = nColIndex;
                 else if (strCellValue.IndexOf("Upper Tolerance", StringComparison.OrdinalIgnoreCase) > -1)
                     N_Upper_Tolerance = nColIndex;
             }

             //Read all rows to get the values
             for (int nRowIndex = 2; nRowIndex <= nRowsCount; nRowIndex++)
             {
                 Excel.Range cellQualityHeader = usedRange.Cells[nRowIndex, N_Quality_Header] as Excel.Range;
                 String strValue = cellQualityHeader.Value2.ToString();
                 if (strValue == String_Empty)
                     continue;


             }


        }
        catch (Exception oException)
        {


        }
        finally
        {
            excelUsedRange.Clear();
            //excelWorkbook.Save();
            excelWorkbook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);

            excelWorkbooks.Close();
            excelApp.Quit();

            Marshal.ReleaseComObject(excelUsedRange);
            Marshal.ReleaseComObject(excelWorksheet);
            Marshal.ReleaseComObject(excelSheets);
            Marshal.ReleaseComObject(excelWorkbooks);
            Marshal.ReleaseComObject(excelWorkbook);
            Marshal.ReleaseComObject(excelApp);


            excelUsedRange = null;
            excelWorksheet = null;
            excelSheets = null;
            excelWorkbooks = null;
            excelWorkbook = null;
            excelApp = null;

            GC.GetTotalMemory(false);
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.GetTotalMemory(true);



        }
于 2012-09-27T07:08:41.310 に答える
0

私はProcess.GetProcessを使用して、そこでexeファイルを探します。ウィンドウはアクセスできないデスクステーションで作成されると思うので、サービスの世界のウィンドウとは何の関係もありません。

于 2011-04-11T21:12:42.303 に答える
0

これは、未使用の Excel プロセスをすべて強制終了するための私のコードです。

Process[] process = Process.GetProcessesByName("excel");
        foreach (Process excel in process)
        {
            if (excel.HasExited)
            {
                excel.Kill();
            }
        }
        process = null;
于 2016-03-16T05:45:25.657 に答える
0

それほどエレガントではないかもしれませんが、受け入れられたソリューションと Safrin のソリューションを組み合わせることになりました。そのため、最初はエレガントな方法で実行しようと試み、それが失敗した場合は総当たりを使用します。その理由は、コードが、1 つの Excel 更新操作が失敗した場合でも続行できる必要があるバッチ プロシージャの一部であるためです。私の問題は、PowerPivot モデルのエラーが原因でエラー メッセージが表示されたダイアログが表示されたことが原因でした。このダイアログは、バックグラウンド プロセスとして実行され、Excel が閉じないように見えたため、表示されませんでした。ダイアログが閉じられるまで (?!)、私のプロセスは続行されませんでした。したがって、タイムアウトメカニズムを使用して別のスレッドでプロセスを開始し、終了が機能しない場合は、作業オブジェクトの破棄時に Excel を強制終了することが、私が考えることができる唯一の解決策でした (それが機能します)...

    public void Dispose()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        if (workbook != null)
        {
            try
            {
                workbook.Close(false);
                Marshal.FinalReleaseComObject(workbook);
            }
            catch { }
        }
        if (excel != null)
        {
            try { excel.Quit(); }
            catch {
                int hWnd = excel.Application.Hwnd;
                uint processID; 
                GetWindowThreadProcessId((IntPtr)hWnd, out processID);
                Process[] procs = Process.GetProcessesByName("EXCEL");
                foreach (Process p in procs)
                {
                    if (p.Id == processID) p.Kill();
                }

            }
            Marshal.FinalReleaseComObject(excel);
        }
    }
于 2014-10-31T16:42:57.420 に答える