Получить PID из MS-Word ApplicationClass?

Рассмотрим этот код:

using Microsoft.Office.Interop.Word;

ApplicationClass _application = new ApplicationClass();

Можно ли получить PID из процесса Winword.exe, который был запущен приложением _application?

Мне нужен PID, потому что с поврежденными файлами я просто не могу выйти из ApplicationClass, даже используя этот код:

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

Я не могу найти процесс winword.exe и убить его, потому что у меня будет несколько, и я не знаю, кого убить. Если я могу получить PID для каждого ApplicationClass, я мог бы просто убить правильный процесс winword.exe, который дает мне проблемы выйти.

Ответы

Ответ 1

Вот как это сделать.

//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

Обычный способ получить это - изменить название Word на что-то уникальное и перейти через список окон верхнего уровня, пока вы его не найдете (EnumWindows).

Ответ 3

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

Ответ 4

В файле Word может быть некоторая ошибка. В результате при открытии файла с помощью метода Word.ApplicationClass.Documents.Open() появится диалоговое окно, и процесс будет зависать.

Используйте Word.ApplicationClass.Documents.OpenNoRepairDialog() вместо этого. Я нашел, что исправлена ​​проблема.

Ответ 5

Нет, к сожалению, нет способа связать экземпляр ApplicationClass с запущенным процессом Word.

Зачем вам нужно убить экземпляр Word? Не могли бы вы просто попросить его закрыть все его документы, а затем просто прекратить использовать этот экземпляр? Если вы удалите все ссылки на класс, то GC запустит и снимет COM.

Ответ 6

Перед запуском приложения перечислите все запущенные процессы Word, запустите приложение и снова запустите процессы Word. Процесс, найденный во втором списке и не найденный в первом, является правильным:

var lst1 = from p in Process.GetProcessesByName("WINWORD") select p.Id;
var app = New Word.Application();
...
var lst2 = from p in Process.GetProcessesByName("WINWORD") select p.Id;
var pid = (from p in lst2 where not lst1.Contains(p.id) select p).ToList()[0];

Метод имеет очевидные проблемы с синхронизацией, но это единственный, который я нашел, который работает в большинстве случаев.