In my scenario I am opening Word documents melodramatically. If the programm opens the same document it should prompt the user that the document is already opened.
Process[] pro = Process.GetProcessesByName("WINWORD");
if (pro.Length > 0)
{
foreach (Process p in pro)
{
p.kill();
}
}
I am using the above code to find the process and killing already opened documents. The problem is that it is killing word.exe so that all the other opened documents also close.
How do I find the name of the document and close that particular document only?
I used p.MainWindowTitle to get the opened document's name but its not showing all the opened documents, rather showing the first opened document name.
What is the correct solution?
You can use File.Open method to open the file in non-sharing mode FileShare.None.
FileStream stream = null;
bool isOpen = false;
try
{
stream = File.Open(#"DFilePath&Name",FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch(IOException)
{
isOpen = true;
//Show your prompt here.
}
finally
{
if (stream != null)
stream.Close();
}
if(!isOpen)
Process.Start(#"FilePath&Name");
If the file is already open, it will throw an IOException which you can catch and show your prompt.
BTW why were you killing all the processes in the first place if all you had to do was to show a prompt?
Update
This is a general solution direction.
you need to add the reference to Microsoft.Office.Interop.Word
I think Word Interop makes you specify even the default arguments. That's tedious but it is way less tedious than getting the window title and a lot more robust, if you ask me
Use Microsoft.Office.Interop.Word:
using Microsoft.Office.Interop.Word;
class Program
{
static void Main()
{
// Open a doc file.
Application application = new Application();
Document document = application.Documents.Open("C:\\word.doc");
// Close word. if desired
// application.Quit();
}
}
I suspect word will automatically prevent opening the same document twice. If not, the Documetns interface to enumerate any currently opened documents, so you can check beforehand
Related
I need some help.
My application works with Outlook files.
For example, I have a MSG format file is stored at my PC.
Let's imagine that I haven't got any running Outlook processes on my PC.
var myProcess = new Process { ProcessInfo = new ProcessStartInfo {FileName = targetPath}}
where targetPath is full path to my file.
Then I start process:
myProcess.Start();
At this moment Outlook runs at OS. Looking into TaskManager I see this process, and it's unique PID.
And there is my first question: why this PID is different from myProcess.Id ?
Moving on. I need to check is my file still opening at Outlook. I resolve this issue by trying to open this file in my application for a certain time.
var iterations = 3600;
while (iterations > 0 ) {
Thread.Sleep(1000);
var fInfo = new FileInfo(targetPath);
FileStream stream = null;
try {
stream = fInfo.Open(FileMode.Open, FileAccess.Read | FileAccess.Write, FileShare.None);
} catch {
//I expect if exception occurs then file is not lock and can send it to server.
}
finally{
if(stream != null)
stream.Close();
}
iteration--;
}
I think, while my MSG file is using by Outlook, I my application cant open file. In that way I decide that cant save my file and send it to server. But! If I add attachment but NOT close this e-mail at Outlook, my application CAN open this file. And I don't understand why Outlook change Read/Write attribute of this file? And how I can solve this issue?
Unfortunately, I haven't any idea why it happens and how to make it work.
I was looking on any info at web that can help to solve my issue, but has no result :(
Thank you for your time.
Firstly, Outlook is a singleton - if you start a new instance of outlook.exe, it will simply switch control to the already running instance and exit.
Outlook internally caches / references open MSG files, there is really northing you can do about that.
I'm using the below method to check if a file is already in use... seems to work just fine but my problem is that if I have excel open, sometimes the filestream actually opens and leaves open the excel file that its currently checking.
Anyone know why the file is actually opening and not closing when it leaves the using statement?
EDIT: More to the above, it opens the excel file and then it display a message box telling me that the file is available to Read/Write
I put the below in the comments but I think it pertains to my usage of the IsFileLocked code and may actually be the real cause??
I'm using the IsFileLocked code along with a filewatcher. When the filewatcher goes off I check if the excel file is still in use and if its not in use then I query data back from that excel file.
Process.. 1.) Excel file has changed or is being changed by another user 2.) make sure its still not in use with the IsFileLocked method 3.) if file is no longer in use then query data back from the excel file but sometimes the excel file actually opens on the user's computer who is watching excel files for changes.. if this makes sense
protected virtual bool IsFileLocked(string path)
{
try
{
using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
{
}
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
}
//file is not locked
return false;
}
I've got this code
string archiveFileName = BuildArchiveFileName(i, null);
string tmpArchiveFileName = BuildArchiveFileName(i, "tmp");
try
{
using (FileStream tmpArchiveMemoryStream = new FileStream(tmpArchiveFileName, FileMode.Create))
{
using (BinaryWriter pakWriter = new BinaryWriter(tmpArchiveMemoryStream))
{
if (i == 0)
{
WriteHeader(pakWriter, pakInfo.Header);
WriteFileInfo(pakWriter, pakInfo.FileList);
uint remainingBytesToDataOffset = pakInfo.Header.DataSectionOffset - CalculateHeaderBlockSize(pakInfo.Header);
pakWriter.Write(Util.CreatePaddingByteArray((int)remainingBytesToDataOffset));
}
foreach (String file in pakInfo.FileList.Keys)
{
DosPak.Model.FileInfo info = pakInfo.FileList[file];
if (info.IndexArchiveFile == i)
{
//Console.WriteLine("Writing " + file);
byte[] fileData = GetFileAsStream(file, false);
int paddingSize = (int)CalculateFullByteBlockSize((uint)fileData.Length) - fileData.Length;
pakWriter.Write(fileData);
pakWriter.Write(Util.CreatePaddingByteArray(paddingSize));
}
}
}
}
}
finally
{
File.Delete(archiveFileName);
File.Move(tmpArchiveFileName, archiveFileName);
}
I've tested this with NUnit on small file sizes and it works perfectly. Then when I tried it on a real life example , that are files over 1 GB. I get in trouble on the delete. It states the file is still in use by another process. While it shouldn't that file should have been disposed of after exiting the using branch. So I'm wondering if the dispose of the filestream is slow to execute and that is the reason I'm getting in trouble. Small note in all my file handling I use a FileStream with the using keyword.
While it shouldn't that file should have been disposed of after exiting the using branch
That's not what it is complaining about, you can't delete archiveFileName. Some other process has the file opened, just as the exception message says. If you have no idea what process that might be then start killing them off one-by-one with Task Manager's Processes tab. That being your own process is not entirely unusual btw. Best way is with SysInternals' Handle utility, it can show you the process name.
Deleting files is in general a perilous adventure on a multi-tasking operating system, always non-zero odds that some other process is interested in the file as well. They ought to open the file with FileShare.Delete but that's often overlooked.
The safest way to do this is with File.Replace(). The 3rd argument, the backup filename, is crucial, it allows the file to be renamed and continue to exist so that other process can continue to use it. You should try to delete that backup file at the start of your code. If that doesn't succeed then File.Replace() cannot work either. But do check that it isn't a bug in your program first, run the Handle utility.
I have an app that is running on a server and that has to write some stuff to excel files. When I want to save and close files I'm getting trouble when the files are open by other machines and users. Excel opens dialogs to ask for filenames but it is running on a server there is no user to close the dialogs. So when the file is open and cannot be written to it should be skipped with no GUI asking for filenames.
Workbook book = excel.Workbooks.Open(filename);
Worksheet sheet = (Worksheet) book.Worksheets.get_Item(1);
// write stuff in cells
book.SaveAs(filename);
book.Close(false);
How can I make excel to try to save the file and then close is no matter what ?
(In my app there is no lost data, it can be written to the excel files later anyways)
file exists → overwrite
file open → don't save, just close
Looks like this answers the question, check if the file is in use before you choose to save or skip.
Is there a way to check if a file is in use?
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
To check if a file exists you can use
if (File.Exists(filename)){
// if the file exists
book.Save();
}
else{
//if the file doesnt exist
book.SaveAs(filename);
}
All problems might be solved if I set the share options for the one file that I must update. So that multiple users can update the file simultaneously: Menu → Extra → ...
This doesn't solve the problem to 100% but better than nothing:
private static void saveAndClose(Workbook book, string filename)
{
try
{
File.Delete(filename);
}
catch { }
if (!File.Exists(filename))
book.SaveAs(filename);
book.Close(false);
}
I am using document.Active() method which is a part of Microsoft.office.interop.word namespace. I want to open the file i.e. I want to see the file opened in the Word application. I have set thetrackRevisions property true and rest of all the things.
I just want the file to open NOT IN SAVE-AS MODE. Just open so that when I open up a document from DB or from my PC drives I just want it to open.
Here is the code that I am executing:
Word.Document tempDoc = app.Documents.Open("E:\\xyz.docx");
// Activate the document so it shows up in front
tempDoc.Activate();
tempDoc.TrackRevisions = true;
foreach (Revision rev in tempDoc.Revisions)
{
string editedBy = rev.Author;
//string what = rev.Cells;
}
tempDoc.Close(ref Nothing, ref format, ref Nothing);
Any suggestions that come to your mind?
You just want word to open?
Have you tried
Process.Start('path to word plus filename');