The process cannot access the file used by another process - c#

I have a windows application (in C#) which sends a DOC file to a pdf printer, creates pdf and read the bytes. The application uses word automation to print pdf using the following code
object Background = false; //to make sure the pdf file is created before continuing
wordApp.Visible = true;
wordApp.ActivePrinter = printerName;/*pdf printer*/
wordDoc = wordApp.Documents.Open(ref objFileName,
ref missing, ref objFalse, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing);
wordDoc.Activate();
wordDoc.PrintOut( Background, ref missing, ref Range, ref missing,
ref missing, ref missing, ref missing, ref Copies,
ref missing, ref PageType, ref PrintToFile, ref Collate,
ref missing, ref ManualDuplexPrint, ref PrintZoomColumn,
ref PrintZoomRow, ref missing, ref missing);
do
{System.Threading.Thread.Sleep(10);
} while (wordApp.BackgroundPrintingStatus > 0);
wordDoc.Close(ref objFalse, ref missing, ref missing);
After creating the pdf, i read the bytes using
bytes = System.IO.File.ReadAllBytes(Path.ChangeExtension(fileName, "pdf"));
Even though i set the background to false, it take a second or so for the file to be created in the directory, so readallbytes fails as it cannot find the file. I added the following code to wait for a time period so the pdf file appears
while (!File.Exists(Path.ChangeExtension(fileName, "pdf")))
{
System.Threading.Thread.Sleep(1000);
}
bytes = System.IO.File.ReadAllBytes(Path.ChangeExtension(fileName, "pdf"));
But sometimes i get exception that filename.pdf does not exist or i get process cannot access the file as it is being used by another process. I do not understand why file is not accessible as i am not doing anything that would lock the file and another thing i don't get it is i could read the bytes sometimes but thats does not happen always. I get not found error, does that mean the file is not created with in the sleep timeframe?

Instead of trying to do this with Thread.Sleep, I suggest you use a FileSystemWatcher object to monitor the folder for newly-created or newly-renamed files. This will allow you to set up an event to trigger the code for subsequent processing when the file is ready.

Related

Add gridview in word document

I want to add gridview in the following code.
How do I add a Gridview into a word document?
My Word document creation code ;
object missing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document aDoc = null;
DateTime today = DateTime.Now;
object readOnly = true;
object inVisible = true;
aDoc = wordApp.Documents.Open(ref fileName, ref missing, ref readOnly, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref inVisible, ref missing, ref missing, ref missing, ref missing);
this.FindAndReplace(wordApp, "##formkodu##", TextBox1.Text);
this.FindAndReplace(wordApp, "##sirketadi##", DropDownList11.SelectedItem.Text);
this.FindAndReplace(wordApp, "##il##", ddliller.SelectedItem.Text);
this.FindAndReplace(wordApp, "##isletme##", ddlisletmeler.SelectedItem.Text);
this.FindAndReplace(wordApp, "##yüklenicifirma##", ddlyükleniciler.SelectedItem.Text);
wordApp.Visible = false;
aDoc.Activate();
aDoc.SaveAs(ref saveAs, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
wordApp.Quit(ref missing, ref missing, ref missing);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(aDoc);
Gridview is not a COM ActiveX control, so it cannot be hosted on Word's document surface - at least, not directly.
If you were able to use VSTO then you could use VSTO's built-in tools to wrap the Gridview in a COM ActiveX control in order to place it on the document surface. VSTO is not supported in ASP.NET, however.
A possible way around this could be do develop a VSTO Add-in that's installed on the machines where the document you create is opened. That could take care of wrapping, inserting and managing the ActiveX control + Gridview.
But you might be better off to simply generate a Word table in the document? That works fine using the Interop (or Open XML)...
There is some old information about the basics for creating an ActiveX control on MSDN, by Geoff Darst: https://social.msdn.microsoft.com/Forums/vstudio/en-US/71a75dc4-dcea-454a-9e4a-011a2f811994/vsto-activex-and-powerpoint?forum=vsto
https://social.msdn.microsoft.com/Forums/vstudio/en-US/4282a65c-ccd7-4fd4-a56c-75f84615fff6/embedding-active-x-control-in-office-application-using-vsto-2005?forum=vsto
Instead of interops i would prefer using OpenXML (*.docx) if it possible. How to create a table is documented here: How to: Insert a table into a word processing document (Open XML SDK). With this you don't need interops, which can cause a lot of trouble if the wrong office version is installed or any other issue. Hope this helps.

How to load all controls added to a word document (Microsoft Office Interop Word)?

I am using Microsoft.Office.Interop to open, manipulate and save a Word document file (.doc).
I can get all Text contents but no success in loading added controls (i.e. TextBoxes) in the opened word document.
I get the text using following command
Microsoft.Office.Interop.Word.ApplicationClass oWordApp = new Microsoft.Office.Interop.Word.ApplicationClass();
Microsoft.Office.Interop.Word.Document oWordDoc = oWordApp.Documents.Open(ref fileName, ref missing, ref readOnly, ref missing,ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref isVisible, ref missing, ref missing, ref missing);
oWordDoc.Activate();
oWordApp.Selection.TypeParagraph();
string test = oWordDoc.Content.Text;
How can I have access to all controls included in the base word document?
Thanks.
check this:
Word.Document oDoc=...;
foreach (Word.Shape shape in oDoc.Shapes)
{
//do some thing with shape
}
By changing
oWordApp.Selection.TypeParagraph();
To
oWordApp.Selection.WholeStory();
And digging in oWordDoc.shapes, I gained access to all controls.

Word 2010 Interop: Change the name of the default document

I need to be able to change the name of the default document from Document1 to Report when a Word document is started from my application. The problem is that the name property in the Document object is read only. Any idea on a method I can call at startup that changes the name?
You might be interested in this snippet of code:
Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
object missing = System.Reflection.Missing.Value;
object fileName = "Report";
object isReadOnly = false;
object isVisible = true;
Microsoft.Office.Interop.Word.Document doc = wordApp.Documents.Add(ref missing, ref missing, ref missing, ref isVisible);
doc.SaveAs2(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref isReadOnly, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
wordApp.Visible = true;
This will pop open a new Word document named "Report" as you specified. Notice this uses the concept I mentioned in the comment, that is, it saves the file first with a new name then opens it. In this case, the default location is probably your User's "Documents" folder, but you can specify the path as needed.
Don't forget to close and release the COM objects "doc" and "wordApp" as needed. Sometimes the GC doesn't mop it all up appropriately, especially if the application closes unexpectedly or if you forget to close any of them when you're done.

Is there a tool or library, similar to wkhtmltopdf, to convert html to word documents?

It must be able to handle css and javascript as the page contains "highcharts" javascript charts.
It doesn't have to be an external process, a library would be great too.
Basically I need to be able to create a word document containing highcharts as images along with some text and other graphics.
Any ideas would be great.
Look at this as an example
It depends a lot on the nature of the html document you are trying to convert. One simple way is just to use the Word automation to open an .html document and then save it as a .doc document.
object readOnly = false;
object isVisible = true;
object missing = System.Reflection.Missing.Value; // Values we don't care about
object fileName = "C:/webpage.htm";
object newFileName = "C:/webpage.doc";
Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
// word.Visible = true; // To see what's happening
Microsoft.Office.Interop.Word.Document document = word.Documents.Open(ref fileName, ref missing, ref readOnly, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
document.Activate();
object saveFormat = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument;
document.SaveAs(ref newFileName, ref saveFormat, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
document.Close(ref missing, ref missing, ref missing);
Note
You have to add a reference to Microsoft.Office.Interop.Word or something similar
The number of ref missing arguments depends on wich version of Word you are using
You have to use full paths in the filename as the Word instance starts from the System folder.

Comparing two RTF documents side-by-side in Word (VSTO)

For my VSTO Word solution, I need to programatically "compare" two documents side-by-side. In other words I need to, from code, perform the equivalent of clicking the View > Show Side by Side button.
I tried using the CompareSideBySideWith method after loading two documents. An exception is thrown: "The requested member of the collection does not exist". I am not the first to encounter this; see Microsoft's (boilerplate, not particularly helpful) replies in this thread. The MS rep ended up scratching her head and giving up.
I even tried opening two blank documents and comparing them. This time no exception, but the compare didn't happen and CompareSideBySideWith() returned false.
Document doc1 = this.word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
object doc2 = this.word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
doc1.Windows.CompareSideBySideWith(ref doc2);
Has anyone discovered a workaround for this? It seem a pretty basic piece of functionality to have a in a custom solution.
Note: We need to call the actual "Side by Side" compare, not just arrange the windows via Windows.Arrange(). This is partly because our ribbon contains an alias for the View Side by Side button, which won't be turned on (pressed in) unless the actual Side by Side command is called successfully.
Update: The exception was still thrown in the above example involving two new documents; Word swallowed the exception because I tried it outside of my try-catch block.
Per Otaku below I tried calling doc2.Windows.Compare(ref doc1) instead, and this worked for blank documents as well as test documents saved as .docx and .rtf from Word 2007.
However, we need to compare documents saved as RTF from another RTF editor. When I load one of our documents, it fails. To reproduce my error, try loading RTF documents saved from WordPad--these fail as well. I've tried tinkering with the Encoding and Format parameters of Documents.Open() to no avail. It would be nice to avoid having to convert and save the temp file as .docx, particularly for larger documents! Also note that I can click View Side by Side after opening the WordPad-saved RTF files manually, and it works.
Also, it only seems to matter what format the compare document (the document being passed as parameter to Windows.CompareSideBySideWith() is in. For example, if we are doing doc2.Windows.CompareSideBySideWith(ref doc1) as in Otaku's example, it works when doc1 is a regular docx but not when it's an RTF saved from WordPad. (Regardless of where doc2 came from).
Update 2:
As usual, one line of code resolves several days of chasing one's tail:
doc1.Convert(); // Updates the document to the newest object model (i.e. DOCX)
Can now compare side-by-side without a problem.
Reverse the compares of your documents and it should be fine:
For new documents
Document doc1 = this.word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
Document doc2 = this.word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
object o = doc1;
doc2.Windows.CompareSideBySideWith(ref o);
For existing documents
object missing = System.Reflection.Missing.Value;
object newFilename1 = "C:\\Test\\Test1.docx";
Document doc1 = this.word.Documents.Open(ref newFilename1, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
object newFilename2 = "C:\\Test\\Test2.docx";
Document doc2 = this.word.Documents.Open(ref newFilename2, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
object o = doc1;
doc2.Windows.CompareSideBySideWith(ref o);
If your app isn't visible or you are launching a new instance of Word, you should set this.word.Visible = true; before running the opening of documents as CompareSideBySideWith is a UI routine.

Categories