[英]Get PID from MS-Word ApplicationClass?
考虑这个代码:
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 进程,它给我带来了退出的麻烦。
这是如何做到的。
//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;
}
Word 文件中可能存在一些错误。 因此,当您使用Word.ApplicationClass.Documents.Open()
方法打开文件时,将显示一个对话框并且进程将挂起。
请改用Word.ApplicationClass.Documents.OpenNoRepairDialog()
。 我发现它解决了问题。
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();
最后,我找到了解决用户'name'锁定正在使用的文件的方法,而用户没有打开word文档,但我们的程序会在后台进程中产生空白标题,我们也可以在后台杀死那些虚拟的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();
}
}
}
获取它的常用方法是将 Word 的标题更改为唯一的内容,然后在顶级窗口列表中跳转,直到找到它 (EnumWindows)。
在启动应用程序之前,列出所有正在运行的 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];
该方法存在明显的计时问题,但它是我发现的唯一一种在大多数情况下都能可靠工作的方法。
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;
}
}
在我们的街道上放假了! “字”从我这里喝了多少血……
获取PID的方法有哪些:
例子:
// 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)
{
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.