C# 从 MS-Word ApplicationClass 获取 PID?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/814936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:15:25  来源:igfitidea点击:

Get PID from MS-Word ApplicationClass?

c#ms-wordpid

提问by Ricardo

Consider this code:

考虑这个代码:

using Microsoft.Office.Interop.Word;

ApplicationClass _application = new ApplicationClass();

Can I get the PID from the Winword.exe process that was launched by the _application?

我可以从 _application 启动的 Winword.exe 进程中获取 PID 吗?

I need the PID because with corrupted files, I just can't quit the ApplicationClass, even using this code:

我需要 PID,因为对于损坏的文件,即使使用以下代码,我也无法退出 ApplicationClass:

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

I can't search for the winword.exe process and kill it, because I will have several, and I don't know which one to kill. If I can get a PID for each ApplicationClass, I could just kill the correct winword.exe process that is giving me troubles to quit.

找不到winword.exe进程杀掉,因为我会有好几个,不知道杀哪一个。如果我可以为每个 ApplicationClass 获得一个 PID,我就可以杀死正确的 winword.exe 进程,该进程给我带来了退出的麻烦。

采纳答案by Mnyikka

Here is how to do it.

这是如何做到的。

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

回答by JaredPar

No, unfortunately there is no way to associate an instance of ApplicationClass with a running process of Word.

不,不幸的是,无法将 ApplicationClass 的实例与正在运行的 Word 进程相关联。

Why do you need to kill the instance of Word? Couldn't you just ask it to close all of its documents and then simply stop using that instance? If you remove all references to the class eventually the GCwill kick in and take down the COMserver.

为什么需要杀掉Word的实例?难道您不能只要求它关闭所有文档,然后就停止使用该实例吗?如果您删除对类的所有引用,最终GC将启动并关闭COM服务器。

回答by Joshua

The usual way to get it is to change Word's title to something unique and hop through the top-level window list until you find it (EnumWindows).

获取它的常用方法是将 Word 的标题更改为唯一的内容,然后在顶级窗口列表中跳转,直到找到它 (EnumWindows)。

回答by Joshua

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

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

回答by Edwin Tai

There may be some error in the Word file. As a result, when you open the file with the method Word.ApplicationClass.Documents.Open(), there will be a dialog shown and the process will hang.

Word 文件中可能存在一些错误。结果,当您使用方法打开文件时Word.ApplicationClass.Documents.Open(),将显示一个对话框,并且进程将挂起。

Use Word.ApplicationClass.Documents.OpenNoRepairDialog()instead. I found it fixed the problem.

使用Word.ApplicationClass.Documents.OpenNoRepairDialog()来代替。我发现它解决了问题。

回答by Bj?rn Lindqvist

Before you start your application, list all running Word processes, start your application, and list running Word processes again. The process found in the second list and not found in the first one is the right one:

在启动应用程序之前,列出所有正在运行的 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];

The method has obvious timing issues, but it is the only one I've found which works reliably most of the time.

该方法存在明显的计时问题,但它是我发现的唯一一种在大多数情况下都能可靠工作的方法。

回答by Bing

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

回答by Vanda Ros

Finally, I figure out the way to solved File in Use lock by user 'name' while word document not open by user but our program will produce blank title in background processes, we can kill those dummy WINWORD on background as well.

最后,我找到了解决用户'name'锁定正在使用的文件的方法,而用户没有打开word文档,但我们的程序会在后台进程中产生空白标题,我们也可以在后台杀死那些虚拟的WINWORD。

enter image description here

在此处输入图片说明

enter image description here

在此处输入图片说明

By this code we no need to use ReleaseComObject(_application)I really don't know this is a good idea because when I re-open that file first release can't see any content of document at least need to close and open again.

通过这段代码,我们不需要使用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();
            }
        }
    }