C# Limit Error when requesting E-Mails using MAPI - c#

Always when I request E-Mails from my Outlook, which uses Office365 a COM-Exception is thrown, after a count of mails. I really have no idea why...
Error:
System.Runtime.InteropServices.COMException (0xBFE40305):
Die Anzahl der Elemente, die gleichzeitig geöffnet werden können, wurde vom Serveradministrator begrenzt.
Schließen Sie zunächst geöffnete Nachrichten, oder entfernen Sie Anhänge und Bilder von
ungesendeten Nachrichten, die Sie gerade verfassen.
bei Microsoft.Office.Interop.Outlook._MailItem.get_Recipients()
.....
For the people that don't speak German, it means:
The count of the elements which could be opened at the same time, is limited by the server administrator (....)
I don't know anything about such a Limit, and the solution which I can find on Google or MSDN don't help ether.
It looks like it crashes when the program tries to get the E-Mail recipients. Here is the way, how I try to get the Recipients:
foreach (var item in SelectedFolder.Items.Restrict(filter))
{
Outlook.MailItem mail = item as Outlook.MailItem;
if (mail != null)
{
if (mail.Recipients.Count > 0)
{
string caption = mail.Subject;
string MAIL = mail.Recipients[1].PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x39FE001E"); //<--- CRASH HERE
I really don't understand, how this can happen, as far I know, when I select E-Mails from Outlook, they just get "opened" local... So I can't get, how a "Server-Limit" can access to this.

In the online mode the number of simultaneously open objects is limited by the Exchange provider (since each object opens a separate RPC channel).
For the messages, the limit is 255 by default.
Do not use a foreach loop - it will keep each member of the loop referenced until the loop exits. Use a for loop and explicitly release the item (and all of its subjects that you retrieved, such as recipients or attachments) at the end of each iteration using Marshal.ReleaseComObject(). Avoid using multiple dot notation as that forces the compiler to create implicit variables that you cannot explicitly release.
Also keep in mind that the as operator also produces an implicit variable - break that line into two and release both variables using Marshal.ReleaseComObject()

Related

Using Redemption RDOContactItem cannot save more than a number of contacts MAPI_E_TOO_BIG

found I'm trying to create contacts into a user's Mailbox programmatically (using Redemption), based on values from a database.
RDOContactItem rci = (RDOContactItem)session.GetDefaultFolder(rdoDefaultFolders.olFolderContacts).Folders["Contacts Subfolder"].Items.Add("IPM.Contact");
...
rci.Save();
As soon as I reach the limit 250, I get the error:
Error in IMsgStore::OpenEntry(Inbox or Root): MAPI_E_TOO_BIG
ulVersion: 0
Error: Your server administrator has limited the number of items you can open simultaneously. Try closing messages you have opened or removing attachments and images from unsent messages you are composing.
Component: Microsoft Exchange Information Store
Read Dmitry Streblechenko's comments on "This is an indication that you have too many open objects. Do you open each and every message in a folder?" suggestions on http://www.microsoft-questions.com/microsoft/Plaform-SDK-Mapi/32731171/mapietoobig.aspx and even tried his suggestion "Do you release all Exchange objects as soon as you are done with them?"
if (rci != null) Marshal.ReleaseComObject(rci);
even casting to IDisposable to able to dispose it, but it didn't work.
I haven't find a way to close a contact item after being saved.
Increasing the number of items that can be opened simultaneously on the server side is not a happy option either.
How to solve this?
You are using multiple dot notation (5 if I am counting correctly), and that causes the compiler to create implicit variables that you cannot explicitly release. Try the following. You can also try to call GC.Collect() every once in a while, but that would be a sledgehammer of a solution...
RDOFolder contacts = session.GetDefaultFolder(rdoDefaultFolders.olFolderContacts);
RDOFolders folders = contacts.Folders;
RDOFolder subfolder = folders["Contacts Subfolder"];
RDOItems items = subfolder.Items;
RDOMail msg = items.Add("IPM.Contact");
RDOContactItem rci = (RDOContactItem)msg;
...
rci.Save();
Marshal.ReleaseComObject(rci);
Marshal.ReleaseComObject(msg);
Marshal.ReleaseComObject(items);
Marshal.ReleaseComObject(subfolder);
Marshal.ReleaseComObject(folders);
Marshal.ReleaseComObject(contacts);

Localized speech recognition throwing ArgumentException

I have the following problem:
I am using a German Windows7-machine (Culture: "de-DE"), but I want to use the SpeechRecognitionEngine-class with an other culture.
However, the following code throws an ArgumentException:
using (SpeechRecognitionEngine rec = new SpeechRecognitionEngine(new CultureInfo("en-GB"))) //ArgumentException
{
rec.LoadGrammar(new DictationGrammar("grammar:dictation#spelling"));
rec.SpeechRecognized += rec_SpeechRecognized;
rec.SetInputToDefaultAudioDevice();
rec.RecognizeAsync(RecognizeMode.Multiple);
...
}
The Exception message is the following:
Es wurde kein Erkennungsmodul mit der erforderlichen ID gefunden.
Translation:
No recognition module with the required ID could be found.
Does this mean, that some sort of language package is missing on my machine?
I suggest the en-GB-packet has to be installed on the machine.
EDIT:
It would be also reasonable to use a try catch block to prevent the app from crashing if the packet is not available.

Outlook Change MessageClass digital signed Mail

I am working on a project, which displays a customicon and an informationarea in Outlook 2010 for special messages. To achive this, I change the MessageClass of the message. This works great, aslong as the message isn't digitally signed.
Here is the code to change the MessageClass:
public static void SetMessageClass(ref Outlook.MailItem mi) {
try {
if (mi.MessageClass.ToLower() == "ipm.note" || mi.MessageClass.ToLower() == "ipm.note.smime" || mi.MessageClass.ToLower() == "ipm.note.myclass") {
Logger.Log("Setze Message-Class auf " + MESSAGE_CLASS);
mi.MessageClass = MESSAGE_CLASS;
mi.Save();
}
} catch (System.Exception ex) {
Logger.Log("Fehler beim setzen der Message-Class:\r\n" + ex.Message);
}
}
I need to change the MessageClass, because I want to display an icon and an informationarea.
If the mail has a digital signature, the following window appears:
http://social.msdn.microsoft.com/Forums/getfile/186575
It doesn't matter which button I click, the icon doesn't changes.
Can anyone help me?
Greets Knerd
PS: Here is the question in german: http://social.msdn.microsoft.com/Forums/de-DE/vstode/thread/e51b221e-89f6-419f-90e6-e17c74662a9f
Outlook goes to great lengths to represent signed/encrypted message as regular "IPM.Note" MailItem objects (which they are not).
The only workaround I know is to bypass the OOM layer either using Extended MAPI (C++ or Delphi) or Redemption (I am its author - any language) - use RDOSession.GetItemFromID in Redemption. You can then read the MessageClass/PR_MESSAGE_CLASS property and bypass signed/encrypted messages.

DirectoryEntry returns unusable value but does not throw any exception, C# [duplicate]

I'm connecting to a LDAP directory in C#, so I've used the DirectoryEntry class.
When you do the "new DirectoryEntry" with address, login, and password it is supposed to connect to the LDAP directory.
However, even if the connection didn't work, it returns without problem, and the directoryentry variable is set.
So i do i know my connection is really opened ? Right now, I'm using a very very ugly hack : i put a "if(mydirectory.SchemaEntry)" which generates an exception if the connection wasn't etablished, because some of the members of the DirectoryEntry, such as SchemaEntry, aren't set if the connection failed. But 1:that's gotta be 11/10 on the ugliness scale 2:that takes a lot of time before failing.
So what is the good way to do this ? Surely, Microsoft must have provided something (even if I'm using a LDAP directory and not an Active Directory) to know if I'm really connected ?
Just "newing" up a DirectoryEntry does NOT create a connection to the LDAP store.
Only once you start using its properties, or when you access the .NativeObject property explicitly, you'll actually get a connection to the LDAP store.
In order to make sure you're connected, just read out the (DirectoryEntry).NativeObject in a try...catch clause - if it bombs out, you have a problem, otherwise your connection is now up and active.
Unfortunately, to my knowledge, there is no property or method you can call to figure out whether or not you've successfully connected to LDAP using DirectoryEntry.
Marc
You can check DirectoryEntry.Properties.Count. If it's > 0, it's a valid object. .Properties is never null - you'll be able to read the count even if you're not connected up to a valid DirectoryEntry, and a valid DE will always have at least one property.
No try/catch or exceptions necessary.
Ok so marc_s's solution was approximately what i was doing (except i was looking for SchemaEntry and not NativeObject). But the timeout delay is much too long (the query is run to fill autocompletion values for a form). I think I actually prefer to pretend the connection is open and let the query run. That way, i can set my own, smaller, timeout delay.
You can check DirectoryEntry.Properties.Count. If it's > 0,for a valid object.
But still let say your LDAP server is down. you can't identify it with any of its properties.Instead you can catch it using the try catch block
try
{
entry = new DirectoryEntry("priorityLDAPServer", sUserName, sPassword, AuthenticationTypes.None);
if(entry.Properties.Count > 0)
{
object o = entry.NativeObject;
` next need to check user record in application database`
}
}
catch (System.Runtime.InteropServices.COMException comex)
{
//throws you the error if LDAP server is down or wrong "Server is invalid "
// you can further do a nested try catch within this block if you to try a optional LDAP server.*
}
Hope this helps you

How to know if my DirectoryEntry is really connected to my LDAP directory?

I'm connecting to a LDAP directory in C#, so I've used the DirectoryEntry class.
When you do the "new DirectoryEntry" with address, login, and password it is supposed to connect to the LDAP directory.
However, even if the connection didn't work, it returns without problem, and the directoryentry variable is set.
So i do i know my connection is really opened ? Right now, I'm using a very very ugly hack : i put a "if(mydirectory.SchemaEntry)" which generates an exception if the connection wasn't etablished, because some of the members of the DirectoryEntry, such as SchemaEntry, aren't set if the connection failed. But 1:that's gotta be 11/10 on the ugliness scale 2:that takes a lot of time before failing.
So what is the good way to do this ? Surely, Microsoft must have provided something (even if I'm using a LDAP directory and not an Active Directory) to know if I'm really connected ?
Just "newing" up a DirectoryEntry does NOT create a connection to the LDAP store.
Only once you start using its properties, or when you access the .NativeObject property explicitly, you'll actually get a connection to the LDAP store.
In order to make sure you're connected, just read out the (DirectoryEntry).NativeObject in a try...catch clause - if it bombs out, you have a problem, otherwise your connection is now up and active.
Unfortunately, to my knowledge, there is no property or method you can call to figure out whether or not you've successfully connected to LDAP using DirectoryEntry.
Marc
You can check DirectoryEntry.Properties.Count. If it's > 0, it's a valid object. .Properties is never null - you'll be able to read the count even if you're not connected up to a valid DirectoryEntry, and a valid DE will always have at least one property.
No try/catch or exceptions necessary.
Ok so marc_s's solution was approximately what i was doing (except i was looking for SchemaEntry and not NativeObject). But the timeout delay is much too long (the query is run to fill autocompletion values for a form). I think I actually prefer to pretend the connection is open and let the query run. That way, i can set my own, smaller, timeout delay.
You can check DirectoryEntry.Properties.Count. If it's > 0,for a valid object.
But still let say your LDAP server is down. you can't identify it with any of its properties.Instead you can catch it using the try catch block
try
{
entry = new DirectoryEntry("priorityLDAPServer", sUserName, sPassword, AuthenticationTypes.None);
if(entry.Properties.Count > 0)
{
object o = entry.NativeObject;
` next need to check user record in application database`
}
}
catch (System.Runtime.InteropServices.COMException comex)
{
//throws you the error if LDAP server is down or wrong "Server is invalid "
// you can further do a nested try catch within this block if you to try a optional LDAP server.*
}
Hope this helps you

Categories

Resources