The use case: users need the ability to drag & drop email items from Outlook onto a form in my WinForms (.Net 4) application. The application saves these items in .msg format and stores them in a predetermined location.
The problem: my code is not robust against drag-drop from other sources (e.g. dragging a jpeg from IE onto the form triggers the same event). This is because I cannot determine whether the dragged item is an Outlook object, or what source the dragged item(s) came from.
Is there a workaround such that I can only accept drag-drop items of a particular type? Here is my code in the DragDrop event handler:
Outlook.Application outlook = new Outlook.Application();
Outlook.Selection sel = outlook.ActiveExplorer().Selection;
try
{
foreach (object item in sel)
{
if (item is Outlook.MailItem)
{
var mail = item as Outlook.MailItem;
CopyMailItemToLocalTempDir(mail);
txtComment.Text = "Email from " + mail.SenderName + " Regarding " + mail.Subject;
}
}
}
finally
{
// This is hokey but it prevents Outlook from remembering previously selected items
// - refer http://stackoverflow.com/questions/14090420/interop-outlook-doesnt-clear-selected-mails-at-drag-and-drop
var folder = outlook.ActiveExplorer().CurrentFolder;
outlook.ActiveExplorer().CurrentFolder = outlook.GetNamespace("MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
Thread.Sleep(50);
outlook.ActiveExplorer().CurrentFolder = folder;
Marshal.ReleaseComObject(sel);
Marshal.ReleaseComObject(outlook);
sel = null;
outlook = null;
}
Some details on the DragEventArgs object (e) when dragging from Outlook:
e.Data.GetFormats() returns:
{string[15]}
[0]: "RenPrivateSourceFolder"
[1]: "RenPrivateLatestMessages"
[2]: "RenPrivateMessages"
[3]: "RenPrivateItem"
[4]: "FileGroupDescriptor"
[5]: "FileGroupDescriptorW"
[6]: "FileDrop"
[7]: "FileNameW"
[8]: "FileName"
[9]: "FileContents"
[10]: "Object Descriptor"
[11]: "System.String"
[12]: "UnicodeText"
[13]: "Text"
[14]: "CSV"
e.Data.GetData("Text") returns:
"From\tSubject\tReceived\tSize\tCategories\t\r\nJoe Sender\tThis is the email subject\t10:51 AM\t3 KB\t\t"
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.
C is a function driven language because C is a procedural programming language. C++ is an object driven language because it is an object oriented programming. Function and operator overloading is not supported in C. Function and operator overloading is supported by C++. C is a function-driven language.
i have here the source code of solution that allow to drop only outlook items. here are the event handlers:
private void Form1_DragEnter(object sender, DragEventArgs e)
{
//display formats available
this.label1.Text = "Formats:\n";
foreach (string format in e.Data.GetFormats())
{
this.label1.Text += " " + format + "\n";
}
//ensure FileGroupDescriptor is present before allowing drop
if (e.Data.GetDataPresent("FileGroupDescriptor"))
{
e.Effect = DragDropEffects.All;
}
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
//wrap standard IDataObject in OutlookDataObject
OutlookDataObject dataObject = new OutlookDataObject(e.Data);
//get the names and data streams of the files dropped
string[] filenames = (string[])dataObject.GetData("FileGroupDescriptorW");
MemoryStream[] filestreams = (MemoryStream[])dataObject.GetData("FileContents");
this.label1.Text += "Files:\n";
for (int fileIndex = 0; fileIndex < filenames.Length; fileIndex++)
{
//use the fileindex to get the name and data stream
string filename = filenames[fileIndex];
MemoryStream filestream = filestreams[fileIndex];
this.label1.Text += " " + filename + "\n";
//save the file stream using its name to the application path
FileStream outputStream = File.Create(filename);
filestream.WriteTo(outputStream);
outputStream.Close();
}
}
Is there a workaround such that I can only accept drag-drop items of a particular type?
(When working with single files):
if (e.Data.GetData(typeof(...)) is ...)
//process it
and
if (e.Data.GetDataPresent(typeof(...)))
//process it
Since you have not specified the type to be Outlook.MailItem
(or maybe Image
) but the source: I assume your program fails on other parts of the code (due to bad design). E.g. ActiveExplorer().Selection
in 2nd line or in the finally {}
part. This is easily manageable by prefiltering/try-catching in place (before involving outlook) or in the DragEnter
event (better when the type is strictly some type of outlook).
To master drag & drop stuff, check out this.
or for special types like outlook messages, you already have a good solution with plenty of explanations in the article you mentioned.
I also found an answer to your non-general (outlook only) use case (wrote in 2012) that exhibits OutlookDataObject class and probably based on the article you mentioned (wrote in 2008).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With