2009-05-02 94 views
13

考慮以下代碼:從MS-Word ApplicationClass獲取PID?

using Microsoft.Office.Interop.Word; 

ApplicationClass _application = new ApplicationClass(); 

我可以從由_Application推出Winword.exe進程的PID?

我需要的PID因爲損壞的文件,我不能退出ApplicationClass,甚至使用此代碼:

_application.Quit(ref saveFile, ref missing, ref missing); 
System.Runtime.InteropServices.Marshal.ReleaseComObject(_application); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 

我不能搜索Winword.exe進程,並殺死它,因爲我會有幾個,我不知道要殺哪一個。如果我可以爲每個ApplicationClass獲取一個PID,那麼我可以殺死正在給我麻煩退出的正確的winword.exe進程。

回答

5

以下是如何做到這一點。

//Set the AppId 
string AppId = ""+DateTime.Now.Ticks(); //A random title 

//Create an identity for the app 

this.oWordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); 
this.oWordApp.Application.Caption = AppId; 
this.oWordApp.Application.Visible = true; 

///Get the pid by for word application 
this.WordPid = StaticMethods.GetProcessIdByWindowTitle(AppId); 

while (StaticMethods.GetProcessIdByWindowTitle(AppId) == Int32.MaxValue) //Loop till u get 
{ 
    Thread.Sleep(5); 
} 

this.WordPid = StaticMethods.GetProcessIdByWindowTitle(AppId); 


///You canh hide the application afterward    
this.oWordApp.Application.Visible = false; 

string this.oWordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); 
this.oWordApp.Application.Caption = AppId; 
this.oWordApp.Application.Visible = true; 
///Get the pid by 
this.WordPid = StaticMethods.GetProcessIdByWindowTitle(AppId); 

while (StaticMethods.GetProcessIdByWindowTitle(AppId) == Int32.MaxValue) 
{ 
    Thread.Sleep(5); 
} 

this.WordPid = StaticMethods.GetProcessIdByWindowTitle(AppId); 

this.oWordApp.Application.Visible = false; //You Can hide the application now 

/// <summary> 
/// Returns the name of that process given by that title 
/// </summary> 
/// <param name="AppId">Int32MaxValue returned if it cant be found.</param> 
/// <returns></returns> 
public static int GetProcessIdByWindowTitle(string AppId) 
{ 
    Process[] P_CESSES = Process.GetProcesses(); 
    for (int p_count = 0; p_count < P_CESSES.Length; p_count++) 
    { 
     if (P_CESSES[p_count].MainWindowTitle.Equals(AppId)) 
     { 
        return P_CESSES[p_count].Id; 
     } 
    } 

    return Int32.MaxValue; 
} 
+2

@Mmyikka你可以發佈`StaticMethods`類嗎? – BrunoLM 2011-11-25 18:27:45

+3

我試過這個,但我所有的文字處理MainWindowTitle都是空的,並將標題設置爲一個字符串似乎沒有影響,我錯過了什麼? – Arvand 2013-09-25 12:58:24

1

不,很遺憾,沒有辦法將ApplicationClass的實例與正在運行的Word進行關聯。

爲什麼你需要殺死Word的實例?你不能只是要求它關閉所有文件,然後停止使用該實例嗎?如果您最終刪除了該類的所有引用,則GC將啓動並取下COM服務器。

+3

我只是不能關閉文件,因爲它尚未打開。 文檔已損壞,因此出現窗口對話框等待人工干預。但是,我在服務中使用代碼,並且打開了數千個文檔,並且不可能進行人爲干預。 我調查了一下,Excel ApplicationClass有一個Hwnd。與: [DllImport(「user32.dll」)] static extern int GetWindowThreadProcessId(int hWnd,out int lpdwProcessId); 我可以得到PID。 但Word應用程序類沒有一個Hwnd ...真是太遺憾了...... – Ricardo 2009-05-02 15:40:53

2

得到它的通常方法是將Word的標題更改爲獨特的東西,並跳過頂層窗口列表直到找到它(EnumWindows)。

2

http://www.codekeep.net/snippets/7835116d-b254-466e-ae66-666e4fa3ea5e.aspx

///Return Type: DWORD->unsigned int 
///hWnd: HWND->HWND__* 
///lpdwProcessId: LPDWORD->DWORD* 
[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")] 
public static extern int GetWindowThreadProcessId ([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd, out int lpdwProcessId); 


private int _ExcelPID = 0; 
Process _ExcelProcess; 

private Application _ExcelApp = new ApplicationClass(); 
GetWindowThreadProcessId(new IntPtr(_ExcelApp.Hwnd), out _ExcelPID); 
_ExcelProcess = System.Diagnostics.Process.GetProcessById(_ExcelPID); 

... 

_ExcelProcess.Kill(); 
+0

只有excel.ApplicationClass類是Hwnd屬性,而不是問題所在的word.ApplicationClass類。 – 2014-02-07 09:34:32

2

有可能是在Word文件的一些錯誤。因此,當您使用方法Word.ApplicationClass.Documents.Open()打開文件時,將顯示一個對話框並且該過程將掛起。

改爲使用Word.ApplicationClass.Documents.OpenNoRepairDialog()。我發現它解決了這個問題。

1

在你開始你的應用程序,列出所有運行Word程序,啓動應用程序,並再次列表運行Word進程。在第二個列表中找到,並在第一個未發現的過程是正確的:

var oPL1 = from proc in Process.GetProcessesByName("WINWORD") select proc.Id; 
var app = new Word.Application(); 

var oPL2 = from proc in Process.GetProcessesByName("WINWORD") select proc.Id; 
var pid = (from p in oPL2 where !oPL1.Contains(p) select p).ToList()[0]; 

的方法具有明顯的時序問題,但它是唯一一個我發現這工作的大部分時間可靠。