Microsoft.Office.Interop.Word version 14.0.0.0. .NET 4.0 VS 2010.
The MS Word API's Style class has a BaseStyle property that can be used to set the style's base (based on) style. That property works fine for me in VBA.
However from C# using Word interopt there is no BaseStyle property. However, there are two (undocumented as far as I can tell) functions set_BaseStyle() and get_BaseStyle().
When I call set_BaseStyle() I get a COMException with the message:
"This command is not available."
I think this means that the COM interface does not support the procedure (command). But why? Why does it appear in intellisense and compile? Is there a workaround?
This simple example works on my machine (VS 2012, Office 2007)
Application application = new Application {Visible = true};
string styleName1 = "Heading 1";
object styleNameObject1 = styleName1;
string styleName2 = "Heading 2";
object styleNameObject2 = styleName2;
var document = application.Documents.Add();
document.Select();
application.Selection.set_Style(ref styleNameObject2);
Style style = (Style)application.Selection.get_Style();
Style baseStyle = style.get_BaseStyle();
style.set_BaseStyle(ref styleNameObject1);
application.Selection.Range.Text = "This is the title";
application.Quit(false);
So the problem probably lies in your setup. The message is rather vague and it says word cannot do stuff, for other examples look at C# and Word2010 : DeleteAllComments throws "This command is not available." or search and replace in Word documents via .NET automation.
Is the file readonly? Does it happen with other styles or simpler files (such as my example)? Are Macros allowed in Word?
I found the problem.
The sample code posted by Vadim was a big help, as it did work, and I slowly slowly converted in to my code and eventually broke it, them moved back and forth until I homed in on the problem.
However, I can't explain what I found!
I was specifying all parameters when I opened the (existing) document with Application.Documents.Open(). It turns out that if I specify false (0) for the isvisible parameter, the code fails. If I secify true (-1) it works.
Note that in either case I can make 100s of other changes to the document. For some reason I cannot change the base style if it is invisible.
strange.
Thanks for your help.
Related
I am working on converting an application to .Net Core 3.1, and in my class library I am generating a PDF form from an existing template, and filling that form with data. In ITextSharp, the predecessor to IText7, the PdfAcroForm static method ".GetAcroForm()" worked perfectly, but in the current version of iText7 (7.1.12) a Null Reference Exception is thrown. I have followed the documentation to the best of my ability, but I am unsure how to continue. Any suggestions would be appreciated.
NOTE: The template path exists, the new document shows that it has been filled properly, and it is impossible to "new" a PdfAcroForm, you are required to use the static .GetAcroForm() method.
A null check will not solve this issue, as the object should never be null. The documentation indicates that the .GetAcroForm() method will create a new form if the parameter "createNotExist" is set to true, which I have done here.
I have researched and have located an issue on the iText GitHub that indicates that this issue was "fixed" around a year ago: https://github.com/itext/itext7/pull/44#issue-351612749
The following is the method which prepares the forms:
public string DocumentGenerator(string templatePath, FormFieldSet[] formFieldSet, bool useSpecailOutputPath)
{
if(!File.Exists(templatePath))
{
throw new Exception("The template file provided does not exist: MC-071(iText)");
}
string newFile = useSpecailOutputPath ?
m_SpecialOutputPath :
Path.GetTempPath() + Guid.NewGuid().ToString() + ".pdf";
try
{
PdfDocument newDocument = new PdfDocument(new PdfReader(templatePath), new PdfWriter(newFile));
PdfAcroForm acroForm = PdfAcroForm.GetAcroForm(newDocument, true); // <=== Exception Thrown Here
foreach (FormFieldSet fs in formFieldSet)
{
acroForm.GetField(fs.FieldName).SetValue(fs.FillValue);
}
// Sets form flattening
acroForm.FlattenFields();
// Closes and writes the form
newDocument.Close();
return newFile;
}
catch { return string.Empty; };
}
Any suggestions would be greatly appreciated
I had the same problem, and after digging down all the way to iText7's internal objects and methods, I finally "solved" my problem.
Apparently iText has some internal errors/exceptions that they are just sort of "skipping" and "pushing past", because I realized by accident that I had "Enable Just My Code" in Visual Studios disabled, and so my system was trying to debug iText7's code as well as mine. The moment that I re-enabled it in my Visual Studio settings (Tools > Options > Debugging > General > Enable Just My Code checkbox), the problem magically went away.
So I spent four hours trying to troubleshoot a problem that was in THEIR code, but that they apparently found some way to work around and push through the method anyways even on a null reference failure.
My convert to PDF function is now working just fine.
Just an update to anyone looking for this issue. This is a known issue and is fixed in the current development branch. You are safe to bypass the exception in visual studio until it is corrected. This has no negative impact on the functionality and is the result of a misplaced return in the original iText7 source.
I have the following code (simplified to show the problem):
var wdApp = new Application();
var wdDoc = wdApp.Documents.Open("C:\foo.docx");
wdApp.StatusBar = "Updating...";
var rng = wdDoc.Range(10, 10);
if ((bool)rng.Information(WdInformation.wdWithInTable))
{
}
//StatusBar value is gone...
What could be the reason?
How can I prevent it?
Do you know of other situations where this can happen?
Here screenshots of the problem
1 F10 (step over) later
Edit:
The provided code uses NetOffice and not the interop library from Microsoft directly, therefor the syntax is correct. You may notice in the provided screenshots that they are taken from a running application. Breakpoint, highlighting of current line of code executing, aswell as the actual result of the code in the word application on the right. Where at first there is the desired statusbar "Tabelle 8 von 17 wird neu erstellt." (Table 8 out of 17 is recreating) and at the next step my statusbar is gone and its the default stuff "165 von 8227 Wörtern" (165 out of 8227 words)
What could be the reason?
I believe this is to do with the library you are using. I tested your code but with the Word Interop library, and the only way I could get the status bar to reset was to manually click/type within the Word window.
How can I prevent it?
I would say take a look into the code base of library you are using. It is likely that it is doing something that is causing the behaviour. Unless there is a specific reason you are using NetOffice I would suggest switching to the either the standard Interop or VSTO.
Do you know of other situations where this can happen?
As above, I could only get the status bar to reset if I manually carried out some sort of input into the window.
I am currently in the need to compare two Microsoft Word documents with Microsoft.Office.Interop.Word. I've found the Application.CompareDocument method, which does exactly what I want. The following C# source code (snippet) compares a document saved in the filesystem with the current active document and opens the result in a new document:
using Word = Microsoft.Office.Interop.Word;
// [...]
Word.Document originalDocument = this.application.Documents.Open(filePath, ReadOnly: true, Visible: false);
Word.Document diffDocument = this.application.CompareDocuments(
originalDocument,
this.application.ActiveDocument);
((Word._Document)originalDocument).Close(SaveChanges: false);
// TODO Activate two built-in Microsoft Word buttons.
// [...]
But I also need to activate two built-in buttons in the view of the newly created Word document. After searching on MSDN for a while, I am unable to find a way to achieve what I want. I've added two screenshots to this question, which display the built-in buttons I want to activate (sadly, I am using the German version of Microsoft Word 2010, so I don't know what the exact translations are).
"Quelldokumente anzeigen" (could be translated as "Display source documents"). I need to activate the button "Beide anzeigen" (could be translated as "Display both").
"Überarbeitungsbereich" (could be translated as "Revision pane"). I need to activate the button "Überarbeitungsbereich vertikal..." (could be translated as "Vertical revision pane...").
To conclude, I want to know how I can modifiy the state (either directly or indirectly via an method call) of these two buttons.
EDIT (2013-08-03)
The revisions pane can be set via the following method:
diffDocument.ActiveWindow.View.SplitSpecial = Word.WdSpecialPane.wdPaneRevisionsVert;
I am still searching for a solution to display both the source document and revised document panes.
EDIT (2013-08-05)
The show source documents button can be modified to show both source documents via the following method:
diffDocument.ActiveWindow.ShowSourceDocuments = Word.WdShowSourceDocuments.wdShowSourceDocumentsBoth;
Possible solutions of your problems:
Ad 1. but first, you need to open your documents with ReadOnly: false while,according to both C# and VBA test it will not work when you set parameters to ReadOnly: true:
((Word._Document)diffDocument).Windows.CompareSideBySideWith(originalDocument);
Ad 2. this time you need to refer to window object of Word Application. Here is code for active window:
appWRD.ActiveWindow.View.SplitSpecial = Word.WdSpecialPane.wdPaneRevisionsVert;
where: appWRD is Word.Application in my code.
Ad 1 again. (one above was a result of misunderstanding).
According to some test this code should give you what you need:
appWRD.ActiveWindow.ShowSourceDocuments = Word.WdShowSourceDocuments.wdShowSourceDocumentsBoth;
My plan:
I'm trying to setup my C# project to communicate with Nodebox to call a certain function which populates a graph and draws it in a new window.
Current situation: [fixed... see Update2]
I have already included all python-modules needed, but im still getting a
Library 'GL' not found
it seems that the pyglet module needs a reference to GL/gl.h, but can't find it due to IronPython behaviour.
Requirement:
The project needs to stay as small as possible without installing new packages. Thats why i have copied all my modules into the project-folder and would like to keep it that or a similar way.
My question:
Is there a certain workaround for my problem or a fix for the library-folder missmatch.
Have read some articles about Tao-Opengl and OpenTK but can't find a good solution.
Update1:
Updated my sourcecode with a small pyglet window-rendering example. Problem is in pyglet and referenced c-Objects. How do i include them in my c# project to be called? No idea so far... experimenting alittle now. Keeping you updated.
SampleCode C#:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(null);
ScriptRuntime runtime = new ScriptRuntime(setup);
ScriptEngine engine = Python.GetEngine(runtime);
ScriptSource source = engine.CreateScriptSourceFromFile("test.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
SampleCode Python (test.py):
from nodebox.graphics import *
from nodebox.graphics.physics import Vector, Boid, Flock, Obstacle
flock = Flock(50, x=-50, y=-50, width=700, height=400)
flock.sight(80)
def draw(canvas):
canvas.clear()
flock.update(separation=0.4, cohesion=0.6, alignment=0.1, teleport=True)
for boid in flock:
push()
translate(boid.x, boid.y)
scale(0.5 + boid.depth)
rotate(boid.heading)
arrow(0, 0, 15)
pop()
canvas.size = 600, 300
def main(canvas):
canvas.run(draw)
Update2:
Line 139 [pyglet/lib.py] sys.platform is not win32... there was the error. Fixed it by just using the line:
from pyglet.gl.lib_wgl import link_GL, link_GLU, link_WGL
Now the following Error:
'module' object has no attribute '_getframe'
Kind of a pain to fix it. Updating with results...
Update3:
Fixed by adding following line right after first line in C#-Code:
setup.Options["Frames"] = true;
Current Problem:
No module named unicodedata, but in Python26/DLLs is only a *.pyd file`. So.. how do i implement it now?!
Update4:
Fixed by surfing: link text and adding unicodedata.py and '.pyd to C# Projectfolder.
Current Problem:
'libGL.so not found'... guys.. im almost giving up on nodebox for C#.. to be continued
Update5:
i gave up :/ workaround: c# communicating with nodebox over xml and filesystemwatchers. Not optimal, but case solved.
-X:Frames enables the frames option as runtime (it slows code down a little to have access to the Python frames all the time).
To enable frames when hosting you just need to do:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(new Dictionary<string, object>() {
{ "Frames", true }
});
Instead of the null that you're passing now. That's just creating a new dictionary for the options dictionary w/ the contents "Frames" set to true. You can set other options in there as well and in general the -X:Name option is the same here as it is for the command line.
I am trying to put version information to my C# GUI framework retrieved from the latest ClearCase label. This was originally done from Visual Soursafe as below.
vssDB = new VSSDatabaseClass();
vssDB.Open( databaseName, "vssadmin", "vssadmin" );
VSSItem item = vssDB.get_VSSItem( #"$\BuildDCP.bat", false );
foreach(VSSVersion vssVersion in item.get_Versions(0))
{
// Pull the first non-blank label and use that
if ( vssVersion.Label != "" )
{
labelID = vssVersion.Label.ToString();
break;
}
}
I am trying to do something similar using ClearCase since we changed our source code control from VSS to CC. Any help would be greatly appreciated.
Thanks!
I believe this could be better achieved through a script, which would be called from your C# program.
But you may be able to directly call some COM objects, through the CAL interface provided with ClearCase.
The documentation for the interface can be accessed through ClearCase help (Start>Programs>Rational ClearCase>ClearCase Help), where there's an entry for "ClearCase Automation Library (CAL)". An alternate path is to look in the ClearCase/bin directory for "cc_cal.chm".
In VB, with CAL API, that would give something like:
Dim CC As New ClearCase.Application
Dim labelID As String
Set aVersion = CC.Version("[Path-To]\BuildDCP.bat");
Set someLabels = Ver.Labels;
If (someLabels.Count > 0) Then
' the first label listed is the most recently applied
labelID = someLabels.Item(1).Type.Name
EndIf
I really wish that the COM interfaces had better documentation, or were more obvious. Or that the code to ClearCase Explorer or Project Explorer were open source.
I've done a few cool things, but I pretty much started by adding COM references to my C# project, and then started screwing around with the interfaces I found.
Good luck!