|
With Microsoft Word, we can use templates to create documents, and "AutoTexts" to enter text more quickly. I was trying to find out how I could access those features via Interop from a C# application.
The Word.Application object has a property Templates . Also a Word.Document has a property AttachedTemplate .
When I do
Word.Application wordApp = new Word.Application();
the "Templates" does always contain exactly one template - that is Normal.dotm.
When I do
object missing = System.Reflection.Missing.Value;
Word.Application wordApp = new Word.Application();
Word.Document doc = wordApp.Documents.Add(missing, missing, missing, missing);
Template template = doc.get_AttachedTemplate();
template is also always Normal.dotm.
And the same holds true, when I do
Template template = wordApp.NormalTemplate;
Never did I get my other templates.
A Template has an AutoTextEntries property. I find only two entries: my initials and my full name. Never did I see my other AutoTexts.
A Google search was not successful, only lots of hits for opening Word with a template of known path. But I want to enumerate all existing templates, and then get my AutoTexts...
Some further information: on my Win7-64bit computer, Word 2007 is installed. The Interop.Word was generated with Word XP in order to stay compatible with our customers using older software.
Thanks a lot for your help,
Bernhard
|
|
|
|
|
Interop.Word can be such a pain! I am not familiar with the AutoText stuff you are talking about but I have two comments about your post...
1. Word documents by default use the Notmal.dotm template by default then they are created so that would make sense that a call to get_AttachedTemplate() on a new document would return the default template (thus matching .NormalTemplate)
2. In regards to the version of Interop.Word you are using, you will get backwards compatibility by using later versions. It is more the version of Word rather than the version of Windows that you need to cater for. I would recommend getting hold of an Office 2010 version of the Interop and that should span back to work with Office 2003 (if not earlier) - however, not sure if the 64bit Windows will cause an issue with getting this
Illogical thoughts make me ill
modified on Wednesday, February 16, 2011 10:22 AM
|
|
|
|
|
Maybe this can provide a clue? I cannot see the AutoTextEntries property you speak of thou...
foreach(Word.Template template in wordApp.Templates)
{
}
wordApp.Templates supposedly returns all available templates both gloabl and those attached to open documents
Edit:
AutoTextEntries property does not come up in Intellisense, but this does compile...
foreach(Word.Template template in wApp.Templates)
{
foreach(Word.AutoTextEntry entry in template.AutoTextEntries)
{
}
}
Illogical thoughts make me ill
modified on Wednesday, February 16, 2011 10:22 AM
|
|
|
|
|
Thanks for your replies (I had tried those things before I asked the question, and included that very condensed - perhaps too condensed - in my question).
But the point actually is not that I do net see the properties or do not get them at all, but that those properties do not contain the data I expected to be there - perhaps those data are stored somewhere else?
|
|
|
|
|
Meanwhile I had following idea: a Template has a Path property which shows the folder where it is stored, and a FullName property showing the full path including file name. Now I can iterate through all *.dot* files in that directory for getting other templates (and add a button for allowing the user to select a template stored elsewhere).
"AutoText " got a different name for every new version Word (at least for the German edition where it is called "Schnellbausteine" with Word 2007), hence let me explain shortly how to generate and use them.
Imagine, you often have to write "Blah blah blah! " in your documents. Write it once, mark the text, press <ALT><F3>. A dialog pops up where you enter an abbreviation for that text (e.g. "b3"), and save it (default is "Building Blocks.dotx " with Word 2007; it is located in C:\Users\user_name\AppData\Roaming\Microsoft\Document Building Blocks\language_ID ). Next time, you simply type "b3<F3>" and the abbreviation is replaced with the full text.
For that example, I selected "Normal.dotm " for saving it - and guess, now this AutoText shows up in the AutoTexts property of NormalTemplate .
For other AutoTexts, I will open that "Building Blocks.dotx" - but I really do not like that because of the language id in the path name...
If you have a more elegant version, please tell me.
|
|
|
|
|
In my 3 layer application, while I try to compile my business layer, I was getting the following error:
"Task failed because "sgen.exe" was not found, or the correct Microsoft Windows SDK is not installed. The task is looking for "sgen.exe" in the "bin" subdirectory beneath the location specified in the InstallationFolder value of the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0A. You may be able to solve the problem by doing one of the following: 1) Install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5. 2) Install Visual Studio 2008. 3) Manually set the above registry key to the correct location. 4) Pass the correct location into the "ToolPath" parameter of the task. CnCCore"
This is happening only when I try to compile the project in Release Mode. While compiling in Debug mode, there are no issues. It would be great if anybody can provide some solution to resolve this issue.
I googled the error for sometime. Majority of the solution says, to write the key in registry or reinstall the .Net Framework 3.5 version. Is there any other better possible way to avoid this?
I am not sure how to do the fourth resolution. Is this again, writing in registry?
Thanks in advance,
meeram395
Success is the good fortune that comes from aspiration, desperation, perspiration and inspiration.
|
|
|
|
|
Have you checked the path as listed above to ensure that it exists, and that sgen.exe is present in the bin sub-directory?
I must get a clever new signature for 2011.
|
|
|
|
|
meeram395 wrote: This is happening only when I try to compile the project in Release Mode.
That is a clue. Check and compare your debug and release configuration. I'm going to take a wild guess of missing path in release config.
|
|
|
|
|
Am I the only fool using .NET in here?... haha
In the process I´ve explained here the property Process::HasExited is true from the moment the process starts.
The same occurs with the method void extProcessWorkCompleted (System::Object^ /*sender*/, System::ComponentModel::RunWorkerCompletedEventArgs^ e) which is called when the process starts, and not when it actually finishes.
Has this something to do with the process´s code or am I doing something wrong?
|
|
|
|
|
piul wrote: Am I the only fool using .NET in here?
I don't know.
piul wrote: am I doing something wrong?
Most probably.
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
Well... I was trying to make a joke, nothing else. I´m sorry if that dissapointed someone.
|
|
|
|
|
No one is disappointed. It is NOT sensible to rewrite about same question.
And we have Message Type, which has Joke in it.
If you want to Joke, come and have a good joke at Lounge.
|
|
|
|
|
Foolish,
The extProcessWorkCompleted event is raised when the process starts? Definitely someone has got it wrong. Couldn't see any MSDN documentation on extProcessWorkCompleted so I'm guessing it's you.
"You get that on the big jobs."
|
|
|
|
|
piul wrote: The same occurs with the method void extProcessWorkCompleted (System::Object^ /*sender*/, System::ComponentModel::RunWorkerCompletedEventArgs^ e) which is called when the process starts, and not when it actually finishes.
Some executables finish immediately after spawning a child-proces. Can you compare the Process-ID of the executable that you started to the one that seems to be running?
I are Troll
|
|
|
|
|
I have a time consuming process that is called from a Windows forms application and run asynchronously in another thread, when the user clicks on runButton
extProcess = gcnew System::Diagnostics::Process;
extProcess->StartInfo = gcnew System::Diagnostics::ProcessStartInfo;
extProcess->StartInfo->RedirectStandardOutput = true;
extProcess->StartInfo->UseShellExecute = false;
extProcess->StartInfo->FileName = EXTPROC_EXE;
extProcess->StartInfo->CreateNoWindow = true;
extProcess->OutputDataReceived += gcnew System::Diagnostics::DataReceivedEventHandler (this, &Form1::StdoutHandler);
try
{
extProcessThread->RunWorkerAsync();
The thread is launched and the standard output is read, to be shown in real time in a textBox in the main window
void extProcessThreadDoWork (System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e)
{
extProcess->Start();
extProcess->BeginOutputReadLine();
}
void Form1::StdoutHandler (Object ^ sender,
System::Diagnostics::DataReceivedEventArgs ^output)
{
textBox->AppendText (output->Data + "\n");
}
The problem comes in this last line. An exception is launched "Control accessed from a thread other than the thread it was created on"
I do understand why, but I don´t know how to solve it...
|
|
|
|
|
|
You need to have a look at the invoke methods in the article shown by the other poster
MSDN: Look at the example at the bottom of the page[^]
As barmey as a sack of badgers
Dude, if I knew what I was doing in life, I'd be rich, retired, dating a supermodel and laughing at the rest of you from the sidelines.
|
|
|
|
|
This[^] explains it, however all examples are C# or VB.NET; same principles apply to C++/CLI.
Amd a BackgroundWorker's ProgressChanged and RunWorkerCompleted handlers don't have the cross-thread problem as they run on the thread that created the BGW, which normally is the main thread. That is one of the big advantages of BGW.
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
I have a windows Forms application that calls a mathematical calculations .exe
superMinerProcess->Start();
superMinerProcess->BeginOutputReadLine();
while (!superMinerProcess->HasExited)
{
If I set a breakpoint after the Start(); the program only reaches it after the process has finished. I don't understand... Any idea?
|
|
|
|
|
That is inconclusive. Where is this code located? what is in the while loop? what is it you are trying to achieve?
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
The application is a dialog that runs a long mathematical calculation (the external process, an independent executable) when pressing a Run button. Hence, this code is located within the buttonRun_Click function.
while (!superMinerProcess->HasExited)
{
if (processCancelled)
{
processCancelled = false;
break;
}
}
processCancelled is set to true in buttonCancel_Click . What I´m trying is to be able to kill the process when the user clicks on the Cancel button. I´ve tried writing superMinerProcess->Kill() in buttonCancel_Click but it won´t work because the Cancel button is just not clickable while the process is running.
Here´s the rest of relevant code of the process
superMinerProcess = gcnew System::Diagnostics::Process;
superMinerProcess->StartInfo = gcnew System::Diagnostics::ProcessStartInfo;
superMinerProcess->StartInfo->RedirectStandardOutput = true;
superMinerProcess->StartInfo->UseShellExecute = false;
superMinerProcess->StartInfo->FileName = SUPERMINER_EXE;
superMinerProcess->StartInfo->CreateNoWindow = true;
superMinerProcess->StartInfo->Arguments = getArguments();
superMinerProcess->OutputDataReceived += gcnew System::Diagnostics::DataReceivedEventHandler (&Form1::StdoutHandler);
|
|
|
|
|
OK, that is quite wrong for several reasons:
1.
the while loop has no blocking calls, so it will spin at full speed, consuming all cycles of one (perhaps the only) core. If you must have a polling loop like that, at least slow it down by inserting say Thread.Sleep(100);
However it is in general better to avoid a polling loop.
2.
It is not OK to halt the main thread like that, as the whole GUI will freeze. If e.g. another window pops up on top of your app, and then goes away again, your app won't repaint itself.
The correct approach would be:
- to have a separate thread (I suggest a BackgroundWorker) which launches the process, captures its output, and waits for its termination;
- to launch this thread from your button click handler (possibly also disabling said button, turning the cursor into a wait cursor, etc);
- to have a delegate dealing with intermediate results (maybe showing them in a ListBox);
- to have another delegate dealing with the termination of the process (restoring the GUI back to normal).
BTW: said thread would not need a polling loop on superMinerProcess->HasExited , as it could use superMinerProcess->WaitForExit()
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
I like the idea of having the process in a different thread. It does work much better.
However I have a problem when it comes to display in my form the text captured from the process. I have a delegate superMinerThreadWorkCompleted in charge of displaying the results.
void superMinerThreadWorkCompleted (System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e)
{
textBox = "Process text";
}
But I get the error
C3352: superMinerThreadWorkCompleted(System::Object ^,System::ComponentModel::DoWorkEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)'<br />
1>Form1.cpp in the line
superMinerThread->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler (&Form1::superMinerThreadWorkCompleted);
I can fix this by making the delegate static but then I cannot modify member class textBox .
What could be the way around this?
|
|
|
|
|
piul wrote: DoWorkEventArgs
piul wrote: RunWorkerCompletedEventArgs
these are different! the former is just wrong.
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
Changed the delegate to
void superMinerThreadWorkCompleted (System::Object^ sender,
System::ComponentModel::RunWorkerCompletedEventArgs^ e)
{}
and still got the same error
'void SuperMinerGUI::Form1::superMinerThreadWorkCompleted(System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)'<br />
1>Form1.cpp
|
|
|
|