Как убить Excel - PullRequest
       16

Как убить Excel

0 голосов
/ 19 марта 2012

У меня есть метод c # в консольном приложении X, который запускает процесс; консольное приложение Y (написано в том же решении c #). Затем приложение Y запускает макрос vba в книге Excel 2010.

В целях тестирования в wkbook VBA я добавил некоторый код, чтобы вызвать ошибку времени выполнения 1004.

winForm использует событие процесса, вызванное с помощью таймера форм, для уничтожения процесса. Он работает так, как запрограммировано. Я просто хотел бы попытаться сделать это немного больше. Почему, когда я завершаю процесс, экземпляр XL остается открытым в тот момент, когда он находит ошибку? Как мне найти способ избавиться от экземпляра XL, если он все еще существует, когда он убивает процесс, и затем отправить сообщение об ошибке обратно в мою winForm?

(ps следующий код знаком, но вопрос не является дубликатом)

    private int elapsedTime;
    private Process p;
    private System.Windows.Forms.Timer myTimer;
    const int SLEEP_AMOUNT = 1000;//1s
    const int MAXIMUM_EXECUTION_TIME = 5000;//5s


    private void btRunReport_Click(object sender, EventArgs e) {
        btRunReport.Enabled = false;
        lbStatusUpdate.Text = "Processing..";

        //instantiate a new process and set up an event for when it exits
        p = new Process();
        p.Exited += new EventHandler(MyProcessExited);
        p.EnableRaisingEvents = true;
        p.SynchronizingObject = this;
        elapsedTime = 0;
        this.RunReportScheduler();

        //add in a forms timer so that the process can be killed after a certain amount of time
        myTimer = new System.Windows.Forms.Timer();
        myTimer.Interval = SLEEP_AMOUNT;
        myTimer.Tick += new EventHandler(TimerTickEvent);
        myTimer.Start();

    }
    private void RunReportScheduler() {
        p.StartInfo.FileName = @"\\fileserve\department$\ReportScheduler_v3.exe";
        p.StartInfo.Arguments = 2;
        p.Start();
    }
    private void MyProcessExited(Object source, EventArgs e){
        myTimer.Stop();
        btRunReport.Enabled = true;
        lbStatusUpdate.Text = "Start";
    }
    void TimerTickEvent(Object myObject, EventArgs myEventArgs) {
        myTimer.Stop();
        elapsedTime += SLEEP_AMOUNT;
        if (elapsedTime > MAXIMUM_EXECUTION_TIME)
        {p.Kill();}
        else
        {myTimer.Start();}
    }

Ответы [ 2 ]

1 голос
/ 20 марта 2012

это может быть проблема с планировщиком отчетов, у которого нет правильного метода, который закрывает Excel.

Это такой метод:

private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}
0 голосов
/ 20 марта 2012

Я оставил оригинальный фрагмент кода без изменений, но я воспользовался помощью Эндрю, но в основном помощью моего хорошего друга, который, к сожалению, не подписан на SO.Excel кажется мертвым!Кроме того, он закодировал его так, чтобы он передавал обратно индикатор, сообщающий форме, были ли у него проблемы с Excel или нет.Также дает нам возможность построить максимальное время выполнения для каждого процесса Excel.

Он использовал следующий SO ответ , чтобы помочь избавиться от Excel

1. В планировщикепрограмма

  • Переместить таймер туда
  • Реализовать код очистки excel в случае, если в vba нет ошибок, и в противоположном случае, когда достигнуто максимальное время выполнения (используйте метод Kill)
  • Из планировщика вернуть 0 в приложение форм, если Excel завершил работу нормально, или 1, если он был уничтожен

2. В приложении форм проанализировать возвращаемое значение из планировщика в обработчике событий ProcessExited и включитькнопка и т. д.

Итак, новый планировщик:

 using System;
 using System.Text;
 using System.Runtime.InteropServices;
 using System.Diagnostics;
 using Excel = Microsoft.Office.Interop.Excel;
 using System.Timers;


class Program
{
   private const int SLEEP_AMOUNT = 1000;
   private const int MAXIMUM_EXECUTION_TIME = 10000;
   private Excel.Application excelApp =null;
   private Excel.Workbook book =null;
   private Timer myTimer;
   private int elapsedTime;
   private int exitCode=0;

   [DllImport("user32.dll", SetLastError =true)]
   static extern uint GetWindowThreadProcessId(IntPtr hWnd,out uint lpdwProcessId);

   static int Main(string[] args)
    {
       Program myProgram = newProgram();
       myProgram.RunExcelReporting(1);
       return myProgram.exitCode;
    }


   void myTimer_Elapsed(object sender,ElapsedEventArgs e)
    {
       myTimer.Stop();
       elapsedTime += SLEEP_AMOUNT;
       if (elapsedTime > MAXIMUM_EXECUTION_TIME)
        {
            //error in vba or maximum time reached. abort excel and return 1 to the calling windows forms application
           GC.Collect();
           GC.WaitForPendingFinalizers();
           if (book != null)
            {
               book.Close(false,Type.Missing, Type.Missing);
               Marshal.FinalReleaseComObject(book);
               book =null;
            }

           if (excelApp != null)
            {
               int hWnd = excelApp.Hwnd;
               uint processID;
               GetWindowThreadProcessId((IntPtr)hWnd,out processID);
               if (processID != 0)
                   Process.GetProcessById((int)processID).Kill();
                excelApp =null;
                exitCode = 1;
            }
        }
       else
        {
            myTimer.Start();
        }
    }


   void RunExcelReporting(int x)
    {
        myTimer =new Timer(SLEEP_AMOUNT);
        elapsedTime = 0;
        myTimer.Elapsed +=new ElapsedEventHandler(myTimer_Elapsed);
        myTimer.Start();

       try{
            excelApp =new Excel.Application();
            excelApp.Visible =true;
            book = excelApp.Workbooks.Open(@"c:\jsauto.xlsm");
            excelApp.Run("ThisWorkbook.rr");
            book.Close(false,Type.Missing, Type.Missing);
        }
        catch (Exception ex){
           Console.WriteLine(ex.ToString());
        }

       finally
        {
           //no error in vba and maximum time is not reached. clear excel normally
           GC.Collect();
           GC.WaitForPendingFinalizers();

           if (book != null)
            {
               try {
                    book.Close(false,Type.Missing, Type.Missing);
                }
                catch { }
               Marshal.FinalReleaseComObject(book);
            }

           if (excelApp != null)
            {
               excelApp.Quit();
               Marshal.FinalReleaseComObject(excelApp);
               excelApp =null;
            }
        }
    }
}

И новое приложение форм:

public partial class Form1 : Form

{
   SqlDataAdapter myAdapt = null; 
   DataSet mySet =null; 
   DataTable myTable =null; 

   public Form1()
    { InitializeComponent();}

    privatevoid Form1_Load(object sender,EventArgs e){ 
        InitializeGridView();
    }

   private Process myProcess;

   private void btRunProcessAndRefresh_Click(object sender,EventArgs e)
    {
        myProcess =new Process();
        myProcess.StartInfo.FileName =@"c:\VS2010Projects\ConsoleApplication2\ConsoleApplication4\bin\Debug\ConsoleApplication4.exe";
        myProcess.Exited +=new EventHandler(MyProcessExited);
        myProcess.EnableRaisingEvents =true;
        myProcess.SynchronizingObject =this;
        btRunProcessAndRefresh.Enabled =false;
        myProcess.Start();
    }

    privatevoid MyProcessExited(Object source,EventArgs e)
    {
        InitializeGridView();
        btRunProcessAndRefresh.Enabled =true;
       if (((Process)source).ExitCode == 1)
        {
           MessageBox.Show("Excel was aborted");
        }
       else
        {
           MessageBox.Show("Excel finished normally");
        }
    }

   private void btnALWAYSWORKS_Click(object sender,EventArgs e) { 
        InitializeGridView();
    }

    privatevoid InitializeGridView() { 
      using (SqlConnection conn =new SqlConnection(@"Data Source=sqliom3;Integrated Security=SSPI;Initial Catalog=CCL"))
        {
        myAdapt =new SqlDataAdapter("SELECT convert(varchar(25),getdate(),120) CurrentDate", conn);
        mySet =new DataSet();
        myAdapt.Fill(mySet,"AvailableValues"); 
        myTable = mySet.Tables["AvailableValues"];

        this.dataGridViewControlTable.DataSource = myTable;
        this.dataGridViewControlTable.AllowUserToOrderColumns =true;
        this.dataGridViewControlTable.Refresh();
        }
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...