Получить PID из MS-Word ApplicationClass? - PullRequest
14 голосов
/ 02 мая 2009

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

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, который доставляет мне проблемы при выходе.

Ответы [ 7 ]

7 голосов
/ 01 июля 2011

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

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

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

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

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

/// <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;
}
3 голосов
/ 03 августа 2010

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

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

2 голосов
/ 08 сентября 2009

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();
2 голосов
/ 02 мая 2009

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

1 голос
/ 07 февраля 2014

Перед запуском приложения перечислите все запущенные процессы 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];

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

1 голос
/ 02 мая 2009

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

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

0 голосов
/ 22 апреля 2019
enter code here  public void OpenWord(string Path, bool IsVisible)
    {

        MessageFilter.Register();
        object oMissing = Missing.Value;
        GUIDCaption = Guid.NewGuid().ToString();
        wordApp = new Microsoft.Office.Interop.Word.ApplicationClass();
        wordApp.Visible = IsVisible;
        wordApp.Caption = GUIDCaption;
        object oPath = Path;
        wordDoc = wordApp.Documents.Open(ref  oPath, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);

    }
    /// <summary>
    /// 关闭文件
    /// </summary>
    public void CloseWord()
    {
        object oMissing = Missing.Value;
        GUIDCaption = "";
        if (null != wordDoc)
        {
            wordDoc.Close(ref oMissing, ref oMissing, ref oMissing);
        }
        if (null != wordApp)
        {
            wordApp.Quit(ref oMissing, ref oMissing, ref oMissing);
        }
        MessageFilter.Revoke();
        GC.Collect();
        KillwordProcess();

    }
    /// <summary>
    /// 结束word进程
    /// </summary>
    public void KillwordProcess()
    {
        try
        {
            Process[] myProcesses;
            //DateTime startTime;
            myProcesses = Process.GetProcessesByName("WINWORD");

            //通过进程窗口标题判断
            foreach (Process myProcess in myProcesses)
            {
                if (null != GUIDCaption && GUIDCaption.Length > 0 && myProcess.MainWindowTitle.Equals(GUIDCaption))
                {
                    myProcess.Kill();
                }
            }
            MessageFilter.Revoke();
        }
        catch (Exception e)
        {
            throw e;
        }
    }
...