Copying template doc to active doc - c#

I am making Office plugin to Word. Using Microsoft.Office.Interop. I have few .dotm files(Templates). When pressing a button I need to copy all text from one .dotm to my Active document. I cant figure out how can I put in variable the active document. So I can insert the info.
I tried several ways. Now I am trying to open .dotm copy text from there and then paste it to my active one. But it doesn't work. The Word will start with no errors(while starting in Visual Studio) and then when I am pressing the button it tells me that there is no open document on this: var MyDoc = app.ActiveDocument;
1)
private void Button1_Click(object sender, RibbonControlEventArgs e)
{
var app = new Microsoft.Office.Interop.Word.Application();
var MyDoc = app.ActiveDocument;
var sourceDoc = app.Documents.Open(#"C:\install\CSharp\test.docx");
sourceDoc.ActiveWindow.Selection.WholeStory();
sourceDoc.ActiveWindow.Selection.Copy();
MyDoc.ActiveWindow.Selection.Paste();
2)
var newDocument = new Microsoft.Office.Interop.Word.Document();
newDocument.ActiveWindow.Selection.Paste();
newDocument.SaveAs(#"C:\install\CSharp\test1.docx");
But if I do that way(2):
It will work. But I need to paste into my active document. Also I think that the copy paste method is not so good. Maby there is some other method to import one document into an other.

Never, ever, ever do (2). Using new Microsoft.Office.Interop.Word.Document(); is certain to cause unexpected memory leak problems. Word lets you do it, but it's not supported. new should only ever be used for a new instance of the Word application.
Instead, use Documents.Add referencing the template file. That will create a copy of the template as a new document - very simple:
private void Button1_Click(object sender, RibbonControlEventArgs e)
{
var app = new Microsoft.Office.Interop.Word.Application();
var MyDoc = app.Documents.Add(#"C:\install\CSharp\test.docx");
}

Related

Previewing a PDF in C#

I would like to create a PDF document with iTextSharp and preview it directly in the application.
And this not only once, but as often as I like, during runtime, when the user makes changes to the text input.
So far it works, but as I said before only once, when the program is started.
When I try to generate the PDF file again, I get an error message,
that the process cannot access the saved PDF document because it is currently being used by another process.
I have already tried to prevent access, but without success so far.
private void CreateDocument()
{
//my attempt to stop the browser from blocking the file acces
if (browser.IsBusy())
{
browser.Stop();
}
doc = new Document(PageSize.A4);
writer = PdfWriter.GetInstance(doc, new FileStream("document.pdf", FileMode.Create));
doc.Open();
cb = writer.DirectContent;
//here is the actual pdf generation
doc.Close();
//this is the part where I set the pdf document reference from the web browser
browser.Navigate(#"path\document.pdf");
}
The actually error occurs where I set the PDFwriter instance.
I've found a page preview component in the toolbox from iTextSharp, but sadly no reference on how to use it. Using that might work easier than trying it with the web browser.
If you don't mind a little bit of flickering just navigate to "about:blank" before you try to save.
If you have a probelm with that, just make a temporary copy of the file and open the copy with the browser. Probably not the best solutions, but should work
My problem was, that the web browser navigation is asynchronous.
As a workaround I used an event listener that keeps track, when the browser actually loaded the document.
For more information about that topic check this question out: https://stackoverflow.com/a/583909/12178103
Down here you can see my complete code
//gets called when the application starts
public Form1()
{
InitializeComponent();
//first time the web browser load operation gets called - make sure to set the event handler
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowserUnload);
WebBrowserLoad();
}
//this button regenerates the pdf
private void Button_Click(object sender, EventArgs e)
{
WebBrowserLoad();
}
//creates the actually pdf document
private void WebBrowserLoad()
{
browser.Hide();
browser.Navigate("about:blank");
}
private void WebBrowserUnload(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (e.Url.ToString() == "about:blank")
{
doc = new Document(PageSize.A4);
using (fileStream = new FileStream("document\pdf", FileMode.Create))
{
using (writer = PdfWriter.GetInstance(doc, fileStream))
{
PageEventHelper pageEventHelper = new PageEventHelper();
writer.PageEvent = pageEventHelper;
doc.Open();
cb = writer.DirectContent;
//create the pdf here
writer.Flush();
doc.Close();
doc.Dispose();
}
}
browser.Navigate(#"path\document.pdf");
}
else if (e.Url.ToString() == "file:///path/document.pdf")
{
browser.Show();
}
}

Multiple Instances of Word Document Ribbon button disable in Word Addin Project

My task was to create a new document from a given word document and then I need to disable the custom ribbon button only in that newly created Word document ribbon. Not the active document consider here because it is getting switch when user switch it.
Currently I cannot get the new Word instance ribbon control from C# code. When I apply following, both documents are affected.
CustomRibbon ribbon = Globals.Ribbons.CustomRibbon;
ribbon.button.Enabled = false;
Something like this should work, you have to find a way to identify your document
private void MyAddin_Startup(object sender, System.EventArgs a)
{
this.Application.DocumentChange += new ApplicationEvents4_DocumentChangeEventHandler(Application_DocumentChange);
}
private void Application_DocumentChange()
{
bool enableButton = false;
if(yourdocument) // put something here that checks the document you want the button to be enable in
{
enableButton = true;
}
CustomRibbon ribbon = Globals.Ribbons.CustomRibbon;
ribbon.button.Enabled = enableButton;
}

How to define parent process from child when are having the same process id

I am using C#.With this code I am trying to open a word document (WINWORD) and get notify when the specific file or file name that I have open from the software has close.
Right now if I open the x.docx file from the software and open another y.docx manualy and close the y.docx file my programs things that was the x.docx because are having the same process name WINWORD.
I have read a lot of articles but i couldn't find anything.Is it possible to do this in any way?
private void button1_Click(object sender, EventArgs e)
{
Process mydoc = new Process();
mydoc.StartInfo.FileName = "op.docx";
mydoc.StartInfo.WorkingDirectory = "C:\\";
mydoc.Start();
mydoc.WaitForExit();
notifyIcon1.Visible = true;
notifyIcon1.Icon = new System.Drawing.Icon(Path.GetFullPath(#"C:\Users\Marios\Desktop\down.ico"));
notifyIcon1.BalloonTipTitle = "waiting...";
notifyIcon1.BalloonTipText = "Word has has opened...";
notifyIcon1.ShowBalloonTip(100);
Displaynotify();
}
protected void Displaynotify()
{
try
{
var processes = Process.GetProcessesByName("WINWORD");
notifyIcon1.Visible = true;
notifyIcon1.Icon = new System.Drawing.Icon(Path.GetFullPath(#"C:\Users\Marios\Desktop\down.ico"));
notifyIcon1.BalloonTipTitle = "exited.";
notifyIcon1.BalloonTipText = "Word has exited...";
notifyIcon1.ShowBalloonTip(100);
}
catch (Exception ex)
{
}
}
Update 1 with links from the Answer
I have change my code and now i open it with this way but still i cant do what i want
private void button1_Click(object sender, EventArgs e)
{
Word.Application oWord = new Word.Application();
Microsoft.Office.Interop.Word.Document oDoc = oWord.Documents.Open("C:\\op.docx");
oWord.Visible = true;
((Word._Document)oDoc).Close();
// ((Word._Document)oDoc).Close();
//((Word._Application)oWord).Quit();
//Displaynotify();
}
You can automate Word from your C# application. In that case you will be able to check what documents are opened at the moment and handle the Close event of the Document class which is fired when a document is closed.
See How to automate Microsoft Word to create a new document by using Visual C# for more information and sample code in C#. Also you may find the C# app automates Word (CSAutomateWord) sample project helpful.
In that case there is no need to run a new process. All the job can be done using Word automation.

how to open a powerpoint file that has been modified in c#

i have a c# windows forms application that opens up a powerpoint file, now if i make a change to the powerpoint file and if my program is running it must automatically pick up the file that has been modified, or can i set like a timer to refresh the page so it will pick up the changes?
The following code works in opening a file.
private void button1_Click(object sender, EventArgs e)
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
var file = pres.Open(#"C:\Pres1.pptx", MsoTriState.msoFalse, MsoTriState.msoTrue, MsoTriState.msoFalse);
PowerPoint.SlideShowSettings slideSetting = file.SlideShowSettings;
slideSetting.Run();
PowerPoint.SlideShowWindows slideShowWindows = app.SlideShowWindows;
while (true)
{
if (slideShowWindows.Count <= 0)
break;
System.Threading.Thread.Sleep(100);
}
}
You can use the FileSystemWatcher class to detect changes to that file (http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(v=vs.110).aspx).

Excel Automation: Protect single worksheet from deletion by user

VSTO 4.0 / Office 2007
In an Excel document-level automation project, I have a worksheet that must not be deleted from the workbook. I am afraid that a careless user might delete it by accident, which currently causes a lot of grief (exceptions galore).
I can not protect the entire workbook, because the user must be able to create, delete and otherwise modify this file. Exactly one sheet needs to be protected from deletion, but I may be overlooking something, so if there exists such solution I'm all ears. For example I could imagine that I can Protect() and Unprotect() the workbook when the sheet is visible, but this solution seems messy.
Googling yielded the following VBA code:
Private Sub Worksheet_Activate()
Dim CB As CommandBar
Dim Ctrl As CommandBarControl
For Each CB In Application.CommandBars
Set Ctrl = CB.FindControl(ID:=847, recursive:=True)
If Not Ctrl Is Nothing Then
Ctrl.OnAction = "RefuseToDelete"
Ctrl.State = msoButtonUp
End If
Next
End Sub
I'm not familiar with VBA, but I tried running this from the VSTO generated startup method:
private void Sheet1_Startup(object sender, System.EventArgs e)
{
//Is there a neater way to iterate through all Office Collections?
for (var i = 1; i <= Application.CommandBars.Count; i++)
{
var commandBar = Application.CommandBars[i];
//847 is a magical constant that any fule no has something to do with sheet deletion
var control = commandBar.FindControl(Id: 847, Recursive: true);
if (control != null) control.OnAction = null;
}
}
This code seems to do exactly nothing. You may ask "Hey, Gleno, why are you setting OnAction to null" , well I don't know what to set it to... The linked VBA solution attaches to Activate and Deactivate events, so there's more code where that came from.
Thanks in advance.
I had to do something very similar today. I would just disable the sheet delete buttons whenever your one "undeleteable" sheet is active. If there's a keyboard shortcut to delete a sheet, I can't find one. (If there is, you could disable that too.)
This would go in your ThisWorkbook class:
private void ThisWorkbook_Startup(object sender, System.EventArgs e)
{
this.SheetActivate += (sh) =>
{
this.ribbon.InvalidateBuiltinControl("SheetDelete");
};
}
public bool CanDeleteActiveSheet()
{
if (this.ActiveSheet == null)
return true;
// Replace Sheet1 with your sheet's CodeName
return ((Excel.Worksheet)this.ActiveSheet).CodeName != "Sheet1";
}
// Keep a local reference to the ribbon in your ThisWorkbook class
// so you can call InvalidateControl() from it.
Ribbon ribbon;
protected override IRibbonExtensibility CreateRibbonExtensibilityObject()
{
this.ribbon = new Ribbon();
return this.ribbon;
}
This would go in your ribbon code behind:
public void InvalidateBuiltinControl(string controlID)
{
this.ribbon.InvalidateControlMso(controlID);
}
public bool deleteButton_GetEnabled(IRibbonControl control)
{
return Globals.ThisWorkbook.CanDeleteActiveSheet();
}
And this would go in your ribbon xml:
<commands>
<command idMso="SheetDelete" getEnabled="deleteButton_GetEnabled" />
</commands>
I'm still a little leery of holding on to that ribbon reference in ThisWorkbook, but so far no one has mentioned a better way in the question I posted earlier. Hope this helps!
I'm having a similar problem where I know how to protect the worksheet but I need to turn protection on after the sheet has been populated with external data from a SQL connection. I cannot locate the correct event to do this.
This should help you put it in the startup event for the worksheet:
Me.Protect(password:="password", allowFiltering:=True, allowSorting:=True, allowUsingPivotTables:=True)

Categories