Outlook VSTO add-in 80080005 exception while looking up tasks - outlook

I have a VSTO add-in, that looks up an Outlook task by an EntryID or a Subject, and does some operations on it.
One of the users logged the following error message from it:
Retrieving the COM class factory for component with CLSID {0006F03A-0000-0000-C000-000000000046} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE))
Here's the function that finds the Task Item
public Outlook.TaskItem FindTask(String EntryID, String Subject)
{
try
{
Outlook.Application OutlookApp = new Outlook.Application();
Outlook.NameSpace ns = null;
Outlook.MAPIFolder tasksFolder = null;
Outlook.Items taskFolderItems = null;
Outlook.Items filteredtaskFolderItems = null;
Outlook.TaskItem task = null;
ns = OutlookApp.Session;
ns.SendAndReceive(false);
tasksFolder = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);
taskFolderItems = tasksFolder.Items;
//Try to find the task by entryID
dynamic OutlookItem = null;
OutlookItem = ns.GetItemFromID(EntryID);
if (OutlookItem != null)
{
if (OutlookItem is Outlook.TaskItem)
{
Outlook.TaskItem foundItem = (Outlook.TaskItem)OutlookItem;
return foundItem;
}
}
//If not found by EntryID, find it by a Subject
string subjectmatch = "[Subject] ='" + Subject + "'";
filteredtaskFolderItems = taskFolderItems.Restrict(subjectmatch);
for (int i = 1; i <= filteredtaskFolderItems.Count; i++)
{
task = (Microsoft.Office.Interop.Outlook.TaskItem)filteredtaskFolderItems[i];
return task;
}
}
catch(Exception ex)
{
//log exception
}
return null;
}
I've found a couple of explanations for the error log, but none of them really made sense (multiple users accessing the same COM interface, messed up registry etc.)
Any clear signs that maybe the code is wrong, and that's the reason this exception is being generated, or it's Outlooks fault?
I have to mention, that I'm instantiating Outlook from another Office application.

This most likely means your app is running in a security context different from that of Outlook.
Is either app running with elevated privileges (Run as Administrator)?
Also, if this code is in an addin, why are you creating a new instance of the Outlook.Application instead of using the instance passed to your addin?

Related

Outlook event function triggers multiple times when used on shared mailbox - C#

I've function which checks every new coming email inbox and if it is reply, it would move it to "Reply" folder.
It runs on shared mailbox in multiple people's PC. The problem is, it moves the email file but creates multiple copies of the same email into "Reply" folder. How can I fix it?
Here is my code, any help will be appreciated.
Thank you.
Outlook.NameSpace outlookNameSpace;
Outlook.MAPIFolder inbox;
private Outlook.Items items;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Outlook.NameSpace ns = Globals.ThisAddIn.Application.Session;
Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
outlookNameSpace = this.Application.GetNamespace("MAPI");
string recipientName = "abc#abcd.com";
Outlook.Recipient recip = outlookNameSpace.CreateRecipient(recipientName);
recip.Resolve();
if (recip.Resolved)
{
inbox = outlookNameSpace.GetSharedDefaultFolder(recip, Outlook.OlDefaultFolders.olFolderInbox);
items = inbox.Items;
items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
}
}
void items_ItemAdd(object Item)
{
if (Item != null)
{
Outlook.MailItem mail = Item as Outlook.MailItem;
if (mail.MessageClass == "IPM.Note")
{
try
{
Outlook.Application app = Globals.ThisAddIn.Application;
if (Item is Outlook.MailItem)
{
if (mailItem.ConversationIndex.Length >= 64)
{
Outlook.Folder nonInbox = folder.Parent as Outlook.Folder;
string FolderName = "Reply";
Outlook.MAPIFolder DestFolder = null;
try
{
DestFolder = nonInbox.Folders[FolderName];
}
catch
{
}
try
{
mailItem.Move(DestFolder);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
The way I dealt with it is when our user reply to email, it will save custom user property along with original email from customer. User property is our user's name. When they get reply from customer, add-in checks if current user is same as user property saved in original email, if they are same; then add-in will move the email to folder. Like this, condition on every reply will be true only once.

Force tags to update from external event

this is a somewhat exotic question but I will try anyway.
I am writing a Visual Studio 2010 Extension using MEF. At some point in my code, I am required to provide some error glyphs ( like brakepoints ) whenever a document is saved. The problem is that I can't seem to find how to force GetTags of my ITagger to be called without having the user writing anything.
I can catch the document save event but I am missing the "link" between this and somehow getting GetTags method to be called. Any ideas?
Here is some code :
internal class RTextErrorTag : IGlyphTag
{}
class RTextErrorGlyphTagger : ITagger<RTextErrorTag>
{
private IClassifier mClassifier;
private SimpleTagger<ErrorTag> mSquiggleTagger;
private EnvDTE._DTE mMSVSInstance = null;
private List<object> mDTEEvents = new List<object>();
internal RTextErrorGlyphTagger(IClassifier classifier, IErrorProviderFactory squiggleProviderFactory, ITextBuffer buffer, IServiceProvider serviceProvider)
{
this.mClassifier = classifier;
this.mSquiggleTagger = squiggleProviderFactory.GetErrorTagger(buffer);
mMSVSInstance = serviceProvider.GetService(typeof(EnvDTE._DTE)) as EnvDTE._DTE;
var eventHolder = mMSVSInstance.Events.DocumentEvents;
mDTEEvents.Add(eventHolder);
eventHolder.DocumentSaved += new EnvDTE._dispDocumentEvents_DocumentSavedEventHandler(OnDocumentSaved);
}
void OnDocumentSaved(EnvDTE.Document Document)
{
//fire up event to renew glyphs - how to force GetTags method?
var temp = this.TagsChanged;
if (temp != null)
temp(this, new SnapshotSpanEventArgs(new SnapshotSpan() )); //how to foce get
}
IEnumerable<ITagSpan<RTextErrorTag>> ITagger<RTextErrorTag>.GetTags(NormalizedSnapshotSpanCollection spans)
{
foreach (SnapshotSpan span in spans)
{
foreach (var error in this.mSquiggleTagger.GetTaggedSpans(span))
{
yield return new TagSpan<RTextErrorTag>(new SnapshotSpan(span.Start, 1), new RTextErrorTag());
}
}
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
}

Getting the Internet e-mail address from an Exchange Outlook Contact programmatically?

I’m trying to read out the Internet formatted address from an Exchange connected Outlook. I read all contacts from the Outlook Contacts, i.e. not from the Global Address Book (GAB), and the problem is that for all users that are stored in Contacts from the Exchange GAB I’ve only managed to read out the X.500 formatted address which is not useful in this case. For all manually added contacts that are not in the domain of the Exchange server, the Internet address is exported as expected.
Basically I’ve used the following code snippet to enumerate the Contacts:
static void Main(string[] args)
{
var outlookApplication = new Application();
NameSpace mapiNamespace = outlookApplication.GetNamespace("MAPI");
MAPIFolder contacts = mapiNamespace.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
for (int i = 1; i < contacts.Items.Count + 1; i++)
{
try
{
ContactItem contact = (ContactItem)contacts.Items[i];
Console.WriteLine(contact.FullName);
Console.WriteLine(contact.Email1Address);
Console.WriteLine(contact.Email2Address);
Console.WriteLine(contact.Email3Address);
Console.WriteLine();
}
catch (System.Exception e) { }
}
Console.Read();
}
Is there any way to extract the Internet address instead of the X.500?
You need to convert from ContactItem to AddressEntry - one email address at a time.
To do this, you need to access the AddressEntry via the Recipient object model. The only way to retrieve the actual Recipient EntryID is by leveraging the PropertyAccessor of the ContactItem.
const string Email1EntryIdPropertyAccessor = "http://schemas.microsoft.com/mapi/id/{00062004-0000-0000-C000-000000000046}/80850102";
string address = string.Empty;
Outlook.Folder folder = this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts) as Outlook.Folder;
foreach (var contact in folder.Items.Cast<Outlook.ContactItem>().Where(c=>!string.IsNullOrEmpty(c.Email1EntryID)))
{
Outlook.PropertyAccessor propertyAccessor = contact.PropertyAccessor;
object rawPropertyValue = propertyAccessor.GetProperty(Email1EntryIdPropertyAccessor);
string recipientEntryID = propertyAccessor.BinaryToString(rawPropertyValue);
Outlook.Recipient recipient = this.Application.Session.GetRecipientFromID(recipientEntryID);
if (recipient != null && recipient.Resolve() && recipient.AddressEntry != null)
address = recipient.AddressEntry.GetExchangeUser().PrimarySmtpAddress;
}

Linq to Entities - Reference EntityKey

Now that I have built a database.
Visual Studio 2008 SP1’s ADO.NET Entity Framework has generated an Entity Model like this:
http://img835.imageshack.us/img835/1810/carease15test1ef.png
I have created a method as follow:
private void buttonAddPatient_Click(object sender, EventArgs e)
{
using (carease15test1Entities context = new carease15test1Entities())
{
long bnumber = Convert.ToInt32(textBoxToBed.Text);
long rnumber = Convert.ToInt32(textBoxOfRoom.Text);
long bid = (from b in context.bed
where b.bnumber == bnumber
select b.bid).First();
long rid = (from r in context.room
where r.rnumber == rnumber
select r.rid).First();
// Create a new bed, and input its details.
patient p = new patient();
p.pname = textBoxPatient.Text;
p.Bed_bid = bid;
p.bedReference.EntityKey = new EntityKey("carease15test1Entities.bed", "bid", bid);
p.Bed_Room_rid = rid;
p.bed.roomReference.EntityKey = new EntityKey("carease15test1Entities.room", "rid", rid);
context.AddTopatient(p);
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException ex)
{
// Resolve the concurrency conflict by refreshing the // object context before re-saving changes.
context.Refresh(System.Data.Objects.RefreshMode.ClientWins, p);
// Save changes.
context.SaveChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Everything works perfectly except for
p.bed.roomReference.EntityKey = new EntityKey("carease15test1Entities.room", "rid", rid);
It turns out a NullRefenceException saying “Object reference not set to an instance of an object.”
Here is my project files.
http://www.mediafire.com/?w3rjjbxbxw6wacv
Could anyone give me some help?
Thank you so much.
You should do
p.bedReference.Load()
So that contents of p.bed are loaded.
P.S.
If you can upgrade to .NET 4.0 it will be done automatically for you.

add shortcut to my program when right click

Im not sure what the exact term should i called. I want to add shortcut to my C# program when i right click in windows.
From my findings, it got something to do with configure the "regedit". I have this example, but it was made for IE. can anyone point me to any references that can solve my problems?
references:
http://blog.voidnish.com/?p=17
http://www.codeguru.com/cpp/misc/misc/internetexplorer/article.php/c11007/
thank you very much.
UPDATED today..
Based on response from Factor Mystic, i add this code to the original. I have 2 solutions. One, It was created in registry HKEY_ CLASSES_ ROOT, but i cannot see the result when i right click the doc files.
private const string ProgName = "Software\\Classes\\Word.Document\\shell";
private const string MenuName = "Software\\Classes\\Word.Document\\shell\\NewTesting";
public const string Command =Software\\Classes\\Word.Document\\shell\\NewTesting\\command";
private void Form1_Load(object sender, EventArgs e)
{
txtProgram.Text = "Word.Document.8";
txtName.Text = "Testing";
txtPath.Text = "C:\\temp\\encriptTest.exe";
check();
addItem()
}
public void check()
{
RegistryKey regmenu = null;
RegistryKey regcmd = null;
try
{
//this.CheckSecurity();
regmenu = Registry.ClassesRoot.OpenSubKey(MenuName, false);
}
catch (ArgumentException ex)
{
// RegistryPermissionAccess.AllAccess can not be used as a parameter for GetPathList.
MessageBox.Show(this, "An ArgumentException occured as a result of using AllAccess. "
+ "AllAccess cannot be used as a parameter in GetPathList because it represents more than one "
+ "type of registry variable access : \n" + ex);
}
catch (SecurityException ex)
{
// RegistryPermissionAccess.AllAccess can not be used as a parameter for GetPathList.
MessageBox.Show(this, "An ArgumentException occured as a result of using AllAccess. " + ex);
this.btnAddMenu.Enabled = false;
//this.btnRemoveMenu.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(this, ex.ToString());
}
finally
{
if (regmenu != null)
regmenu.Close();
if (regcmd != null)
regcmd.Close();
}
}
private void CheckSecurity()
{
//check registry permissions
RegistryPermission regPerm;
regPerm = new RegistryPermission(RegistryPermissionAccess.Write, "HKEY_CLASSES_ROOT\\" + ProgName);
regPerm.AddPathList(RegistryPermissionAccess.Write, "HKEY_CLASSES_ROOT\\" + MenuName);
regPerm.AddPathList(RegistryPermissionAccess.Write, "HKEY_CLASSES_ROOT\\" + Command);
regPerm.Demand();
}
private void addItem()
{
RegistryKey regmenu = null;
RegistryKey regcmd = null;
RegistryKey regprog = null;
try
{
regprog = Registry.ClassesRoot.CreateSubKey(ProgName);
if (regmenu != null)
regmenu.SetValue("", this.txtProgram.Text);
regmenu = Registry.ClassesRoot.CreateSubKey(MenuName);
if (regmenu != null)
regmenu.SetValue("", this.txtName.Text);
regcmd = Registry.ClassesRoot.CreateSubKey(Command);
if (regcmd != null)
regcmd.SetValue("", this.txtPath.Text);
}
catch (Exception ex)
{
MessageBox.Show(this, ex.ToString());
}
finally
{
if (regprog != null)
regprog.Close();
if (regmenu != null)
regmenu.Close();
if (regcmd != null)
regcmd.Close();
}
}
Second, create in HKEY_ LOCAL_ MACHINE.
private bool Add_Item(string Extension,string MenuName, string MenuDescription, string MenuCommand)
{
//receive .doc,OpenTest,Open with Opentest,path: C:\\temp\\encriptTest.exe %1
bool ret = false;
RegistryKey rkey = //receive .doc extension (word.Document.8)
Registry.ClassesRoot.OpenSubKey(Extension); //set HKEY_LOCAL_MACHINE\software\classes\word.Document.8
if (rkey != null)
{
string extstring = rkey.GetValue("").ToString();
rkey.Close();
if (extstring != null)
{
if (extstring.Length > 0)
{
rkey = Registry.ClassesRoot.OpenSubKey(extstring, true);
if (rkey != null) //with extension file receive OpenTest as shell
{
string strkey = "shell\\" + MenuName + "\\command"; //..\shell\OpenTest\command
RegistryKey subky = rkey.CreateSubKey(strkey);
if (subky != null)
{
subky.SetValue("", MenuCommand); // path: C:\\temp\\encriptTest.exe %1
subky.Close();
subky = rkey.OpenSubKey("shell\\" + MenuName, true); //..\shell\OpenTest
if (subky != null)
{
subky.SetValue("", MenuDescription); // name displayed: Open with &OpenTest
subky.Close();
}
ret = true;
}
rkey.Close();
}
}
}
}
return ret;
}
}
My concerned, which Main Key should i use?
I believe you want to add items to the Explorer context menu.
Here is a nice article on CodeProject that shows you how to do it:
http://www.codeproject.com/KB/cs/appendmenu.aspx (basically it's just adding the appropriate keys to the windows registry)
You're going to want to determine the file type (ProgID) of .doc files. You can find this in HKEY_CURRENT_USER\Software\Classes\.doc (it is the default value).
Then add the key HKEY_CURRENT_USER\Software\Classes\<ProgID>\shell\NewMenuOption\command, where the default value is the path to your program.
You can do all this with Registry.SetValue and GetValue.
Check out this msdn page to get started.
Edit: Additional info, the difference between hive keys:
HKEY_LOCAL_MACHINE\Software\Classes and HKEY_CURRENT_USER\Software\Classes are similar, but HKLM is for system defaults/all user settings, and HKCU is for per user settings. Per user settings don't require elevated privileges, so you can write your context menu keys as a regular user with no pain.
HKEY_CLASSES_ROOT is a view combining HKEY_LOCAL_MACHINE\Software\Classes and HKEY_CURRENT_USER\Software\Classes, with writes directed to HKLM. This is a shortcut to writing system default values, and many tutorials show this because it's slightly simpler, but unless you're installing the application for all users I don't recommend it.
Advanced registry info on MSDN
Thank you very much for the responses. Very2 apreciate Them..
As Per Conlcusion, 3 ways on solving my prob. in easy understadable approach:
Adding shortcut in 3 ways:
1. create directly in registry window:
http://www.codeguru.com/cpp/misc/misc/internetexplorer/article.php/c11007/
2. shortcut available only to folders.
http://www.codeproject.com/KB/cs/appendmenu.aspx
http://blog.voidnish.com/?p=17
3. shortcut available to all files and folders.
http://www.autoitscript.com/forum/index.php?showtopic=103265&view=findpost&p=731920

Resources