I have a protected document (doc.ProtectionType == wdAllowOnlyFormFields). It has areas that can be edited. Everything else is protected even from copying. I'm using the NetOffice.Word library and I'm trying to programmatically find text and create a bookmark in the found range. The problem is that when I try to call the method wordDoc.Content.Duplicate.Find.Execute(smthParams), the exception "COMException: This method or property is not available because the object refers to a protected area of the document." occurs. And, I can get any range of text manually without any problems:
var range = doc.Content.Duplicate;
range.SetRange(start, end);
In a range obtained in this way, I can create a bookmark with no problem. But I can't find the range corresponding to the text I'm looking for in this way. I am trying to create a bookmark this way:
public void CreateBookmarkTest()
{
Document doc = Context.WordDocument;
var searchText = "smth text";
var bookmarkName = "newBookmark";
using Range docRange = doc.Content.Duplicate;
foreach (var paragraph in docRange.Paragraphs)
{
using Range paragraphRange = paragraph.Range;
var text = paragraphRange.Text;
var startParagraph = paragraphRange.Start;
var endParagraph = paragraphRange.End;
var startIndex = text.IndexOf(searchText);
if (startIndex >= 0)
{
text = GetParagraphTextWithHiddenSymbols(paragraphRange, text);
startIndex = text.IndexOf(searchText);
var startFoundRange = startParagraph + startIndex;
var end = startFoundRange + searchText.Length;
paragraphRange.SetRange(startFoundRange, end);
var foundText = paragraphRange.Text;
if (foundText == searchText)
{
doc.Bookmarks.Add(bookmarkName, paragraphRange);
break;
}
}
}
}
private string GetParagraphTextWithHiddenSymbols(Range paragraphRange, string initialText)
{
var text = initialText;
foreach (Field field in paragraphRange.Fields)
{
int index = text.IndexOf(field.Result.Text);
if (index >= 0)
{
text = text.Replace(field.Result.Text, $"{{{field.Code.Text}}} {field.Result.Text}{(char)21}");
}
}
return text;
}
The problem is that, in this case, not always foundText == searchText. Sometimes foundText is offset and I can't figure out how to fix it yet. And this way seems to me slow and suboptimal. Perhaps there is some way to correctly implement search and text replacement (it would be ideal through Find.Execute). I'm also wondering if there's any way to get the areas allowed for editing (or just find out if the current Range is allowed for editing or not)?
I tried to convert using Oscar's idea from the answer below. The code works much better, but it also bugs out on large paragraphs with lots of unprotected input fields.
Thanks a lot for your help, friend!
It should be that hidden text like Field's code text in it results in this problem. Whatever NetOffice, Microsoft.Office.Interop.Word or VBA, etc. You can try my code first. Although it's not a perfect solution so far, notice this block snippet:
at least it points the way to debugging, knowing what the problem is. You can follow this direction for further refinement.
It is a logical necessity that Find objects cannot execute searched when the protection type is like this
wdAllowOnlyFormFields. I think it's because the Find object class is not just a find class, but also includes a replace (edit) facility. Either you need to unprotect it, or change the way it is protected, or choose to use the current alternative, both of which I have conditioned flows in the code above. In addition to using thisforeach paragraphapproach to locate, you can also consider using a regular expression to achieve this. No matter which method you use, you have to do proper processing of the hidden text such as Fields' code text in order to get accurate results.20230712 ContentControls ,either
So the answer is in your file there is no field in it, and all of the file it has is plenty of ContentControl not Fields!
ActiveDocument.ContentControls.Countis 3.ActiveDocument.Fields.Countis 0. The new code is updated above.