Connecting to an existing Outlook process - c#

I'm building an application that opens existing mail messages in Outlook. The user may or may not already be running Outlook. All works well if Outlook is not running, but if it's already running I get a COM error (80080005). The internet seems to indicate that this can happen if the existing Outlook process is running with a higher permission level than the app that tries to bind to it.
Is there some other way for me to ask Outlook to open a message, or do I just need to make sure I match permission levels?
Thanks,
-Patrick
EDIT Adding code to original question, as Stack Overflow does not permit meaningful formatting in comments.
I was originally doing the following:
var outlook = new Outlook.Application();
That line works in all cases except the case where I've launched Outlook prior to launching my application. In that case, I get the aforementioned 80080005 error code.
I've changed this to be a bit more COM-explicit:
Application outlook;
try
{
outlook = (Application)Marshal.GetActiveObject("Outlook.Application");
}
catch (COMException ex)
{
if (ex.ErrorCode == -2147221021)
outlook = new ApplicationClass();
else
throw;
}
However, that code still does not quite work -- if Outlook is running, I trap an exception whose ErrorCode is 0x800401E3 (MK_E_UNAVAILABLE). But when I attempt to create the new ApplicationClass object, I still get the same 80080005 error code.
I've also tried putting the following into the catch block instead of the new ApplicationClass() line, but there's no difference in behavior:
outlook = (Application) Activator.CreateInstance(
Type.GetTypeFromProgID("Outlook.Application"));

Turns out that the cause of the problem was the debugger -- I was launching Word from Visual Studio's debugger. When launching Word via normal pathways, the 80080005 code goes away.
-Patrick

Without seeing your code I'm guessing, but it sounds like you are calling CreateObject(). You need to call GetObject() if Outlook is already running.
First, use GetObject to see whether Outlook is already running (You need to catch
the error).

Related

The process cannot acces the file as it is being used by another process C#

I have a .Net console application. I would like to catch any exceptions occur during the execution and write it to a text file. If there is any entry on the file before, I am getting
The process cannot acces the file as it is being used by another process.
I tried closing the connections as well below but still it's showing the same error.
catch (Exception ex)
{
using (System.IO.StreamWriter writeerror = new System.IO.StreamWriter(_txtError))
{
writeerror.WriteLine(ex.Message);
writeerror.Flush();
writeerror.Close();
}
}
Note: At the start of the program execution I am deleting the file and regenerate if any error occurs.
Finally I found where was the issue. At the end of all the functions I had a send e-mail function which send the log file as attachment to a group. The problem is from my workstation I can't send emails. Once the deploy the code in server, e-mail task will function as it's supposed to do. I had a similar catch stmt for Send email task and when it fails it tries to write the same error file I'm ATTACHING in the email task. Once i removed the catch logic the issue is resolved. Whew!! I know.. It's a stupid mistake! :( Learnt something from this mistake

Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE)) when running through Windows Service?

i am try to hook to outlook application from windows Service but getting an exception Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE)) here is my code.
public void ItemSendEvent()
{
try
{
if (Process.GetProcessesByName(ApplicationConstants.OUTLOOK_PROCESS_NAME).Count() > 0)
{
// If so, use the GetActiveObject method to obtain the process and cast it to an Application object.
outlookApplication = Marshal.GetActiveObject(ApplicationConstants.OUTLOOK_APPLICATION_NAME) as Microsoft.Office.Interop.Outlook.Application;
Microsoft.Office.Interop.Outlook.NameSpace nameSpace = outlookApplication.GetNamespace(ApplicationConstants.OUTLOOK_NAME_SPACE);
nameSpace.Logon("", "", Missing.Value, Missing.Value);
nameSpace = null;
outlookApplication.ItemSend += outlookApplication_ItemSend;
}
log.Info("Outlook Item Send event registered successfully.");
}
catch (System.Exception ex)
{
log.Error("Exception occurred while registering Outlook Item Send event. " + ex.Message);
}
}
but the same code when i launch it through Windows Form Application its working Fine. i gone through some site's and they were saying that outlook object is not in ROT Table. what will be the solution.
Outlook, or any other Office app, cannot run in a Windows service even if your service is running as an interactive user. Only Extended MAPI (C++ or Delphi only) or an Extended MAPI wrapper like Redemption (I am its author - its RDO family objects) can be used in a service.
In your particular case, it looks like you are trying to trap the Application.ItemSend event. There is absolutely no reason to create a Windows service for that. Create a COM addin - it will be loaded by Outlook and run as long as Outlook itself is running in the same process in the same security context.
Two common issues could cause this.
The first would be that you are running Visual Studio in Administrator mode and you are starting your program from within VS, and the Office application is not. To fix that, you need to run your Office application with elevated privileges, in Administrator mode, as well.
The second could be caused by the application not being fully started/loaded when you call Marshal.GetActiveObject(...).
Old, but still significant thread.
I collided with this error when tried to access Outlook data using the MS example.
Treating the error in a Try / Catch block and offering the option of newing Outlook solves the problem:
const int ERROR_HRESULT_0x800401E3_MK_E_UNAVAILABLE= -2147221021;
Outlook.Application application = null;
// Check whether there is an Outlook process running.
if (Process.GetProcessesByName("OUTLOOK").Any())
{
try
{
// If so, use the GetActiveObject method to obtain the process and cast it to an Application object.
application = Marshal.GetActiveObject("Outlook.Application") as Outlook.Application;
}
}
catch (Exception ex)
{
//This is the branch where you can get correctly the current Outlook instance
if (ex.HResult == ERROR_HRESULT_0x800401E3_MK_E_UNAVAILABLE)
{
application = new Outlook.Application();
}
}
}
else
{
application = new Outlook.Application();
}
Although the newing trick functions, no other Outlook instance is created, as Outlook behaves like a Singleton.
I only tested it with Office 365 64 bits installed.
you don't need to have your application as a service to get it on the background ...
if your winform work well, just put your winform in background running on the systray for instance

How to close outlook application opened by another user

I have a situation,I have an application which sends mail using OUTLOOK,problem is while I'm trying to send mails from the application which is opened as Administrator it throws exception
Retrieving the COM class factory for component with CLSID
{0006F03A-0000-0000-C000-000000000046} failed due to the following
error: 80080005 Server execution failed (Exception from HRESULT:
0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
Is there any way to solve it programmatically?
You could call Process.GetProcessesByName() passing in OUTLOOK or whatever the actual process name is.
This gets you an array of process. You can then iterate through each of these and check the user that started the process. If the user isn't the ones you want you can call Process.Kill() and terminate the process.
Getting the user might be tricky, you can use WMI for this (you could also use WMI to list the processes).
Check this answer here for getting the user name.
However I would rethink how you send your mail. The last thing I'd want as a user is watching my Outlook disappear because your application is trying to send an e-mail.
Perhaps a little late to the party on this one but there are two possible approaches here.
As highlighted by Lloyd, you can attempt to connect to an existing Outlook process for the 'current' user (if one exists) by calling
Process.GetProcessByName("OUTLOOK");
This gets an array of Outlook processes and you can iterate through these until the instance you're looking for.
Alternatively, (or if no process is found), you can initialize a new instance of the Outlook application, connect to the default MAPI namespace and send your email that way. Presumably you're using objects defined in the Microsoft.Office.Interop.Outlook library?
You may need to call the Logon/Logoff routines against the namespace and proceed that way, remembering to correctly dispose of any new instances after use, even acquiring the process ID of the new app instance and calling .Kill on that.

how to resolve The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

PowerPoint.Application PowerPoint_App;
PowerPoint_App = new PowerPoint.ApplicationClass();
PowerPoint_App.DisplayAlerts = PowerPoint.PpAlertLevel.ppAlertsNone;
PowerPoint.Presentation presentation;
presentation = null;
try
{
PowerPoint_App.Visible = MsoTriState.msoTrue;
presentation = PowerPoint_App.Presentations.Open(strPptFilePath, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoFalse);
PowerPoint.Slide tempSlide = null;
int totalSlides = presentation.Slides.Count;
int slideNo = 0;
I am getting the below exception on PowerPoint_App.Presentations.Open code.
Exception Message: The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))
I did not received this error previously on this block of code. Everything was working perfectly before. Can anyone help?
I ended up removing:
PowerPoint_App.Visible = MsoTriState.msoTrue;
And it worked...!!!
I'm working through a similar problem (controlling Excel via PowerShell), and wanted to add that -- in a way I cannot begin to explain -- the analogue to #Milind Anantwar's suggestion caused my script to start working.
More details, in case they help:
In my case, everything worked fine when run locally. I started seeing the
Application is busy
exception only when I moved to executing via an Azure Hybrid Worker Runner.
With reference to the following snippet, I was seeing the exception after line 2, but removing line 2 "fixed" the problem:
$excel = New-Object -ComObject Excel.Application
$excel.visible = $SHOW_EXCEL
$workbook = $excel.Workbooks.Open($_excel_file)
I saw the exception when $SHOW_EXCEL was set to $false.
I just want to say that Nikolay's advice was 100% spot on for me. Although my problem was with code that interacted with Excel rather than PowerPoint, I believe it'll apply all the same.
Suddenly and seemingly out of nowhere a service that had been running flawlessly for years without issues started encountering this error. There weren't any recent code changes that could've been suspect, either.
I logged into the server via Remote Desktop using credentials for the service account that runs the automated service in question and as soon as I manually launched Excel, I was presented with a pop-up with some unrelated news I didn't care about. I clicked OK on this, closed Excel, logged out, and restarted the service and voila! No more issues.
Long story short, the root cause of the problem (for me) was that Excel was trying to present a pop-up and continued code execution couldn't continue because there wasn't a user to acknowledge the pop-up. Acknowledge it and your issue will go away if you have the same issue I did.
Check your Task Manager; you may have an orphaned application instance from a debugging session. Kill it and try again. That has been the case for me before.
For me, I had to wait for Excel to be "ready" after opening up a workbook. The below fixed the issue:
xlApp = new Excel.Application();
xlBook = xlApp.Workbooks.Open(workbook);
// wait for the workbook to open
while (!xlApp.Ready)
{
Thread.Sleep(500);
}

Windows Service not working when installed, works fine in Debug mode; crashes on Moving/deleting files

I created a windows service which watches a directory. When a file is dumped into it, it takes the data and puts it into a database. Then this file is moved to another directory and deleted. It works fine in debug mode. But when i install it on my computer it stops after throwing the data into the database and the file in question is neither moved or deleted. I suspect a permission issue is involved. I tried to create a event log:
public Service1()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
So i have three questions.
(1) What could be causing my service to work as described in debug but fail when installed on my computer.(2) I have initiated a event log as shown above. But do i need to add other code to record the event of my service stopping. I presume this would be done in a 'override onShutdown' method.(3) Finally when my service stops, i want to look at the event log. But i do not know how to do this, is in administrative tools? stored as a file on some directory?
Here is edit to this post in lieu of the grateful advice given below.
try
{
File.Move(e.FullPath, finalString);
File.Delete(e.FullPath);
}
catch(Exception q)
{
EventLog.WriteEntry("MySource", q.ToString(), EventLogEntryType.Error);
using (StreamWriter w = new StreamWriter(ConfigurationManager.AppSettings["fmd"], true))
{
w.Write(DateTime.Now.ToString("dd-MM-yyyy_hh-mm-ss"));
w.Write(q.ToString());
}
}
As per suggestion i put a try-catch around the file move and delete plus i added a OnShutdown method:
protected override void OnShutdown()
{
using (StreamWriter w = new StreamWriter(ConfigurationManager.AppSettings["ond"], true))
{
w.Write("stop OnShutdown");
}
//EventLog.WriteEntry("MySource", message, EventLogEntryType.Error);
}
I do not know how to pass any system error message to the shutdown method, so any advice appreciated. When i installed my modified code as a service, it again stopped before moving or deleting the files. Neither of my two logs accessed by a stream recorded anything. Plus the event viewer showed nothing either?
You can write as following,
if (!EventLog.SourceExists("MySource"))
EventLog.CreateEventSource("MySource", "Application");
EventLog.WriteEntry("MySource", message, EventLogEntryType.Error);
to view the event log messages, Goto Administrator Tools -> Event Viewer and look for the source you have created. or Just simply type eventvwr in run window.
When Services installed, it works under SYSTEM User account where service might not have access to some resources. Please put logs and see where exactly the issue is.
If you service installed in your development machine, use attach to process option under DEBUG Menu in Visual Studio to find out.
What could be causing my service to work as described in debug but fail when installed on my computer?
Permissions. The service is likely running under LocalSystem or Network Service if you didn't provide a different identity.
I have initiated a event log as shown above. But do i need to add other code to record the event of my service stopping. I presume this would be done in a 'override onShutdown' method?
Yes, you're assumption is correct.
Finally when my service stops, i want to look at the event log. But i do not know how to do this, is in administrative tools?
Just hit Windows Key+R to get the Run dialog and type eventvwr.
Well i found the reason for all the commotion. I eventually found some logs in the event viewer. They were listed in Administrative events in custom logs. There were three error logs: .Net runtime; Application error & Service Control Manager. In '.Net Runtime' the stack showed a unhandled exception for system.windows.forms. I stupidly included a pop up box in my release version. But even when i commented this away; i got a error. So i went back and found other message boxes, primarily in try catch statements. Removed these and solved the issue.

Categories

Resources