2012-03-19 135 views
0

我在控制台应用程序X中有一个c#方法,这启动了一个进程;控制台应用程序Y(用相同的c#解决方案编写)。 App Y然后在Excel 2010工作簿中激发vba宏。如何杀死Excel

对于在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

我读了标题,并认为这是另一个人恨微软。 – 2012-03-19 21:03:57

+0

认为标题的变化可能有助于 – whytheq 2012-03-19 21:05:09

回答

0

我离开的代码原有的位不变,但我已经用从安德鲁的帮助,但我的一个好朋友的主要帮助谁不幸的是,不注册到SO。 Excel似乎已经死了!另外,他编码的方式是,它返回一个指示器,告诉表单是否与excel有问题。同时也为我们提供了在每个Excel过程的最大运行时间内进行构建的选项。

他用以下SO answer,以帮助摆脱的Excel

1.In调度程序

  • 移动计时器有
  • 落实情况的Excel清洁代码存在VBA没有错误,在当最大执行时间达到了(使用Kill方法)
  • 从调度器返回0到表单应用程序如果Excel正常结束或1,如果它被杀死
  • 相反的情况下

2.In的形式应用从调度分析返回值在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 [email protected]"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(); 
     } 
    } 
    } 
1

它可能与报告调度的问题,它不具有关闭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(); 
    } 
} 
+1

感谢安德鲁 - 目前没有接近的代码,但我明天将开始玩这个。我的朋友也建议我上面介绍的代码是可以的,问题更可能与ReportScheduler_v3.exe和它处理xl的方式有关 – whytheq 2012-03-19 21:28:50