I use this code to add a footer to a word document, but I want to make the footer read-only or uneditable if opened by an application. Is this possible? I searched on the net, but there isn't mention anywhere how to make it uneditable.
Word.Application wordApp = null;
// word document
document = null;
try
{
wordApp = new Word.Application();
//WordApp.Visible = true;
// open
document = wordApp.Application.Documents.Open(wordpath);
foreach (Word.Section wordSection in document.Sections)
{
//Get the footer range and add the footer details.
Word.Range footerRange = wordSection.Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
footerRange.Font.ColorIndex = Word.WdColorIndex.wdGray50;
footerRange.Font.Size = 15;
footerRange.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
footerRange.Text = wordHeaderName;
}
// save
document.Save();
}
finally
{
// close excel document & application
if (document != null)
{
try
{
document.Close(Word.WdSaveOptions.wdDoNotSaveChanges);
}
catch { }
}
if (wordApp != null)
{
try
{
wordApp.Quit();
}
catch { }
}
}
Recent versions of Word (since 2007, as I recall) have a protection possiblity that allows you to block the entire document for editing - you can then explicitly allow editing for various ranges. The tricky part is that these ranges must have content in order for the permission to take (and remain) in effect.
This means you might need to put some "hidden text" in a header, for example, that should be editable. And if any header or footer is locked the option to unlink from previous is not available. Any missing functionality could be provided with code tools that unprotects, does whatever needs to be done, then reprotects.
On the assumption that all "parts" of the document already exist when you open the document and create a footer, change your code to something like the following.
Notes:
there might be syntax "blips" as I'm converting this from VBA
You should probably read up on document Protection in both the object
model as well as the general Word help, especially IRM possibilities.
You can assign a password to the protection.
Code snippet:
Word.Application wordApp = null;
// word document
document = null;
try
{
wordApp = new Word.Application();
//WordApp.Visible = true;
// open
document = wordApp.Application.Documents.Open(wordpath);
Word.Range permittedRange = document.Content;
permittedRange.Editors.Add(Word.WdEditorType.wdEditorEveryone);
foreach (Word.Section wordSection in document.Sections)
{
//Allow editing the headers?
permittedRange = wordSection.Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
permittedRange.Editors.Add(Word.WdEditorType.wdEditorEveryone);
//Get the footer range and add the footer details.
Word.Range footerRange = wordSection.Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
footerRange.Font.ColorIndex = Word.WdColorIndex.wdGray50;
footerRange.Font.Size = 15;
footerRange.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
footerRange.Text = wordHeaderName;
}
document.Protect(Word.WdProtectionType.wdAllowOnlyReading, ref missing, ref missing, ref missing, ref missing);
// save
document.Save();
Related
I'm attempting to create a word document, but text between certain words should be crossed out. I tried looking online for solutions but the only solution I could find was:
Set myRange = document.Range(Start:= document.Words(1).Start, _End:= document.Words(3).End)
myRange.Font.StrikeThrough = True
from here https://msdn.microsoft.com/en-us/vba/word-vba/articles/font-strikethrough-property-word for VBA. Unfortunately there was nothing for C#.
Does anyone know how you would add a strike-through to specific pieces of text before saving it all to a word document?
My code for reference:
//input is a StringBuilder received by method
try {
//Create an instance for word app
Microsoft.Office.Interop.Word.Application winword = new Microsoft.Office.Interop.Word.Application();
//Set animation status for word application
winword.ShowAnimation = false;
//Set status for word application is to be visible or not.
winword.Visible = false;
//Create a missing variable for missing value
object missing = System.Reflection.Missing.Value;
//Create a new document
Microsoft.Office.Interop.Word.Document document = winword.Documents.Add(ref missing, ref missing, ref missing, ref missing);
//adding text to document
document.Content.SetRange(0, 0);
document.Content.Text = input.ToString();
//Save the document
object filename = #"C:\Users\TempUser\Desktop\temp1.docx";
document.SaveAs2(ref filename);
document.Close(ref missing, ref missing, ref missing);
document = null;
winword.Quit(ref missing, ref missing, ref missing);
winword = null;
Console.WriteLine("Document created successfully!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I've extracted the relevant part from your code to make it easier to follow.
My assumption with this sample is that text should be inserted at the end of the document and formatted as "strikethrough". Notice how I declare a Word.Range object and assign the body of the document to it. For understanding how it works, think of a Range like a Selection, but you can have more than one and it's not visible in the document.
The next line "collapses" the Range to its end-point - like pressing Right arrow. If you did not collapse the Range, the text assigned to it would replace what's in the document (like over-typing a selection). The text is then assigned to the Range and the Strikethrough applied.
Note that in the old Word Basic days "true" and "false" were not concepts used for setting font decoration. Word's object model still uses these old Word Basic commands. Under the covers they still use -1 for true and 0 for false (and sometimes 1 for something else). While the VB languages can use the "pseudo boolean" settings (true/false) that have been added to the object model for convenience, C# doesn't "see" them, so you need -1 for true.
//adding text to document
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
Word.Range rng = document.Content;
rng.Collapse(ref oCollapseEnd);
rng.Text = input.ToString();
rng.Font.Strikethrough = -1; // 0 for false
I build word addin that have two check-boxes to swabbing between TEXT view and XML View.
And in the XML viewing I restrict the editing. When the user return back to TEXT viewing I remove the restriction for editing.
The code:
private void ShowDocBodyXML_Click(object sender, RibbonControlEventArgs e)
{
var doc = Globals.DLPAddIn.Application.ActiveDocument;
doc.Save();
string fileName = doc.FullName;
doc.Close();
using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
{
MainDocumentPart mainPart = document.MainDocumentPart;
Body body = mainPart.Document.Body;
string text = body.InnerXml;
body.RemoveAllChildren();
DocumentFormat.OpenXml.Wordprocessing.Paragraph para = body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
Run run = para.AppendChild(new Run());
run.AppendChild(new Text(text));
}
Globals.DLPAddIn.Application.Documents.Open(fileName);
doc = Globals.DLPAddIn.Application.ActiveDocument;
object missing = System.Reflection.Missing.Value;
doc.Protect(Microsoft.Office.Interop.Word.WdProtectionType.wdAllowOnlyReading,
missing, missing, missing, missing);
doc.Save();
}
private void ShowDocBodyText_Click(object sender, RibbonControlEventArgs e)
{
var doc = Globals.DLPAddIn.Application.ActiveDocument;
object missing = System.Reflection.Missing.Value;
if (doc.ProtectionType != WdProtectionType.wdNoProtection)
doc.Unprotect(missing);
doc.Save();
string fileName = doc.FullName;
doc.Close();
using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
{
MainDocumentPart mainPart = document.MainDocumentPart;
Body body = mainPart.Document.Body;
string text = body.InnerText;
body.RemoveAllChildren();
body.InnerXml = text;
}
Globals.DLPAddIn.Application.Documents.Open(fileName);
}
The code is working with out any problem but if the Word Doc have an image when the user trying to return back to TEXT viewing the the code throw exception (The file was corrupted) in this code:
Globals.DLPAddIn.Application.Documents.Open(fileName);
I think when I restrict the editing it remove the image file.
If it's like that how can i solve this problem.
Your current approach does not work when there are images or other resources in the document because your strip all images when creating the Word document containing only the XML of the MainDocumentPart.
One solution to this is to show the OpenXML in the so-called Flat OPC format. This format describes the entire OpenXML (zip) package in a single XML document (without the hierarchical structure of the OpenXML package).
The easiest way to obtain the XML in Flat OPC format is to use the Document.WordOpenXML property:
var doc = Globals.DLPAddIn.Application.ActiveDocument;
var xml = doc.WordOpenXML;
var newDoc = Globals.DLPAddIn.Application.Documents.Add();
newDoc.Range.Text = xml
I have created a word document which generates dynamic contents using word.interop. It has some page breaks used in between. what is the problem which I am facing is, this page breaks creates blank pages which I don't want to show to users.
In some cases I need those page breaks there in order to maintain the page layout, so I can't think about removing those page breaks. but what I want is another solution like, in case if there no contents in a particular page other than a page break, remove that page.
How can I accomplish this, please help..
Thanks in advance..
Ahm quite easy: just look on the page and if the only paragraph there contains only a pagebreak - delete the page (or more accurate: save the empty pages to a list an delete in one stepat the end of the story):
I cannot provide code for you, because there is no sample code.
private bool RemoveBlankPage()
{
Word.Application wordapp = null;
Word.Document doc = null;
Word.Paragraphs paragraphs=null;
try
{
// Start Word APllication and set it be invisible
wordapp = new Word.Application();
wordapp.Visible = false;
doc = wordapp.Documents.Open(wordPath);
paragraphs = doc.Paragraphs;
foreach (Word.Paragraph paragraph in paragraphs)
{
if (paragraph.Range.Text.Trim() == string.Empty)
{
paragraph.Range.Select();
wordapp.Selection.Delete();
}
}
// Save the document and close document
doc.Save();
((Word._Document)doc).Close();
// Quit the word application
((Word._Application)wordapp).Quit();
}
catch(Exception ex)
{
MessageBox.Show("Exception Occur, error message is: "+ex.Message);
return false;
}
finally
{
// Clean up the unmanaged Word COM resources by explicitly
// call Marshal.FinalReleaseComObject on all accessor objects
if (paragraphs != null)
{
Marshal.FinalReleaseComObject(paragraphs);
paragraphs = null;
}
if (doc != null)
{
Marshal.FinalReleaseComObject(doc);
doc = null;
}
if (wordapp != null)
{
Marshal.FinalReleaseComObject(wordapp);
wordapp = null;
}
}
return true;
}
This link helped me complete my project
https://code.msdn.microsoft.com/office/How-to-remove-blank-pages-e200755d
I want to merge multiple word documents while preserving the header and footer of each document. The below code is merging the documents but merges the header and the footer as well:
public static void Merge(List filesToMerge, string outputFilename)
{
Application wordApplication = null;
Document wordDocument = null;
try
{
// Create a new Microsoft Word application object
wordApplication = new Application();
wordApplication.Visible = false;
wordApplication.ScreenUpdating = false;
// Create a new file based on our template
object defaultTemplate = #"Normal.dotm";
wordDocument = wordApplication.Documents.Add(ref defaultTemplate);
// Make a Word selection object.
Selection selection = wordApplication.Selection;
// Loop thru each of the Word documents
foreach (string file in filesToMerge)
{
// Insert the files to our template
selection.InsertFile(file);
object pageBreak = WdBreakType.wdSectionBreakNextPage;
selection.InsertBreak(ref pageBreak);
}
// Save the document to it's output file.
object outputFile = outputFilename;
wordDocument.SaveAs(ref outputFile);
}
catch (Exception ex)
{
Console.WriteLine("Error while conversion. Details: " + ex);
}
finally
{
MSWordCleanup(wordApplication, wordDocument);
}
}
Is there anyway to do so?
It might be helpful for you to work through these training lessons:
http://office.microsoft.com/en-us/word-help/headers-and-footers-from-basic-to-elaborate-RZ001021662.aspx
While this won't give you the answer in "automation form", it might be enough for you to figure out the answer.
I have a really simple word document with Content Controls (all text).
I want to loop through the controls, filling them with values from a dictionary. Should be super simple, but something is wrong:
var myValues = new Dictionary<string, string>(); //And fill it
using (var wordDoc = WordprocessingDocument.Open(outputFile, true))
{
MainDocumentPart mainPart = wordDoc.MainDocumentPart;
foreach(SdtElement sdt in mainPart.Document.Descendants<SdtElement>())
{
SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();
if (alias != null)
{
string sdtTitle = alias.Val.Value;
sdt.??? = myValues[sdtTitle];
}
}
mainPart.Document.Save();
}
How do I write my value into the document?
Do I need a CustomXmlPart?
If you are going to do something like that, you'll need to write suitable content into the Sdt's SdtContent: a paragraph or a run or a tc etc depending on the sdt's parent element.
The alternative is to put the contents of your dictionary into a CustomXml part, and set up databindings on each content control which refer to the relevant dictionary element. Word will then resolve the bindings when the docx is first opened (which is not much good to you if you expect your users to open it with something else).
You can use this code.
foreach (SdtElement sdt in mainPart.Document.Descendants<SdtElement>())
{
SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();
if (alias != null)
{
string sdtTitle = alias.Val.Value;
Text t = sdt.Descendants<Text>().First();
t.Text = "test";
}
}