-1

Excel相互運用サービスを操作するために、Excelヘルパークラスを作成しました。excel.exeしかし、サーバー上で が閉じられていないことに気付きました。(windows 2008 64bit 日本語 OS および office 2007 32bit)。プロセス エクスプローラーで確認すると、次のようなツールチップが表示されます。

Path:[Error opening process]

私はやったがexcel.Quit()Marshal.FinalReleaseComObject(_xlApp)期待どおりに何も機能せず、プロセスを強制終了しようとしましたがprocessID、まだプロセスを強制終了していません。

uint processID = 0;
GetWindowThreadProcessId((IntPtr)_hWnd, out processID);
 if (processID != 0)
 {
  System.Diagnostics.Process.GetProcessById((int)processID).Kill();
 }

次に、両方の方法で試しましたが、手動で開いたすべての Excel ドキュメントを閉じます。

System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("EXCEL");
        foreach (System.Diagnostics.Process p in procs)
        {
            int baseAdd = p.MainModule.BaseAddress.ToInt32();
            if (baseAdd == _xlApp.Hinstance)
            {
                p.Kill();
            }
        }

System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("EXCEL");
         foreach (System.Diagnostics.Process p in procs)
         {
             if (p.MainWindowTitle.Length == 0)
             {
                 p.Kill();
             }
         }

このケースに対処する方法について何か考えはありますか?

4

2 に答える 2

1

以下を使用して、タスクマネージャーからExcelを削除できたことがわかりました。

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

    /// <summary>
    /// Excel application
    /// </summary>
    private ApplicationClass m_xlApp = null;

    /// <summary>
    /// Reference to the workbook.
    /// </summary>
    private Workbook m_book = null;

    /// <summary>
    /// Reference to the worksheet.
    /// </summary>
    private Worksheet m_sheet = null;

    /// <summary>
    /// Close the workbook.
    /// </summary>
    public void Close()
    {
        if (m_book != null)
            m_book.Close(Missing.Value, Missing.Value, Missing.Value);

        if (m_xlApp != null)
        {
            m_xlApp.Workbooks.Close();
            m_xlApp.Quit();
        }

        GC.Collect();
        GC.WaitForPendingFinalizers();

        // Release the objects
        Marshal.FinalReleaseComObject(m_sheet);
        Marshal.FinalReleaseComObject(m_book);
        Marshal.FinalReleaseComObject(m_xlApp);

        m_sheet = null;
        m_book = null;
        m_xlApp = null;
    }
于 2013-01-24T13:32:42.930 に答える
1

processId を取得するのはもう少し複雑です。これを試して...

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

    /// <summary>
    /// Gets an Interop.Application object and its associated processId
    /// </summary>
    /// <returns>Excel.Application or Word.Application depending on _isExcel</returns>
    private object ApplicationFactory()
    {
        object application = null;
        string processName = (_isExcel) ? "excel" : "winword";
        Process[] beforeProcesses = null;
        Process[] afterProcesses = null;
        int i = 0;
        while (i < 3)
        { // ourProcess = afterList - beforeList
            beforeProcesses = Process.GetProcessesByName(processName);
            application = (_isExcel) ? (object)new Excel.Application() : (object)new Word.Application();
            afterProcesses = Process.GetProcessesByName(processName);
            if ((afterProcesses.Length - beforeProcesses.Length) == 1)
            { // OK. Just a single new process
                break;
            }
            else
            { // Two or more processes, we cannot get our processId
                // therefore quit while we can and try again
                if (_isExcel)
                    ((Excel._Application)application).Quit();
                else
                    ((Word._Application)application).Quit();
                int indexReferences = 1;
                do
                {
                    indexReferences = System.Runtime.InteropServices.Marshal.ReleaseComObject(application);
                }
                while (indexReferences > 0);
                application = null;
                System.Threading.Thread.Sleep(150);
                i++;
            }
        }
        if (application == null)
        {
            throw new ApplicationException("Unable to create Excel Application and get its processId");
        }
        List<int> processIdList = new List<int>(afterProcesses.Length);
        foreach (Process procDesp in afterProcesses)
        {
            processIdList.Add(procDesp.Id);
        }
        foreach (Process proc in beforeProcesses)
        {
            processIdList.Remove(proc.Id);
        }
        _processId = processIdList[0];
        return application;
    }

    /// <summary>
    /// Kills _processId process if exists
    /// </summary>
    private void ProcessKill()
    {
        Process applicationProcess = null;
        if (_processId != 0)
        {
            try
            {
                applicationProcess = Process.GetProcessById(_processId);
                applicationProcess.Kill();
            }
            catch
            { // no Process with that processId
            }
        }
    }

とは言っても、暴力は最後の手段にすぎません ;-) いくつかの COM オブジェクトが解放されていないため、強制終了する必要があります。( MS サポートを参照してください: Office アプリケーションが閉じません) COM オブジェクトを常に参照し、それらをスタックに入れ、使用後に解放してみてください

System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)

次に、単純なapplication.Quit();application = nullトリックを行います。

それが役に立てば幸い。

編集: - 常に意味: 「2 つのポイントを使用するときはいつでも ( _xlApp.Application., _xlWorkbook.Worksheets,...)

  • スタック手段に追加stack.push(_xlApp.Application)

  • リリース手段stack.pop()

mi helperStack を含めます

using System.Collections.Generic;

namespace OfficeUtils.Stack
{
/// <summary>
/// Stack of COM objects to be released
/// </summary>
public abstract class ComObjectsStack
{
    private Stack<object> comObjects = new Stack<object>();
    private int mark = 0;

    /// <summary>
    /// Releases all the remaining COM objects
    /// </summary>
    ~ComObjectsStack()
    {
        if (comObjects.Count > 0)
            ReleaseAll();
        comObjects = null;
    }

    /// <summary>
    /// Add a new object to the stack to be released
    /// </summary>
    /// <param name="obj">Nuevo objeto a liberar</param>
    public void Push(object obj)
    {
        comObjects.Push(obj);
    }

    /// <summary>
    /// Release the last object in the stack
    /// </summary>
    public void Pop()
    {
        Release(1);
    }

    /// <summary>
    /// Mark for future use of ReleaseUpToMark
    /// </summary>
    public void Mark()
    {
        mark = comObjects.Count;
    }

    /// <summary>
    /// Release up to mark
    /// </summary>
    /// <returns>Number of released objects</returns>
    public int ReleaseUpToMark()
    {
        int numberObjects = comObjects.Count - mark;
        if (numberObjects > 0)
        {
            Release(numberObjects);
            return numberObjects;
        }
        else
        {
            return 0;
        }
    }

    /// <summary>
    /// Release all the objects in the stack
    /// </summary>
    public void ReleaseAll()
    {
        if (comObjects != null)
            Release(comObjects.Count);
    }

    /// <summary>
    /// Release the last numberObjects objects in stack
    /// </summary>
    /// <param name="numberObjects">Number of objects to release</param>
    private void Release(int numberObjects)
    {
        for (int j = 0; j < numberObjects; j++)
        {
            object obj = comObjects.Pop();
            int i = 1;
            do
            {
                i = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            }
            while (i > 0);
            obj = null;
        }
    }
}

}

于 2012-11-13T10:31:43.430 に答える