In case when a word document is opened over the network, and another user is editing it, the file is write blocked for other users. A small window pops up with possibility to open the file write protected, create a local copy and to merge the files later or to notify when the file is available again.
I would like to read out that flag before opening the document. Unfortunately it is not the file property flag (FileInfo), which is set using file system. How is it possible to get the "already in use" flag using .Net?
Related
I creating VSTO Add-In that will send documents to server via REST API.
I need send currently opened document (e.g. docx) just as a file.
First problem was getting full name of the active document.
If found the only way:
Path.Combine(Globals.ThisAddIn.Application.ActiveDocument.Path,
Globals.ThisAddIn.Application.ActiveDocument.Name)
This code can return good path on local drive: D:\Docs\Doc1.docx
But also it can return HTTP path to document in a cloud (e.g. OneDrive): https://d.docs.live.net/xxxxx/Docs\Doc1.docx
Even if it would only local documents I can't get file of this document. I tryed this code:
using (var stream = new StreamReader(docFullPath)) { }
And in case of locally stored document I got System.IO.IOException: The process cannot access the file because it is being used by another process. Not surprizing.
And in case of cloud stored document I got System.NotSupportedException: The given path's format is not supported. Of cource!
I believe I'm doing all wrong and my goal is reachable.
My question is: How read file of currently opened document on MS Office App from Add-In without closing App?
Even if you could access the file ActiveDocument.FullName points to there is no guarantee that the user already has saved all changes to disk, or even worse, the document is still in the state of creation and has never been saved yet.
There is another little known/documented way to retrieve a file of an open document which is using the IPersistFile COM interface which is implemented by the Document object. The following sample saves a document to the specified location. This happens without modifying the save state of the document, i.e. you get the exact version of the document as it is open (and not as it has previously been saved to disk) and the user may later still decide to save possible modifications of the document or not.
public static void SaveCopyAs(this Document doc, string path)
{
var persistFile = (System.Runtime.InteropServices.ComTypes.IPersistFile)doc;
persistFile.Save(path, false);
}
You can copy an open document on the filesystem using File.Copy(FullName, <some_temp_filename>), and then send the copy to your REST service. This works even though it's still open for exclusive reading/writing in Word.
In my console application, I am generating some .pdf files and putting them in a specific folder. Each of these files have unique content with unique names. For example, a similar file names is "6cc32a23-321d-3v8ba181-aa4c38cd7e3a.pdf".
What I would like to do, is open these allow the user to open the pdf from within the console application. Of course they could navigate to the folder they are stored in each time, but I don't wan to do that.
Because the name of each file is unique, how can know which file to open? I had the thought of created a method that searches the folder based on the newest "Date modified". The method basically search the folder for the newest file and attempt to open it. Is that even possible? Any other suggestions would be helpful as well. Thanks!
I have a C# program which generates a CSV file, then opens an XLSM file in Excel (using ProcessStartInfo and Process.Start). The macro in the XLSM loads the CSV file and distributes data from it to specific cells. Eventually this will be C# generating a spreadsheet without macros that can be loaded in any office suite, and the CSV will disappear.
My problem is that this system now needs to support running the XLSM from anywhere on disk. It finds the CSV via a hardcoded relative path, which doesn't work from a user-specified location. I'd like to do something similar to passing a compiler parameter to define a constant.
EDIT 1:
Alternative approaches I have considered and rejected:
Copy the XLSM to a standard location near the CSV and run it from there.
I would need to copy the file back to its original location, but I don't know when Excel is closed to do that... Except maybe in Excel, but it doesn't know the original location, hence this question.
Create the CSV file next to the user-specified XLSM location.
The CSV file's location is specified in an NLOG configuration file, and changing the surrounding implementation to use a hardcoded path would be expensive. This is the only idea I've had that could work, but it would hurt.
Create a Windows-based hard link to the custom location from the standard location.
I can't assume I'm running on an NTFS filesystem.
Porting your CSV generating program to a user machine you could:
set an environment variable on the user machine to the target directory; e.g. (cmd line) SET CSVPATH=C:\My\CSV
let the macro from your CSV processing XLSM read this environment variable using the Environ() function; e.g. (VBA) MyPath = Environ("CSVPATH") & "\"
alternatively, you could
use a directory selection dialog in an "installation XLSM" to write the correct file path(s) to the target machine's registry using the SaveSetting statement
let the macro from your CSV processing XLSM read the registry using the GetSetting() function to get the correct path
My task is to generate Word documents. By selecting the appropriate options, we can generate a document. I have the base documents in the server, and if I click generate, then the document will be generated and we can save it on our local drive.
If I am using the portal now and, at the same time, if some one is using it in their machine at the same time, then the document is not getting generated. It's automatically getting posted back.
I want to show a progress bar or something like that, so that the person waits until the document is completely generated.
Is this possible using threads?
When you read your base document on the server, use File.Open with FileAccess.Read or File.OpenRead.
By doing this, you can read the same files with several threads at the same time.
Is there any way to determine if a file is open by anything include applications that do not lock the file (like notepad).
I need to detect when a given file myfile.txt is no longer open in any application including notepad - so i cannot use File.Open(...) with exclusive access to test since the file has no lock on it.
No. When Notepad has opened a file, it has read the entire file in and then closed it. So there is no trace in the OS that links Notepad's private memory with the file on disk.
Opening the file exclusively will not work, because Notepad does not have the file open. Searching Notepad's handle table will not work, because Notepad does not have the file open.
The only way to detect this is to write an unmanaged DLL that is injected into every process to scan their virtual memory, searching for the exact file contents. Not recommended.
You must call File.Open(...) specifying your desired access flags and check the returning value to determine if the file is opened or if the access is denied. This is the recommended and safe way to access a file.