3

I have an instance of Microsoft.Office.Interop.Excel.Application. In order to ensure that the EXCEL.EXE process dies in time I need to find the ProcessID that was instantiated when I created the Application object.

I found samples for this when the Excel Application has a window.

Is there a way to do that for a "hidden" instance i.e. when there is no window bound to the EXCEL.EXE process i.e. when excelApp.Hwnd is not set?

Community
  • 1
  • 1
Zverev Evgeniy
  • 3,643
  • 25
  • 42
  • 1
    From where do you get the `Microsoft.Office.Interop.Excel.Application`? – NineBerry Jun 05 '16 at 01:47
  • I create the instance of `Microsoft.Office.Interop.Excel.Application` in my code and it is used by my code. I need to avoid orphaned `EXCEL.EXE` after I dispose of it. Most of the time this is not a problem as I use all the known strategies to correctly release all the COM references. This is not enough though. I need an alarm technique which will let me know if I failed. – Zverev Evgeniy Jun 05 '16 at 11:54
  • I have never seen a case that the Hwnd of the Excel.Application is not set. Can you show some sample code how you produce an Excel.Application without Hwnd being set? – NineBerry Jun 05 '16 at 12:29
  • Not being able to find out what process implements an interface is foundational bedrock in COM. One scary scenario is what you are going to do next, assuming you *can* get the PID. Process.Kill() is a really, *really* bad idea on an Office program. You'll trigger the auto-recovery code when you start it again, never something you want to have happen in an interop scenario. Fix the real problem, don't attack the symptom. A trivial one, GC.Collect + GC.WaitForPendingFinalizers is always good enough. You just have to put it in the right place. – Hans Passant Jun 05 '16 at 13:43
  • @HansPassant Who said I am going to kill the orphaned process? Did I say that? Do not judge others using yourself as a standard. I need the answer to `DETECT` orphaned process and build an alert saying: "there is a problem in need for attention". – Zverev Evgeniy Jun 06 '16 at 09:36
  • Hmya, nice save, but what do you expect your user to do with this information? Task Manager does not make it better. Just fix the bug. – Hans Passant Jun 06 '16 at 09:41
  • @HansPassant What user? I am speaking of server code. Unattended. The "so-called user" is the problem log. The server receives excel files via WCF upload and dumps them into a directory. A windows service handles the files in a queue. Excel files` structure changes over time. Code changes over time. I need a way of monitoring that would give an alarm that some recent change led to a problem. There are about 15 active `EXCEL.EXE` processes working normally. There is a log of PIDs that should die "soon". There is an agent watching the log and it needs a binding between the PIDs and excel apps. – Zverev Evgeniy Jun 06 '16 at 09:49
  • Oh dear. Such a scenario requires a completely different approach, not particularly difficult to implement. Put this essential info your question so you can get an answer that will actually help you. – Hans Passant Jun 06 '16 at 10:10
  • @HansPassant SO is not the place for software architecture discussions. Your qualification of the scenario as being in need for a "completely different approach" is questionable. I needed a piece of technical advice and I got one. Please, be constructive. SO is good because it is a place where one could find a constructive technical answer and use it for some scenario totally different from the one was discussed in the original question. This is why I try not to bring it all up here i.e. leave the architecture mess behind. – Zverev Evgeniy Jun 06 '16 at 12:13

1 Answers1

4

Application.Hwnd has a valid window handle that you can use to get the process for the associated Excel application even when the application has no visible workbook window.

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

Process GetExcelProcess(Microsoft.Office.Interop.Excel.Application excelApp)
{
     int id;
     GetWindowThreadProcessId(excelApp.Hwnd, out id);
     return Process.GetProcessById(id);
}

void TerminateExcelProcess(Microsoft.Office.Interop.Excel.Application excelApp)
{
     var process = GetExcelProcess(excelApp);
     if (process != null)
     {
          process.Kill();
     }
}

private void button1_Click(object sender, EventArgs e)
{
     // Create Instance of Excel
     Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
     try
     {
          // Work with oXL
     }
     finally
     {
          TerminateExcelProcess(oXL);
     }
}

Note: This question has some answers that explain why the Excel process will not terminate when you are finished working with it from C# via automation (unless you are very pedantic about making sure you release every reference to any object you use explicitly).

Community
  • 1
  • 1
NineBerry
  • 26,306
  • 3
  • 62
  • 93
  • Do you mean that it's true event for excel instances created from ASP.NET w3wp process and non interactive sessions (session-0) like a windows service process? – Zverev Evgeniy Jun 05 '16 at 12:57
  • Yes. As long as you can successfully create the Automation object, it will have a valid window handle. – NineBerry Jun 05 '16 at 13:05
  • Thanks for the good news. I am going to take my time testing that and will accept the answer on success. – Zverev Evgeniy Jun 06 '16 at 09:38