您可以枚举所有的Word窗口,并尝试找到其中包含该文档的窗口。同时,如果您在Word中打开该文件时尝试打开它,将会出现IOException异常。但这并不是完美的解决方案 :(
以下是解决方案:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace WordExampleApp
{
class Program
{
const int ERROR_SHARING_VIOLATION = -2147024864;
static readonly string WORD_CLASS_NAME = "OpusApp";
static readonly string WORD_DOCUMENT_CLASS_NAME = "_WwB";
delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
static void Main(string[] args)
{
string filePath = @"C:\temp\asdasd.docx";
string documentName = Path.GetFileNameWithoutExtension(filePath);
var isDocOpened = IsDocumentOpened(documentName);
Console.WriteLine("Is document opened: {0}", isDocOpened);
bool canRead = CanReadFile(filePath);
Console.WriteLine("Can read file: {0}", canRead);
}
private static bool CanReadFile(string path)
{
try {
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None)) { }
return true;
}
catch (IOException ex) {
if (ex.HResult == ERROR_SHARING_VIOLATION)
return false;
else throw;
}
}
private static bool IsDocumentOpened(string documentName)
{
IntPtr hwnd = FindWindow(WORD_CLASS_NAME, documentName + " - Word");
List<IntPtr> childs = GetChildWindows(hwnd);
var classText = new StringBuilder("", 1024);
var windowText = new StringBuilder("", 1024);
foreach (var childHwnd in childs)
{
if (0 == GetClassName(childHwnd, classText, 1024)) {
}
if (0 == GetWindowText(childHwnd, windowText, 1024)) {
}
var className = classText.ToString();
var windowName = windowText.ToString();
if (className == WORD_DOCUMENT_CLASS_NAME && windowName == documentName)
return true;
classText.Clear();
windowText.Clear();
}
return false;
}
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle gcHandle = GCHandle.Alloc(result);
try {
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(gcHandle));
}
finally {
if (gcHandle.IsAllocated)
gcHandle.Free();
}
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
list.Add(handle);
return true;
}
[DllImport("user32", ExactSpelling = false, CharSet = CharSet.Auto)]
internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
}
}
Quit()
方法后仍将继续运行而不会出现窗口。与其检查文档是否已打开,您应该确保首先正确处理Word的处理。尝试此线程,这很可能是发生的情况。 - NikProcess.GetProcesses()
,然后通过名称查找所有的Word
进程,最后调用process.Kill()
来结束它们。但是如果 Word 有窗口(即用户正在使用它),你不想结束它,所以要检查if(process.MainWindowHandle == (IntPtr)0)
,如果为真,则表示 Word 正在静默运行。如果需要更多解释,请告诉我。 - Nik