Microsoft.Office.Interop.Word "Cannot activate application" - c#

We are having a problem experienced by a few users when attempting to launch Word from our application via the office interop:
using Word = Microsoft.Office.Interop.Word;
public void ShowWord()
{
_word = new Word.ApplicationClass();
_word.Visible = true;
_word.Activate();
}
If word is not always open a COM exception is thrown stating "Cannot activate application." Adding a Thread.Sleep(1000) before calling _word.Activate() prevents this, but obviously is not ideal.
public void ShowWord()
{
_word = new Word.ApplicationClass();
_word.Visible = true;
Thread.Sleep(1000)
_word.Activate();
}
Has anyone seen this before and knows what is causing this and what the right way to fix this is?

We encountered a similar issue, and it seems that Word is asynchonously waiting for the OS to show its window. The way we resolved this is by waiting until the Visible property returns true:
public void ShowWord()
{
_word = new Word.Application();
_word.Visible = true;
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
while (!_word.Visible && sw.ElapsedMilliseconds < 10000)
{ /* Just Wait!! (at most 10s) */}
_word.Activate();
}
Hope this helps somebody.

Does your application have permission to activate the Word COM object?
Check in DCOMCNFG what the local activation security requirements are.
However, not sure why your Thread.Sleep(1000)would allow it to work?

Related

Make application close when .exe is executed again

I'm currently working on a simple converter tool and was wondering if it's possible to make the application close if I run the .exe again. Some kind of "if two instances run -> close both".
I need this function because I run the application via a shortcut-button inside a third party program. So I would like if my converter app closes once I press this shortcut-button again.
I know it sounds counter intuitive running the exe again to close, but i have to have my app work the same way as the integrated tools in the third party program, and this involves opening and closing tools by pressing their respective toggle-buttons. I can't add a plug-in running inside the third party program, but i CAN add a shortcut button next to the integrated tools. It's a work around, but it will at least act like a toggle button.
You could do something like this:
Process currentProcess = Process.GetCurrentProcess();
bool suocide = false;
foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
{
if (process.MainModule.FileName == currentProcess.MainModule.FileName && process.Id != currentProcess.Id)
{
process.CloseMainWindow();
process.Close();
//process.Kill(); or you can do kill instead
suocide = true;
}
}
if (suocide)
currentProcess.Kill(); // you probably don't care about new process as it is just for closing purpose but if you do then do a proper application exit
You can put it inside your window constructor.
Step 1 Identify a 2nd instance:
I'd recommend the MUTEX answer in this question:
How can I prevent launching my app multiple times?
Step 2 Get that first instance closed
Although the MUTEX answer identifies a second instance, it gives no way to find it and tell it to close.
Solution: Listen with a named pipe in the app (first instance the ClosEE):
//using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public static class SomeClass
{
public static void SomeMethod()
{
Threading.Thread t = new Threading.Thread(() =>
{
try {
while (true) {
dynamic server = new NamedPipeServerStream("Closer", PipeDirection.InOut, -1);
server.WaitForConnection();
if (!server.IsConnected)
return;
dynamic reader = new IO.StreamReader(server);
dynamic casetxt = reader.ReadToEnd();
server.Close();
RootForm.Invoke(() =>
{
if (casetxt == "End") {
System.Environment.Exit(0);
}
});
}
} catch (Exception ex) {
// try/catch required in all child threads as error silently ends app.
// log it...
}
});
t.IsBackground = true;
t.Name = "EnderListener";
t.Start();
}
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
Then when you detect a second instance via the Mutex, send this message from the 2nd instance the "Closer":
dynamic serverloopcount = 1;
dynamic iteration = 1;
dynamic GotServerCount = false;
do {
NamedPipeClientStream client = new NamedPipeClientStream("Closer");
client.Connect();
if (!GotServerCount) {
GotServerCount = true;
serverloopcount = client.NumberOfServerInstances;
}
dynamic reader = new IO.StreamReader(client);
dynamic writer = new IO.StreamWriter(client);
writer.WriteLine("End");
writer.Flush();
writer.Close();
client.Close();
iteration += 1;
} while (iteration <= serverloopcount);
Good luck.

Outlook 2010 VSTO - Non-Admin users receive "The operation failed." when Task.Save is called

I have an Outlook add-in that is working successfully for about 100 users. It interacts with our application and creates/updates Tasks and Appointment items. However, one client cannot get it to work for anyone who is not a network administrator. Through some logging, I can see that it works fine until it gets to the part where it should save the Task, and then it throws the infamous "The operation failed." error. I have tried in vain to get more error details by investigating inner exceptions and such, but "The operation failed." is all I can seem to get out of it.
To make it simpler to debug, I eliminated our application from the picture and wrote them a test add-in that just creates 9 tasks (hard-coded to "Task 1", "Task 2", etc.) and it fails in the same place with the same error. I have asked them to write a macro to see if a macro is able to create tasks for these users. I am awaiting their reply on that.
Anyway, I have been on MSDN for over a month trying to get help on the issue and nobody has been able to help. I am hoping someone here could shed some light. If you can provide any insight on what might be happening or suggestions to help me track down the problem, it would be greatly appreciated!
This is the function I am using to create the sample tasks in the test add-in:
private void CreateTasks()
{
int i = 1;
Outlook.TaskItem t = null;
Outlook.UserProperties ups = null;
Outlook.UserProperty up = null;
string name = string.Empty;
while (i < 10)
{
name = string.Format("Task {0}", i.ToString());
t = Application.CreateItem(Outlook.OlItemType.olTaskItem);
t.Subject = name;
t.Status = Outlook.OlTaskStatus.olTaskNotStarted;
t.Body = string.Format("Task {0} description", i.ToString());
t.Categories = "Test Task";
t.Importance = Outlook.OlImportance.olImportanceNormal;
t.ActualWork = 0;
t.TotalWork = 5 * 60;
//mimic dates that might come in main add-in
DateTime st = Convert.ToDateTime("12/10/2013");
st = st.AddDays(i);
t.StartDate = st;
DateTime end = Convert.ToDateTime("01/02/2014");
end = end.AddDays(i);
string EP = end.ToShortDateString() + " 5:00:00 PM";
end = Convert.ToDateTime(EP);
t.DueDate = end;
//mimic how we keep track of our items in the main add-in
ups = t.UserProperties;
up = ups.Find("ID");
if (up == null)
{
up = ups.Add("ID", Outlook.OlUserPropertyType.olText);
}
up.Value = string.Format("ID {0}", i.ToString());
//This is where the "The Operation Failed." error occurs on every single task.
try
{
((Outlook._TaskItem)t).Save();
}
catch (Exception ex)
{
//logs message to file
}
//Release objects
if (up != null) Marshal.ReleaseComObject(up);
if (t != null) Marshal.ReleaseComObject(t);
i++;
}
GC.Collect();
}
According to MSDN:
Saves the Microsoft Outlook item to the current folder or,
if this is a new item, to the Outlook default folder for the item type.
Does the "non administrator user" have access to this folder?
I'd hedge a bet it is something to do with Access permissions. This would be the first place to start.
Is this in an Exchange mailbox? I've seen this error before when connection to the server becomes spotty. If it is, see if the error occurs if you switch from cached mode to online mode. I don't think it's a code issue.

Duplicate process (strange issue)

I am trying to prevent opening help file more than once.
This is the method I am using:
public void openHelp()
{
int count = 0;
string helpPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + #"\MyApp\Help\eHelp.chm";
System.Diagnostics.Process[] helpProcs = System.Diagnostics.Process.GetProcesses();
foreach (System.Diagnostics.Process proc in helpProcs)
{
if (proc.MainWindowTitle == "Sample App Help")
{
count++;
}
}
if (count == 0)
{
System.Diagnostics.Process.Start(helpPath);
}
else
{
}
}
The idea is, if you find the process with the same MainWindowTitle, then do not start a new one.
However, this is not reliable. In some cases it still starts the process, even though one is already running. Is there an issue with a logic?
Thank you.
P.S. Of course the MainWindowTitle is "Sample App Help", at least that is what I see while debugging.
Update:
Issue only occurs when user has minimised help file. So I suspect something happens in the system and I need to check something. Any suggestions?
The Remarks section in Process.MainWindowTitle contains the following note:
The main window is the window that currently has the focus; note that
this might not be the primary window for the process. You must use the
Refresh method to refresh the Process object to get the current main
window handle if it has changed.
Could this perhaps be the cause of your problem?
What about keeping the process id of a newly started help viewer and before starting another one, just check if the old one is still alive.
int id = ...
try
{
var proc = Process.GetProcessById(id);
}
catch
{
// no process running with that id
}

Can I use SetErrorMode in C# process?

I'm preparing for writing an online judge core,
A program that can compile user's code and run the program to check the answer like uva online judge.
And I'm having problem in catching the exception of submit program like below.
int main()
{
while(~scanf("%d %d",n,&m))
{
printf("%d\n",n+m);
}
return 0;
}
it's access denied at first line because it scan an integer to error position.
how can I catch runtime error for my process?
I used to use "try catch" to catch the exception,
but it didn't reply anything about runtime error.
so I only check the exit code of the submit program although it's not a good method to check except for a process..
and it shows like photo
I have to close the error message box manually,
and I find a solution that is to use a SEH Handler DLL for the process.
SetErrorMode(SEM_NOGPFAULTERRORBOX);
but I don't know how to use it in C# process.
and below is my code of judger
timer = new Stopwatch();
timer.Reset();
submitProg = new Process();
submitProg.StartInfo.FileName = outputFile;
submitProg.StartInfo.UseShellExecute = false;
submitProg.StartInfo.CreateNoWindow = true;
submitProg.StartInfo.RedirectStandardInput = true;
submitProg.StartInfo.RedirectStandardOutput = true;
submitProg.StartInfo.RedirectStandardError = true;
submitProg.StartInfo.ErrorDialog = false;
submitProg.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
submitProg.EnableRaisingEvents = true;
submitProg.Start();
timer.Start();
progInput = submitProg.StandardInput;
progOutput = submitProg.StandardOutput;
progInput.Write(inputStream.ReadToEnd());
submitProg.StandardInput.Close();
while (!submitProg.HasExited)
{
peakPagedMem = submitProg.PeakPagedMemorySize64;
peakVirtualMem = submitProg.PeakVirtualMemorySize64;
peakWorkingSet = submitProg.PeakWorkingSet64;
if (peakPagedMem > memLimit)
{
submitProg.Kill();
}
if (timer.ElapsedMilliseconds > timeLimit)
{
timeLimitExceed = true;
submitProg.Kill();
}
}
timeUsed = timer.ElapsedMilliseconds;
timer.Stop();
if(submitProg.ExitCode!=0)systemRuntimeError = true;
Thanks for helping, and so sorry for my poor English.
==================================
p.s.
the question is how can I set error mode for the child process in C#.
My English is not good enough to explain the problem, so sorry.<(_ _)>
If you mean the Win32 API function SetErrorMode then you'll need to use P/Invoke, which is easy with such a simple signature:
[DllImport("kernel32.dll")]
static extern ErrorModes SetErrorMode(ErrorModes uMode);
[Flags]
public enum ErrorModes : uint {
SYSTEM_DEFAULT = 0x0,
SEM_FAILCRITICALERRORS = 0x0001,
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
SEM_NOGPFAULTERRORBOX = 0x0002,
SEM_NOOPENFILEERRORBOX = 0x8000
}
(The Site http://www.pinvoike.net/ is always a good place to start to get the right declaration.)
You cannot set the error mode in another process without injecting code into that process. Which is impossible to do easily in C#. It isn't going to work well in C/C++ either, these kind of programs don't live long enough to give you time to inject.
It doesn't solve your problem anyway, you also have to protect against programs that never exit after they got stuck in an endless loop. The simple solution is to give every program a limited amount of time to execute. Say 10 seconds. If it doesn't complete then Process.Kill() it and declare a failure. This will also take care of the programs that bomb with a message box.
Trivial to implement with the Process.WaitForExit(milliseconds) overload.

C# SAPI in a web service

var speechEngine = new SpVoiceClass();
SetVoice(speechEngine, job.Voice);
var fileMode = SpeechStreamFileMode.SSFMCreateForWrite;
var fileStream = new SpFileStream();
try
{
fileStream.Open(filePath, fileMode, false);
speechEngine.AudioOutputStream = fileStream;
speechEngine.Speak(job.Script, SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak | SpeechVoiceSpeakFlags.SVSFDefault); //TODO: Change to XML
//Wait for 15 minutes only
speechEngine.WaitUntilDone((uint)new TimeSpan(0, 15, 0).TotalMilliseconds);
}
finally
{
fileStream.Close();
}
This exact code works in a WinForm app, but when I run it inside a webservice I get the following
System.Runtime.InteropServices.COMException was unhandled
Message="Exception from HRESULT: 0x80045003"
Source="Interop.SpeechLib"
ErrorCode=-2147201021
Does anyone have any ideas what might be causing this error? The error code means
SPERR_UNSUPPORTED_FORMAT
For completeness here is the SetVoice method
void SetVoice(SpVoiceClass speechEngine, string voiceName)
{
var voices = speechEngine.GetVoices(null, null);
for (int index = 0; index < voices.Count; index++)
{
var currentToken = (SpObjectToken)voices.Item(index);
if (currentToken.GetDescription(0) == voiceName)
{
speechEngine.SetVoice((ISpObjectToken)currentToken);
return;
}
}
throw new Exception("Voice not found: " + voiceName);
}
I have given full access to USERS on the folder C:\Temp where the file is to be written. Any help would be appreciated!
I don't think the System.Speech works in windows service. It looks like there is a dependency to Shell, which isn't available to services. Try interop with SAPI's C++ interfaces. Some class in System.Runtime.InteropServices may help on that.
Our naming convention requires us to use a non-standard file extension. This works fine in a Winforms app, but failed on our web server. Changing the file extension back to .wav solved this error for us.
Make sure you explicitly set the format on the SPFileStream object. ISpAudio::SetState (which gets called in a lower layer from speechEngine.Speak) will return SPERR_UNSUPPORTED_FORMAT if the format isn't supported.
I just got the webservice to spawn a console app to do the processing. PITA :-)

Categories

Resources