2011-12-29 18 views
6

tôi là tạo ra một thể hiện mới của Word bằng cách sử dụng văn phòng interop bằng cách làm này:Nhận xử lý cửa sổ cụ thể sử dụng Office interop

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

tôi có thể nhận được một cửa sổ xử lý như thế này:

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

Vấn đề là mã hoạt động trên giả định rằng không có trường hợp nào khác của Word đang chạy. Nếu có nhiều, nó không thể đảm bảo rằng xử lý nó trả về là cho trường hợp mà tôi đã khởi chạy. Tôi đã thử sử dụng GetForegroundWindow sau khi phát hiện một sự kiện WindowActivate từ đối tượng của tôi nhưng điều này là tất cả chạy trong một ứng dụng WPF được thiết lập để chạy như cửa sổ trên cùng, vì vậy tôi chỉ nhận được xử lý cửa sổ WPF. Có cách nào khác để có được xử lý cho trường hợp của tôi từ?

+0

Vâng, không làm điều đó. Bất cứ điều gì bạn muốn làm với xử lý đó, chắc chắn có một cách tốt hơn. –

+0

Từ năm 2013 trở đi có thuộc tính Application.Hwnd – Jbjstam

Trả lời

6

Không chắc chắn lý do tại sao bạn cần xử lý đối với Word, nhưng một cách tôi đã thực hiện điều này trước đây là thực sự thay đổi chú thích cửa sổ Word và tìm kiếm nó. Tôi đã làm điều này bởi vì tôi muốn lưu trữ ứng dụng Word bên trong một điều khiển, nhưng đó là một câu chuyện khác. :)

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()); 
    } 
    } 

Khi bạn có tay cầm, bạn có thể khôi phục chú thích nếu muốn.

+0

Vâng, tại sao tôi cần làm điều này cũng là một câu chuyện khác. Nhưng tôi nghĩ rằng đề xuất của bạn không chỉ giúp tôi có được nơi mà tôi sẽ thực sự làm cho toàn bộ trải nghiệm của tôi trở nên đẹp hơn một chút với chú thích tùy chỉnh. – HotN

+1

Đồng ý với Eddie Paz nhưng với một thay đổi: bạn sẽ kiểm tra xem liệu (p.MainWindowTitle.Contains ("My Word")) bởi vì từ thêm một số chữ cái khác vào startnig của điều đó. –

1

Bạn đã nhận được danh sách tất cả các quy trình Word. Bạn có thể lặp qua danh sách này, lấy ID cha của mỗi tiến trình và khớp với quy trình hiện tại tức là ứng dụng của riêng bạn đã tạo một cá thể Word. Đây là những gì tôi có trong đầu:

IntPtr getChildProcess(string childProcessName) 
{ 
    var currentProcess = Process.GetCurrentProcess(); 

    var wordProcesses = Process.GetProcessesByName(childProcessName); 
    foreach (var childProcess in wordProcesses) 
    { 
     var parentProcess = ProcessExtensions.Parent(childProcess); 
     if (currentProcess.Id == parentProcess.Id) 
      return currentProcess.Handle; 
    } 

    return IntPtr.Zero; 
} 

Lớp ProcessExtensions có sẵn trong this excellent response cho bài đăng trước đó. Tôi đã sử dụng lớp này trong mã của riêng mình và không có khiếu nại.

+0

FYI câu hỏi được liên kết có câu trả lời khác dường như là một lựa chọn tốt hơn so với ProcessExtensions. – Chris

1

Tôi sẽ để lại câu trả lời tôi đã chọn là chính xác, vì đó là những gì tôi tìm thấy để làm việc trở lại khi tôi đã viết này. Tôi đã kể từ khi cần phải làm một cái gì đó tương tự cho một dự án khác nhau và thấy rằng cố gắng để cập nhật các chú thích ứng dụng dường như là ít đáng tin cậy (Office 2013 so với năm 2010? Ai biết ...). Đây là giải pháp mới mà tôi đã đưa ra để giữ nguyên chú thích cửa sổ.

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; 

Điều này sử dụng trình so sánh tùy chỉnh sau để đảm bảo quá trình khớp (tìm thấy 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(); 
    } 
} 
0

answer này giải thích làm thế nào để có được các đối tượng Word.Application từ một hwnd, có nghĩa là chúng ta lặp qua tất cả các quá trình từ hoạt động và có thể kiểm tra nếu Word.Application của họ phù hợp với đối tượng Word.Application của chúng ta. Bằng cách này, bạn không cần phải làm bất cứ điều gì với chú thích cửa sổ.

Xin lưu ý rằng bạn chỉ có thể có được quá trình của một Word.Application đó là nhìn thấy và có một hoặc nhiều tài liệu mở (mã mở một tài liệu trống tạm thời trong trường hợp sau):

using System; 
using System.Linq; 
using System.Text; 
using Word = NetOffice.WordApi; 
using System.Runtime.InteropServices; 
using System.Reflection; 
using System.Diagnostics; 

namespace WordHwnd 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (var app = new Word.Application() { Visible = true }) 
      { 
       Console.WriteLine(WordGetter.GetProcess(app).MainWindowHandle); 
      } 

      Console.ReadLine(); 
     } 
    } 

    class WordGetter 
    { 
     [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")] 
     private interface IDispatch 
     { 
     } 

     private const uint OBJID_NATIVEOM = 0xFFFFFFF0; 
     private static Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); 

     [DllImport("Oleacc.dll")] 
     private static extern int AccessibleObjectFromWindow(int hwnd, uint dwObjectID, byte[] riid, out IDispatch ptr); 

     private delegate bool EnumChildCallback(int hwnd, ref int lParam); 

     [DllImport("User32.dll")] 
     private static extern bool EnumChildWindows(int hWndParent, EnumChildCallback lpEnumFunc, ref int lParam); 

     [DllImport("User32.dll")] 
     private static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount); 

     private static bool Find_WwG(int hwndChild, ref int lParam) 
     { 
      if (GetClassName(hwndChild) == "_WwG") 
      { 
       lParam = hwndChild; 
       return false; 
      } 
      return true; 
     } 

     private static string GetClassName(int hwndChild) 
     { 
      var buf = new StringBuilder(128); 
      GetClassName(hwndChild, buf, 128); 
      return buf.ToString(); 
     } 

     public static Process GetProcess(Word.Application app) 
     { 
      Word.Document tempDoc = null; 

      //This only works if there is a document open 
      if (app.Documents.Count == 0) 
       tempDoc = app.Documents.Add(); 

      var processes = Process.GetProcessesByName("WINWORD"); 

      var appsAndProcesses = processes 
       .Select(p => new { Process = p, App = WordGetter.GetWordApp(p) }) 
       .Where(x => !Equals(x.App, null)); 

      Process process = null; 

      foreach (var appAndProcess in appsAndProcesses) 
      { 
       if (appAndProcess.App == app) 
       { 
        process = appAndProcess.Process; 
        break; 
       } 
       else 
       { 
        appAndProcess.App.Dispose(); 
       } 
      } 

      tempDoc?.Close(false); 

      return process; 
     } 

     public static Word.Application GetWordApp(Process process) 
     { 
      return GetWordApp(process.MainWindowHandle); 
     } 

     public static Word.Application GetWordApp(IntPtr hwnd) 
     { 
      return GetWordApp((int)hwnd); 
     } 

     public static Word.Application GetWordApp(int hwnd) 
     { 
      var wwG_Hwnd = 0; 

      var callback = new EnumChildCallback(Find_WwG); 

      EnumChildWindows(hwnd, callback, ref wwG_Hwnd); 

      if (wwG_Hwnd != 0) 
      { 
       IDispatch iDispatch; 

       var result = AccessibleObjectFromWindow(wwG_Hwnd, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), out iDispatch); 

       if (result >= 0) 
       { 
        var obj = iDispatch.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, iDispatch, null); 

        return new Word.Application(null, obj); 
       } 

       return null; 
      } 

      return null; 
     } 
    } 
} 

tôi sử dụng NetOffice trong ví dụ này, nhưng bạn có thể dễ dàng thay đổi nó để làm việc với các thư viện interop tiêu chuẩn bằng cách chỉnh sửa câu lệnh using và làm Marshal.ReleaseComObject() thay vì Word.Application.Dispose().

0

phương pháp khác, cách sử dụng thực tế là tiêm macro được chạy trực tiếp trong quá trình WINWORD:

using System; 
using Word = NetOffice.WordApi; 
using System.Diagnostics; 

namespace WordHwnd 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (var app = new Word.Application() { Visible = true }) 
      { 
       var process = GetProcess(app); 
       Console.WriteLine(process.MainWindowHandle); 

       app.Quit(); 

      } 

      Console.ReadLine(); 
     } 

     private static Process GetProcess(Word.Application app) 
     { 
      var tempDocument = app.Documents.Add(); 
      var project = tempDocument.VBProject; 
      var component = project.VBComponents.Add(NetOffice.VBIDEApi.Enums.vbext_ComponentType.vbext_ct_StdModule); 
      var codeModule = component.CodeModule; 
      codeModule.AddFromString("#If Win64 Then\r\n Declare PtrSafe Function GetCurrentProcessId Lib \"kernel32\"() As Long\r\n#Else\r\n Declare Function GetCurrentProcessId Lib \"kernel32\"() As Long\r\n#End If"); 

      var result = app.Run("GetCurrentProcessId"); 

      var process = Process.GetProcessById((int)result); 

      tempDocument.Close(false); 

      return process; 
     } 
    } 

}