Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get specific window handle using Office interop

I'm creating a new instance of Word using the Office interop by doing this:

var word = Microsoft.Office.Interop.Word.Application();
word.Visible = true;
word.Activate;

I can get a window handle like this:

var wordHandle = Process.GetProcessesByName("winword")[0].MainWindowHandle;

The problem is that code works on the assumption that there's no other instance of Word running. If there are multiple, it can't guarantee that the handle it returns is for the instance that I've launched. I've tried using GetForegroundWindow after detecting a WindowActivate event from my object but this is all running within a WPF application that's set to run as the topmost window, so I just get the handle to the WPF window. Are there any other ways to get the handle for my instance of word?

like image 242
HotN Avatar asked Dec 29 '11 21:12

HotN


2 Answers

Not sure why you need the handle to Word, but one way I've done this before is to actually change the Word window caption and search for it. I did this because I wanted to host the Word application inside a control, but that's another story. :)

  var word = new Microsoft.Office.Interop.Word.Application(); 
  word.Visible = true; 
  word.Activate();
  word.Application.Caption = "My Word";

  foreach( Process p in Process.GetProcessesByName( "winword" ) )
  {
    if( p.MainWindowTitle == "My Word" )
    {
      Debug.WriteLine( p.Handle.ToString() );
    }
  }

Once you got the handle, you can restore the caption if you like.

like image 192
Eddie Paz Avatar answered Nov 15 '22 03:11

Eddie Paz


I'll leave the answer I've selected as correct, since it was what I found to work back when I wrote this. I've since needed to do do something similar for a different project and found that trying to update the application caption seemed to be less reliable (Office 2013 vs. 2010? Who knows...). Here's the new solution I've come up with that leaves window captions intact.

var startingProcesses = Process.GetProcessesByName("winword").ToList();

var word = new Microsoft.Office.Interop.Word.Application(); 

var allProcesses = Process.GetProcessesByName("winword").ToList();

var processDiff = allProcesses.Except(startingProcesses, new ProcessComparer());

var handle = processDiff.First().MainWindowHandle;

This uses the following custom comparer to ensure the processes match (found here).

class ProcessComparer : IEqualityComparer<Process>
{
    public bool Equals(Process x, Process y)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }

        if (x == null || y == null)
        {
            return false;
        }

        return x.Id.Equals(y.Id);
    }

    public int GetHashCode(Process obj)
    {
        return obj.Id.GetHashCode();
    }
}
like image 3
HotN Avatar answered Nov 15 '22 03:11

HotN