我在后台使用Word文档做了几件事,有时,如果应用程序失败,MS Word的一个实例将在后台运行。 重新启动后,它会尝试打开同一个文件,并且会出现与此相关的问题流。
我想了解(在这里找不到合适的答案)如何检查我正在尝试打开的文件是否已经打开。
我的代码:
Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
Document wordDoc = new Document();
wordDoc = wordApp.Documents.Open(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
wordApp.Visible = false;
如何在执行wordApp.Documents.Open
之前检查文件是否已打开?
谢谢!
答案 0 :(得分:3)
您可以尝试打开该文件,如果该文件已经打开IOException
将被抛出并指示该文件已打开:
public bool fileIsOpen(string path)
{
System.IO.FileStream a = null;
try
{
a = System.IO.File.Open(path,
System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.None);
return false;
}
catch (System.IO.IOException ex)
{
return true;
}
finally
{
if (a != null)
{
a.Close();
a.Dispose();
}
}
}
答案 1 :(得分:2)
您可以枚举所有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)
{
// Path to exist word document
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)) {
// something wrong
}
if (0 == GetWindowText(childHwnd, windowText, 1024)) {
// something wrong
}
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);
}
}
答案 2 :(得分:1)
有同样的问题。我的解决方案是始终将文档以ReadOnly的形式打开并进行复制。我知道问题是一种检查文档是否已打开的方法,但是如果文档以只读方式打开,则不必检查此问题:
public static MsWord.Document CopyTemplate(string Template, MsWord.Application wordApp)
{
var TemplateDoc = wordApp.Documents.Open(Template, ReadOnly: true);
TemplateDoc.Select();
wordApp.Selection.Copy();
TemplateDoc.Close(SaveChanges: false);
var NewDoc = wordApp.Documents.Add();
NewDoc.Select();
wordApp.Selection.PasteAndFormat(MsWord.WdRecoveryType.wdFormatOriginalFormatting);
return NewDoc;
}
答案 3 :(得分:0)
好吧,我认为一种简单的方法是检查当前正在运行的进程的标题:
bool isWordFileAlreadyOpened = false;
var alreadyOpenedProcessForWordFile = Process.GetProcesses().FirstOrDefault(p => p.MainWindowTitle.Contains(alreadyOpenedProcessForWordFile));
isWordFileAlreadyOpened = alreadyOpenedProcess != null;