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


person Ricardo    schedule 02.05.2009    source источник


Ответы (9)


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

//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;
}
person Mnyikka    schedule 01.07.2011
comment
@Mmyikka, можешь опубликовать StaticMethods класс? - person BrunoLM; 25.11.2011
comment
Я пробовал это, но все мои текстовые процессы MainWindowTitle пусты, и установка заголовка на строку, похоже, не имеет эффекта. Я что-то упустил? - person Arvand; 25.09.2013

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

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

person Edwin Tai    schedule 03.08.2010

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

person Joshua    schedule 02.05.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();
person Community    schedule 08.09.2009
comment
Только класс excel.ApplicationClass является свойством Hwnd, а не классом word.ApplicationClass, о котором идет речь. - person Björn Lindqvist; 07.02.2014

Наконец, я выяснил, как решить блокировку файла в использовании по имени пользователя, в то время как текстовый документ не открывается пользователем, но наша программа будет создавать пустой заголовок в фоновых процессах, мы также можем убить эти фиктивные WINWORD в фоновом режиме.

введите здесь описание изображения

введите здесь описание изображения

В этом коде нам не нужно использовать ReleaseComObject(_application). Я действительно не знаю, что это хорошая идея, потому что, когда я снова открываю этот файл, первый выпуск не может видеть содержимое документа, по крайней мере нужно закрыть и снова открыть.

    public static void KillProcessBlankMainTitle(string name) // WINWORD
    {
        foreach (Process clsProcess in Process.GetProcesses())
        {

            if (Process.GetCurrentProcess().Id == clsProcess.Id)
                continue;
            if (clsProcess.ProcessName.Equals(name))
            {
                if(clsProcess.MainWindowTitle.Equals(""))
                    clsProcess.Kill();
            }
        }
    }
person Vanda Ros    schedule 18.03.2020

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

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

person JaredPar    schedule 02.05.2009
comment
Я просто не могу закрыть документ, потому что он еще не открыт. Документ поврежден, поэтому появляется диалоговое окно, ожидающее вмешательства человека. Однако я использую код в сервисе и открываю тысячи текстовых документов, и вмешательство человека невозможно. Я исследую немного больше, и Excel ApplicationClass имеет Hwnd. С: [DllImport (user32.dll)] static extern int GetWindowThreadProcessId (int hWnd, out int lpdwProcessId); Я могу получить PID. Но Word ApplicationClass не имеет Hwnd... Какой позор... - person Ricardo; 02.05.2009

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

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

person Björn Lindqvist    schedule 07.02.2014
comment
это не может быть ответом, потому что нет гарантии, что только ваше приложение открывает процессы winword! - person Arvand; 14.06.2014

И на нашу улицу пришел праздник! Сколько крови Слово выпило из меня...

Какие есть способы получить PID:

  1. Получить список процессов, запустить WORD, получить список процессов, среди которых будет нужный процесс. Недостаток, если многопоточность, это будет большая проблема!!!
  2. Через установку уникальное имя для окна. Мистер Бинг принес с Гидом хорошую идею. Недостатком является особенность ОС Windows, если окно, сгенерированное процессом, не имеет свойства отображения, процесс теряет атрибут Заголовок и оно будет пустым. То есть всегда должно быть либо wordApp.Visible = true. Либо мы делаем правду, совершаем магию, а затем снова ложь.
  3. Получить Hwnd можно через окно открытого документа! Как было предложено в одном из сообщений https://stackoverflow.com/a/59146157/4143902 Недостаток в том, что вам нужно чтобы на мгновение создать невидимое окно документа и получить Hwnd, закрыть его и продолжить работу. Лучший вариант.

Пример:

// Setting up the environment
app.Visible = false;
app.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
app.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable;
app.ScreenUpdating = false;

// The interface is a collection of documents
Word.Documents docs = app.Documents;

// Getting the window handle
Word.Document trashDoc = docs.Add();
Word.Window wind = trashDoc.ActiveWindow;
// Converting the handle to the process id
int intProcId;
GetWindowThreadProcessId(wind.Hwnd, out intProcId);
// If we want multithreading, we store the dictionary task - >window id
lock (objWorkThreadLock)
{
    if (dictThread.ContainsKey(idTask)) dictThread[idTask] = intProcId;
}
trashDoc.Saved = true;
trashDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges, Type.Missing, Type.Missing);
if (trashDoc != null) Marshal.ReleaseComObject(trashDoc);
if (wind != null) Marshal.ReleaseComObject(trashDoc);

// Work further
Word.Document doc = null;
doc = docs.OpenNoRepairDialog( ... )

...

[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

public void Killing(int intProcId)
{
    if (intProcId != 0)
    {
        try
        {
            Process proc = Process.GetProcessById(intProcId);
            proc.Kill();
        }
        catch (Exception ex)
        {
        }
    }
}
person KUL    schedule 31.07.2020

person    schedule
comment
Изменено на OpenNoRepairDialog, как это, MainWindowTitle все еще пусто? какова ситуация - person Bing; 22.04.2019
comment
GUIDCaption = ; Этот баг не имеет значения - person Bing; 22.04.2019