Outlook, custom task pane and drag-drop problem
I want to share a solution to the problem related to using drag-n-drop in my Outlook 2010 add-in. The task was as follows: we needed to implement a UserControl that would accept MailItem or Selection by using the dragging functions, or more precisely Drag-and-Drop. The task turned out to be pretty simple, and we seemed to get everything working, but… there appeared one “BUT”!
The problem
The crux of the problem was that after dragging a MailItem onto our control, Outlook stopped reacting to SelectionChange, i.e. when an Item was selected its contents did not get refreshed in the Reading Pane, moreover each click increased SelectionCount. (This problem was first posted by Andrei Smolin on the Outlook for Developers forum, see Outlook 2010 issue. Drag-n-drop onto a custom task pane causes Selection.Count to grow.)
The problem is there and we have to resolve it. On the one hand, we have the source of drag-n-drop – it is a MailItem, and it is nothing other than a COM object, which is very interesting by itself. My rich experience with COM objects, especially with MSO, tells me they need to be released, but immediately a question arises: Does the Drag&Drop mechanism release them? We’ll try to figure this out. Let us look at the issue from another angle – from the angle of our form that accepts the MailItem object. But we got stuck with the .NET Framework straight away. Well, we’ll have to venture deeper into its maze and decipher how it all works.
Some theory. Windows API and drag and drop
For any window to work with drag-n-drop, it must be registered in the operating system using the RegisterDragDrop function that accepts two parameters: the first one is a window handle and the other – an object that realizes the OLE interface IDropTarget.
Let’s discuss this interface. IDropTarget has four methods:
- OnDragEnter (object pDataObj, int grfKeyState, long pt, ref int dwEffect) – occurs only once when an item being dragged gets into the area of a window registered as drag-n-drop;
- OnDragOver (int grfKeyState, long pt, ref int pdwEffect) – occurs continuously when an object is being dragged over a window registered as drag-n-drop;
- OnDragDrop (object pDataObj, int grfKeyState, long pt, ref int dwEffect) – occurs only once when an item being dragged is dropped in the area of a window registered as drag-n-drop;
- OnDragLeave () – occurs only once when an item being dragged leaves the area of a window registered as drag-n-drop.
Please pay attention to the fact that the system passes an object-source only for TWO of these events: for OnDragEnter and OnDragDrop.
The cause
The Control class of the System.Windows.Forms namespace has four analogous events (DragEnter, DragOver, DragDrop and DragLeave). What is interesting is that the object-source is passed in THREE events using the DragEventArgs parameter. All is clear with DragEnter and DragDrop – the object-source is passed there by the system via the OLE interface IDropTarget. But how does it get into the DargOver event? Let’s assume that after occurrence of the OnDragEnter event, it is saved into some local variable. If so, and if it is a COM object, then it must be released after usage.
I have done further research on this problem in the company of the NET Reflector. How does it work? In the System.Windows.Forms assembly, the Control class has the AllowDrop property; when it is set, a system drag-n-drop is registered or unregistered for each instance of this class.
During registration, the RegisterDragDrop function is called and, as described above, the handle of this control as well as the object implementing the OLE interface IDropTarget is passed to this function (please do not confuse it with the System.Windows.Forms.IDropTarget interface). An instance of the internal class DropTarget acts in the capacity of the mentioned object. Having a closer look at the implementation of this class I noticed (as I suspected from the very beginning!) that its developers forgot or omitted the fact that COM objects can also be dragged-and-dropped with all the ensuing consequences.
The solution
Well, it can’t be helped, we need to fix bugs produced by our counterparts. All in all, we had to slightly rewrite this class, include it in the project separately and give up the idea of using the standard AllowDrop property.
I created a simple shared add-in for Outlook (see the download links at the end of this article) with one custom task pane onto which you can drag and drop your messages.
Build the setup project, install the add-in and start Outlook. Try dropping a couple of emails onto the task pane and pay attention that the Reading Pane reacts properly when this or that Outlook item is selected. Now tick the checkbox and try doing the same again. When you find that the Reading pane doesn't refresh, try to open an email – beware, this may open a bunch of emails, all those you have selected earlier.
Available downloads:
C# sample Outlook add-in
VB.NET sample Outlook add-in
14 Comments
In the DragEvent I make a call to e.Data.GetData(“RenPrivateMessages”); and this fixed the problem for me. I’m assuming somehow this triggered the release of the COM object
Hi Matt,
Thank for you comment. I have tested your code, it worked fine. The approach you suggested can be used as an alternate way to solve this problem.
@Matt Quinn – brilliant & simple workaround. Confirmed working for me as well!
thank you!
I’ll third that. I’ve been tackling this problem for a while and while some of the things seemed to have worked at first the old problem kept popping its head up.
The call to e.Data.GetData() works a treat. Much better then forcing a swapping of folders especially because my routines don’t know what folders are there.
Fantastic Matt Quinn! That’s solved a real problem for us with switching folders destroying Instant Search results. Thanks!
Alexander,
Thanks for the workaround. I have been battling selection issues in Outlook for years and was happy to finally find a solution.
Tim.
Hi Alexander.
I am using drag Drop on Custom Pane in outlook 2010 for saving Mailitems to my local drive. when i select 100s of items and drop them on custom pane for save action my outlook goes into not responding mode and have to restart outlook. i am releasing the COM objects after every item is saved. I don’t know how to stop outlook from going into not responding mode. Work fine for 5 or 10 emails at a time.
Any suggestion.
Thanks.
Hi Nav,
Thank for you comment. I have tried to drag and drop over 100 items to a custom pane in my Add-in Express based Outlook add-in but I was not able to reproduce the Outlook not responding issue. Possibly the problem is in your code of the DragDrop event handler.
Hi Alexander
Thanks for your reply I am using COM shared addin using C#. Is there any way I can stop outlook from going into not responding mode.
Thanks
Hi Nav,
Regrettably, I do not know how to stop outlook from going into not responding mode. I need to have a look at your source code to detect the cause of the issue, probably the problem is with saving Outlook items rather than with drag and drop.
Matt Quinn, Thank you for such an easy work around. I was searching a solution for this bug since a few days.
Alexander, Thank you for the time taken on this, your explanation was very instructive.
So, how do we non-coder end users fix this problem? I can’t organize my tasks into categories because new tasks must be dragged and dropped into the proper location in the ToDo list.
Hello Jeffrey,
This blog is about drag-drop on a *custom* task pane. So yes, this is for coders. Non-coders ask their questions at https://answers.microsoft.com/en-us/office/forum/.
To clarify, the e.Data.GetData(“RenPrivateMessages”) call goes in the DragEnter event.
Thanks for this, it solved my problem too. :)