C# VSTO Outlook 2013 - Explorer Close handle Save Event - c#

I have a RibbonBar with some Buttons that appears in the Outlook Explorer (Double Click on a mail).
Some progresses in the background edit the attachments of the mail. If the user close the Explorer, outlook will ask to save the edited mail (save the changes).
is there a Event to handle this? i don't want that the message appear if my programm has changed the mail.
I wasn't succesfull on the search for an Event. But maybe i just missed something.

There is no need to handle any event for this.
If the user close the Explorer, outlook will ask to save the edited mail (save the changes).
This is a good indicator that changes were not saved or Outlook objects (actually underlying COM objects) were not released correctly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. You can read more about that in the Systematically Releasing Objects article in MSDN.
Some progresses in the background edit the attachments of the mail.
Don't use the Outlook object model from secondary threads. Office applications (Outlook in your case) use the single threaded apartment model. You can gather the required info on the main thread (keep it in a string for example) and process it on another thread. Or you can use a low-level API (Extended MAPI) which allows to run multiple threads. Also you may consider using any wrapper around that API. Frankly speaking, Outlook is a big wrapper around that API.

Related

Minimise winform without blocking Outlook functionality

I am working on a vsto plugin in which I've created a Form(WinForm) that has fields for long text that user has to copy from previous mails. Now, the issue i am facing is, whenever I minimise the winform, the whole Outlook gets minimised. And when I try to open the outlook application from taskbar, it goes to form again.
Is there a way where user can minimise the Form and work on outlook application independently?
For example, he/she might need to scroll through few mails to get some values of field in the winform more than one time, so they minimise the form, fetch the long text, then open the form again and paste it.
Create a task pane instead of a floating window - see https://learn.microsoft.com/en-us/visualstudio/vsto/custom-task-panes?view=vs-2022&tabs=csharp

PropertyChange not fire on Reading Panel when I reply or forward email on Office 2013

I am using Add-in Express(v 7.6.4084) to create an Outlook plugin.
The problem is, that the MailItem.PropertyChange isn't triggered when reply an email on reading panel.
I have searched several topics but wasn't able to find a solution.
Seems you are talking about the inline response feature. If so, you need to use the ActiveInlineResponse property to get an item object representing the active inline response item in the explorer reading pane. It fires the PropertyChange event as expected on my PC with Outlook 2013 installed.
Note, you need to declare the source object at the global scope to prevent it from being swiped by the garbage collector.

Issue with conflicting Outlook Add-Ins

We currently have a team that uses an Outlook Add-In (call it Add-In A) that we developed internally that attaches to the Send event and, if some rules around the From address and Subject are met, a form is displayed, data is written to a SQL database and the email is sent. This works fine.
We've also just had a company-wide rollout of a third party Outlook Add-In (call it Add-In B) that checks any emails you send to see if they're going to an external address and if so asks if you're sure you want to send. Again, this works fine.
The problem is when these two are combined. While there's no technical problem where they conflict or anything like that, there is a potential logical error where you could try and send an email, Add-In A kicks in, the user completes the form and data gets written to the database. Then Add-In B kicks in, warns the user they're sending an external email, they decide against sending and the whole process is cancelled. However, the database has been updated to say it was sent, which is incorrect.
I'm struggling to think of any way to prevent this - if we could force Add-In B to fire before Add-In A then that would solve the issues, but I'm pretty sure that you can't specify the order that each Add-In should fire or be enabled, and we have no control over the code for Add-In B as it's a third party product.
Any suggestions to prevent this from being a possible outcome?
First of all, you may handle the ItemAdd event of the Sent Items folder in Outlook to be sure that a mail item (Outlook Item) was sent for sure. Be aware, the Sent Items folder can be specified an runtime using the SaveSentMessageFolder property of the MailItem class.
Also you may choose the ProgID name for the add-in to make sure that your add-in is loaded after others. The events are fired in the reverse order. But all of these facts are not documented and can be changed at any time. Nobody can guarantee that it work stable all the time.

Catch Outlook events when attaching/sending a file from another application

I'm trying to create an add-in for Outlook 2007/2010 to modify recipients of newly created email messages. Everything works fine if the user creates a new email message inside Outlook (I'm using the Inspectors.NewInspector event). But if the user uses another application (MS Word or Adobe Acrobat for example) to try to email an attachment, the NewInspector event isn't fired when the compose email window is displayed. Is there a straightforward approach to catching an event that is raised in a situation like this?
I've tried using the Application.ItemLoad event, but I can't access any methods or properties after I successfully cast it to an Outlook.MailItem (I get an error stating System.Runtime.InteropServices.COMException: The item’s properties and methods cannot be used inside this event procedure). I'm using C# in Visual Studio 2010.
If the Outlook.exe process is not running then the NewInspector won't fire since ThisAddIn_Startup is not called except when the user opens up Outlook directly.
Since Outlook is not already running when the external application opens the new Inspector window - you would have to manually call ThisAddIn_Startup yourself or attach any custom events that need to fire when the Inspector ribbon is loaded. The best place to do this is by handling CreateRibbonExtensibilityObject or RequestService methods.
protected override object RequestService(Guid serviceGuid)
{
if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
this.ThisAddIn_Startup(this, null);
return base.RequestService(serviceGuid);
}
The only caveat with this is that you need to support method re-entry with ThisAddIn_Startup since the Ribbon and Outlook can both call the startup routine now. You will need to safely administer a lock to ensure you don't keep calling your Init (ThisAddIn_Startup) routine more than once.

Prevent Excel from quitting

I'm missing an Excel.Application.Quit or an Excel.Application.BeforeQuit event. Does anybody know a workaround to mimic these events?
I access Excel from a C# WinForms application via COM Interop. Given an Excel.Application object, how can I:
Preferrably prevent Excel from quitting?
If this is not possible, how can I at least notice when Excel is quit?
Please note: Since I have a COM reference to the Excel.Application, the Excel process does not exit when Excel is "quit" by the user. Although this sounds contradictory, that's how it is. By "quit" I mean that the user hits "Quit" or the "cross button" at the top right corner of the window. The window closes, the files are unloaded, the add-ins are unloaded and whatever stuff Excel does apart from that which I have no clue of. But I can still use the Application object to "revive" the process and make Excel visible again, though the add-ins are then missing, and I have no certainty about what else is in an undefined state.
To get rid of this problem, I would like to either Cancel the Quit at the very start (Think of a BeforeQuit Cancel = true if it existed), or at least be notified when Excel is quit, so I can release the COM objects and make the process really exit, and next time I need Excel again, I will know that I need to start it up first.
Unfortunately it's a vicious circle: As long as Excel runs, I need the COM objects. So I can't dispose of them before Excel is quit. On the other hand, as long as the COM objects are there, the process doesn't exit even if Excel pretends to quit, so I cannot wait for a process exit event or similar.
I have the unpleasing feeling that I'm going to bash my head against a brick wall...
Please note that I haven't tried this.
Create a workbook which has code in it on BeforeClose.
for e.g.
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Cancel = True
End Sub
Open this workbook alongwith other workbooks that you have & it doesn't have to be hidden (if the entire application is invisible).
So, if you try to quit the excel instance, it will force closing of this hidden workbook, which will raise its BeforeClose event & you can write code to stop it from closing.
Note that above code is in VB6 (VBA) and it will need converting into c#.
Post a comment, if you find any difficulty converting.
If you want to hide a workbook, you could do
Workbooks("my workbook").Windows(1).Visible = False
Note: Workbook has a Windows collection. The code above tries to hide the 1st window.
I don't know, can a workbook have more than 1 window? if so, how?
It's a hack of course, but couldn't you use the Windows SetWindowsHookEx API with WH_SHELL or WH_CBT at least to get notified of the Excel's main window being destroyed?
NOTE: It certainly has security implications, i.e. need some admin rights to do cross-process magic.
The problem you are trying to solve here is not going to be solved by monitoring for program exit.
Before you say that I am not answering your question, you state in the question that you are able to revive excel even after the user quits excel. Therefore the excel.exe process is still in play because you have a .net object with a com interop reference to excel.application.
So you have three options:
Avoid the user exiting Excel.
As you have stated keep Excel from quitting, however I am unaware of a way that you can prevent the user from causing Excel to quit, thus as you have correctly noted unloading your and any other addins, etc. Bare in mind that Microsoft specifically design the user interaction this way, they want users to have the ability to close their apps. your addin needs to be able to deal with this, if it can't I'd say thats a problem with your addin not Excel. I might be wrong since i dont know enough about your apps requirements.
Cleanup all unmanaged resources BEFORE the user quits.
What you need to do is cleanup your references to alll Excel and Office unmanaged resources before the user manually quits Excel so that when they do quit your application code is not left with any leftover resources that are now pointing to an instance of excel that no longer has addins etc loaded. Step (a) should be performed as you go, as soon as you no longer need a particular resource or even when reusing it for something else (i.e. a Excel.Range type) whereas step (b) should be used less often however if its a win app and not a addin, probably alot more frequently, it all depends on your app and the window of oppurtunity that you have (time) before the user is likely to complete there tasks an shutdown. Obviously with an addin you can just put it in the shutdown event, or arbitarily in your code.
a. As noted by Otaku, use Marshal.FinalReleaseCOMObject on each unmanaged resource that is != null after use.
if (ComObject != null)
{
Marshal.FinalReleaseComObject(ComObject);
ComObject = null;
}
b. use the GC cleanup pattern for COM resources.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Reload addins
If your not interested in fully tracking down and unloading all unmanaged resources due to the complexity of that task, time constraints (although I'd recommend it), you could look at reloading any required addins that you are presumably already aware of in your environment. This only works if you control the environment.
there are techniques for loading both Excel and COM addins manually. As for other stuff, I'm not aware of that but perhaps its possible if you are using XLLs or maybe XLT in startup/XLSTART dirs but that would load anyways.
There is a KB article, How to automate Excel and then know the user closed it, in C++. I haven't ported this to C#, but it's likely not a lot of work.
Why don't you just execute a System.Diagnostics.Process.Start(#"SomeWorkbook.xlsx"); to ensure that Excel is started. If it already has been started then this will not create a new process.
Why not just use the Application.ApplicationExit event to know when it is closed?

Categories