Outlook.Application.Quit does not work - outlook

I'm trying to quit outlook.application after I'm done with the object like the following
//variables intialisation
var outlookApp = new Microsoft.Office.Interop.Outlook.Application();
RDOFolder store;
RDOStore mailbox;
RDOSession session;
session = Redemption.RedemptionLoader.new_RDOSession();
session.MAPIOBJECT = outlookApp.Session.MAPIOBJECT;
mailbox = session.GetDefaultFolder(rdoDefaultFolder.olFolderInbox).Store;
store = session.GetDefaultFolder(rdoDefaultFolder.olFolderInbox).Parent;
//...code goes on
//Quitting
session.LogOff();
outlookApp.Quit();
Marshal.ReleaseComObject(store);
Marshal.ReleaseComObject(mailbox);
Marshal.ReleaseComObject(session);
Marshal.ReleaseComObject(outlookApp);
What could be the problem? I trying to wait for a couple minutes to make sure they were nothing going on in the outlook process bloking it to quit but it never close itself. When I click on the outlook icon to close it manually I get the following error:
Outlook cannot display this view
But If I break before session.LogOff(), open outlook in full mode and restart the code then it will close without problem.
Thanks!

You are killing the Outlook MAPI session by calling RDOSession.Logoff. Don't do that - the session belongs to Outlook, you just borrowed it by reading the Namespace.MAPIOBJECT property.

Related

Send ENTER key to console in form application in VB.NET

edit: My issue was never quite resolved, but the answer below provided an interesting result.
The app will eventually be called by a powershell script and in this situation, I don't have the issue explained below. No additional {ENTER} is required in the PS console, so no more issue! I couldn't care less if an extra ENTER is required when my app is launched manually via cmd.exe
Problem: In a VB.NET
form app, I'm unable to get the console back to it's "default" state after the code is finished running. I need to press enter manually.
My app can also be executed from command line (in this case, no form is opened. Code is being executed automatically and output sent to console for user to see what happens)
I call AttachConsole(-1), run some code, and when everything's finished I see my latest message in console, but it's as if the process wasn't quite finished.
I have tried SendKeys.SendWait("{ENTER}"). It works well, but only when the console is the current focus. If I click outside the console while the code is running, the ENTER key is sent to whichever window I made active.
So I tried to make the console the current window:
Dim bProcess As Process = Process.GetProcessesByName("cmd").FirstOrDefault()
SetForegroundWindow(bProcess.MainWindowHandle)
// I also tried AppActivate(bProcess.Id)
SendKeys.SendWait("{ENTER}")
FreeConsole()
Nope, the ENTER key will still be sent somewhere else and not to the console. But it does make the console blink orange, so SetForegroundWindow seems to do something...
Any help will be greatly appreciated :)
EDIT
In response to #TnTinMn's answer:
FreeConsole()
// SendKeys.SendWait("test")
PieceOfCodeFromTnTinMn()
Same behavior as I've had so far: This will send the SendKeys.SendWait("~")command "outside" the console if it loses focus while the code is running.
BUT with the 2nd line above un-commented, "test" is sent outside the console and SendKeys.SendWait("~") is sent to the console, as expected.
I'm still trying to figure out what is happening here...
You can use the VB Interaction.AppActivate Method to activate the parent console prior to calling SendKeys.SendWait. This requires that you obtain the ProcessID of the console window that is the parent process of your application.
One way to do this is using Windows Management Instrumentation (WMI). The following is not pretty, but it appears to work. You would execute this after calling FreeConsole
Using currentProcess As Process = Process.GetCurrentProcess
Dim query As New SelectQuery()
Dim props As New StringCollection
props.Add("ProcessId")
props.Add("ParentProcessId")
With query
.ClassName = "Win32_Process"
.Condition = $"ProcessId={currentProcess.Id}"
.SelectedProperties = props
End With
Dim parentProcessId As Int32
Using searcher As New ManagementObjectSearcher(query)
Using mos As ManagementObjectCollection = searcher.Get
Using en As ManagementObjectCollection.ManagementObjectEnumerator = mos.GetEnumerator
If en.MoveNext() Then
parentProcessId = CInt(en.Current.Item("ParentProcessId"))
End If
End Using 'en
End Using ' mos
End Using 'searcher
If parentProcessId <> 0 Then
AppActivate(parentProcessId)
SendKeys.SendWait("~")
End If
End Using 'currentProcess

Is there any better way to launch outlook add-appointment window in bot application?

I need to launch outlook calendar appointment in bot application. I found the below code in Microsoft documentation for launching outlook email.
var message = context.MakeMessage() as IMessageActivity;
message.ChannelData = JObject.FromObject(new
{
action = new { type = "LaunchUri", uri = "mailto:someone#example.comsubject=This%20is%20the%20subject&body=This%20is%20t e%20body"
}
});
await context.PostAsync(message);
And also i tried the Microsoft.Office.Interop.Outlook to add appointment , it also doesn't work for me.
Outlook.Application outlookApp = new Outlook.Application(); // creates new outlook app
Outlook.AppointmentItem oAppointment = (Outlook.AppointmentItem)outlookApp.CreateItem(Outlook.OlItemType.olAppointmentItem); // creates a new appointment
oAppointment.Subject = apt.Subject;
oAppointment.Body = apt.Body;
oAppointment.Location = apt.Location;
oAppointment.Start = Convert.ToDateTime(apt.StartTime);
oAppointment.End = Convert.ToDateTime(apt.EndTime);
Is there any better way to launch outlook calendar appointment.
Your code must call oAppointment.Save.
What exactly are you trying to do? Silently create an appointment (then you code above needs to call oAppointment.Save) or display it to the user (then call oAppointment.Display)?
If your code is running on a server, create an iCal file and let the user download and open in (local) Outlook - it will be happy to display the appointment.
Steve mentioned you could use Microsoft Graph.
You might be able to send an ics file as a media attachment (I haven't tried).
Or you can investigate if the protocol handler outlookcal: supports deep linking.
I think this link tells you how it works in Teams
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deep-links

How to switch Dialogs in BotFramework SDK3 C#

I'm trying to add a timeout Dialog using proactiveMessages. If user doesn't reply to [A dialog], [timeout dialog] comes out. So I think timeout dialog should be the current dialog. But do I to close other dialog [A dialog]?
According this, it seems context.EndConversation was not working in MS Teams. Of course I have tried again. It is still not working.
I also tried the way below. But it seems not working either.
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, context.Activity.AsMessageActivity()))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
}
Any suggestions about changing the dialog?
There are two methods of redirecting dialog flow within a C# bot.
you can use context.Forward() to send a user to a new dialog starting with a message that you are currently processing:
await context.Forward(new NewOrderDialog(), this.ResumeAfterNewOrderDialog, message, CancellationToken.None);
or you can use context.call() to send a user to a new dialog and start from scratch there:
context.Call(new AgeDialog(this.name), this.AgeDialogResumeAfter);
The "ResumeAfter" functions can be defined anywhere (including a function within the new dialog itself) and setting these to where you would like to redirect the user after they have finished with your timeout dialog will allow you to determine the flow.

Outlook.Application.CreateItem with Office365 says: The operation failed

We've written an Outlook plugin using Add-in-Express. Code:
private void CreateShowMessageUsingCreateItem(Outlook._Application OutlookApp)
{
Outlook.MailItem mail = null;
try
{
mail = OutlookApp.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
mail.Save();
mail.Display(false);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
if (mail != null) Marshal.ReleaseComObject(mail);
}
}
Works when Outlook is connected to Exchange. Fails when
Outlook is connected to Office365. Error:
Exception: System.Runtime.InteropServices.COMException (0x80004005): The operation failed.
at Microsoft.Office.Interop.Outlook.ApplicationClass.CreateItem(OlItemType ItemType)
at DocuSignInk.DSToolbox.ShowResponse(MailItem senderEmail) in C:\docusign_source\Ink_Outlook\DocuSignInk\DSToolbox.cs:line 540
Some research indicates that you need to release your objects
when making these calls in a loop. But I'm not in a loop. I
can't even get one call to work, so I don't get to the point
where I can release anything.
Testing with Wireshark and Charles indicates that the problem is
in the client. I was trying to see if there is a more detailed
error coming from the server, but there's no traffic to the server
at all.
A quick Python script works from the command line.
import win32com.client
outlook = win32com.client.Dispatch('Outlook.Application')
mail = outlook.CreateItem(win32com.client.constants.olMailItem)
mail.Save()
mail.Display(False)
So it must be something in the client. I'm guessing maybe thread-related?
This can happen if you haven't activated Microsoft Office (which includes Outlook).
Short, test add-ins can work if they run right away before the activation check happens.
Once the activation check happens the API calls will fail.
Firstly, the code is correct, no additional releasing is required. The most obvious reason is that your Outlook, when connected to Exchange Online, cannot create a mail item. You can check this with the following VBA macro:
Public Sub CreateEmailItem()
Dim mail As Outlook.MailItem
Set mail = Application.CreateItem(olMailItem)
mail.Save
mail.Display (False)
Set mail = Nothing
End Sub
Regards,
Dmitry Kostochko (Add-in Express Team)
I had the same exception along with HResult that was -2147467259.
The direct reason was an outlook popup window informing about its trial version or an outlook closing process which is pending after you have closed previous activities in outlook including an email that was showed up by executing the above code (this process is indicated by a respective tray icon in the taskbar until it disappears).
You need to close the window first or wait for the tray icon to disappear before you execute creating new email.

Using Pgp.exe from a MVC application

I've been tasked with converting a legacy application to mvc. The app used pgp.exe to pgp sign user input and send it as an email. The application works locally and on a test server but won't run on a live server. I've had to jump though hoops such as running a specified user in the application pool so that we can set the keys in the users profile BUT it worked.
For some reason on the live server which is windows 2003 IIS 6 and identical to the testing server it fails. The problem is pgp.exe just wont seem to sign and create files the message I get from the console out put is. "Signature Error"?? When I put the command into a shell window logged in as the app pool user it runs no problem (after a fight with some permissions) but when running through the mvc application/IIS server it fails. The code used to call the process is below.
var startInfo = new ProcessStartInfo();
startInfo.FileName = _pgpexeLocation;
//startInfo.FileName = "pgp.exe";
startInfo.Arguments = string.Format("-sta \"{0}\" -u keyuser-z keypass +COMPATIBLE +FORCE", _tempFilePath);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.LoadUserProfile = true;
using (Process exeProcess = Process.Start(startInfo))
{
// TODO: set limit to wait for and deal with exit
exeProcess.WaitForExit();
//var stringItem = exeProcess.StandardOutput.ReadToEnd();
//Logger.Info(stringItem);
}
I'm clutching at straws here hoping somebody has done something similar before and can help. I'm guessing it's key location or file location not being picked up somewhere but not sure what else to try?
Turns out that even though the app pool was using a specific user and I'd set the keys up in that users appdata folder when I checked the underlying process call it was actually trying to pick the keys up from the Default User profile. Not sure if this was an IIS config or something similar but moving the keys and pgp folder to this appdata instead worked?

Resources