I'm trying to develop an AddIn - or rather, just a proof-of-concept for now, to see if what I have in mind is actually even possible - for Outlook (2010, to be exact), in .NET/C# and I'm facing the following problem:
The AddIn is supposed to offer a new custom Folder (on the top level of the hierarchy, i.e. next to all the other main items, like Tasks, Calendar, Contacts, etc.) in which to offer items to the user. So I figured that in the Startup method of the AddIn I could simply do something like
Outlook.Folder parent = inBox.Parent as Outlook.Folder;
Outlook.Folder myCustomFolder = (Outlook.Folder)parent.Folders.Add("My Custom Folder");
... and that does in fact work. However, there's a problem after quitting Outlook and starting it again. Since the folder is being persisted by Outlook, it is still there the next time Outlook launches and initializes the AddIn again, so the creation of the folder fails because an object of the same name already exists. But I don't see any way how to tell that this is "my" folder from last time.
I don't want to rely on its name to identify the folder (that's just too unreliable to even consider; users might want to rename it, other AddIns might exist that create a folder of the same name, not to mention localization problems etc.), but what else can I use to determine that the custom folder has already been created?
I would either have to be able to somehow add a "tag" do the folder so I can later recognize it as "mine" - or alternatively would need some kind of id that uniquely identifies the folder (and which remains constant even between launches of Outlook!) so I can recognize it by that.
I have been looking at the EntryID and StoreID fields of the [MAPI]Folder object, but from the (sadly, not very detailed) description at the MSDN, I'm not sure if I can rely on them, because apparently they can change under certain conditions.
Any suggestions?
Unless the folder is deleted and then recreated, the entry won't change. But it won't be the same folder anyway - just another folder that might have the same name.
What Outlook does is store the special folders' entryids on the root IPM folder and/or the Inbox folder.
Since you cannot set named properties on folder in Exchange and you cannot just pick your own property tag without risking running into a conflict, create a hidden message in the Inbox folder(which is always present in the default store) and store the folder entry id along with whatever else configuration properties you might need. To make sure your config hidden message is unique, pick a unique mesage class, e.g. IPM.Note.MyCompany.MyAdddin.Config.
Hidden messages can be accessed using MAPIFolder.GetStorage in the Outlook Object Model or RDOFolder.HiddenItems in Redemption.
Related
I'm adding calendar folders as below (C#):
folder = parentFolder.Folders.Add(name, Outlook.OlDefaultFolders.olFolderCalendar);
Sometimes (with no visible pattern, it's quite random), the folder appears in Outlook calendar list, sometimes it doesn't. I'd say it's fifty/fifty. When I create several folders, it can fail for the 1st one in a row, or 3rd, or 2nd. Again, no pattern.
If I restart Outlook, the missing folder finally appear in calendar list. Also, these missing folders cannot be added to navigation groups programmatically (COMException with "try again later" text occurs).
When I check and compare properties of newly created Outlook.Folder in debug windows, I see they are identical for those which are ok and which are not. In particular, DefaultItemType and DefaultMessageClass are the same as for full-on calendar folders.
At the same time, these folder do appear in Outlook folder list (which you access by clicking "..." button and then "Folders" in the context menu). They can be selected there, their contents viewed, etc. But their icon is shown as for normal folder, not calendar folder. Also, on right-click menu, I see actions specific for normal folders, like "IMAP Folders". Upon Outlook restart, their icon changes to calendar's icon.
C1 and two other folders were created fine right from the start, several others (like t2) - have this issue.
All 8 folders are created with the same code within the same loop under the same conditions at the same time.
So, looks like sometimes Outlook creates a folder but without assigning its status as Calendar (more exactly, this assignment is delayed until Outlook restart). And it's absolutely intermittent.
Can this be worked around somehow? To "force" Outlook to assign the calendar status for a folder immediately?
The issue seems to be specific for Outlook 2016, the same never occurred for me with 2010 version. Honestly saying, it looks like a bug in Outlook but I need to work it around anyway and was hoping if someone may come with any suggestions.
EDIT: The issue reproduces even if I create a folder with MFCMAPI tool, no VSTO addin or Outlook COM API involved at all. Certainly a bug in Outlook 2016.
Even if create a calendar directly in Outlook UI with New Calendar command, it happens sometimes.
In Visual Studio 2017, creating a C# Project Template project with the IWizard interface, I pop up my customised dialog to the user but I can't determine whether they've previously selected the "Create Directory For Solution" checkbox. I need to know this while still in the RunStarted() interface function, before the Project object is generated (in other words, I can't use project.DTE.Solution).
Microsoft's awesome documentation says I can just look at $SpecificSolutionName$, but it's always coming up empty for me.
Meanwhile, other StackOverflow questions are either referring to multi-project templates, or just don't have an answer. My particular problem is a simple, one-project template.
I've also tried $SolutionName$. After some frustrating days of exhausting Google, I gave up and have had to fudge things. It would be nice if I didn't have to make guesses for the name of the expected solution folder, if there is one. Worse still, to determine whether the does-it-even-exist solution folder is new or not I find myself comparing folder creation dates. Things are starting to reach a critical mass of hacky workarounds.
Q: How can I find the solution folder name, or at least whether the user has selected to create a new solution folder, inside RunStarted() of a project template wizard?
I learnt that I can just "Attach to Process... " the temporary instance of VS and debug that. So I got to have a look at the replacementsDictionary object.
Contrary to what all the docs say, the template parameter required is actually:
$SpecifiedSolutionName$
... and not "SpecificSolutionName".
That's half the mystery solved but don't let this excite you. SpecifiedSolutionName also doesn't do what the docs say it does.
From
https://learn.microsoft.com/en-us/visualstudio/ide/template-parameters:
When "create solution directory" is not checked, SpecificSolutionName [sic]
is blank.
Nope. When "create solution directory" is not checked, $SpecifiedSolutionName$ contains whatever is in $projectname$.
That would be enough for us if it wasn't for the fact that it is default behaviour for a solution directory and project directory to have the same name. But since that's a common occurrence, this $SpecifiedSolutionName$ value can't tell us whether the user created a new solution directory or not.
So I still see nothing that directly reports whether the user ticked or unticked that checkbox. There is some logic you can jump through however, thanks to another template parameter called $solutiondirectory$.
Which is also broken.
If the user ticks "Create directory for solution", then $solutiondirectory$ is the directory that will hold the solution file. If the user unticks "Create directory for solution", then $solutiondirectory$ is the directory that holds the directory that will hold the solution file, and is thus probably higher up the filesystem than you care about.
What $solutiondirectory$ reports is actually just $destinationdirectory$\..\. That is, the directory above the directory that will hold the project file. It doesn't matter if "Create directory for solution" was ticked or not, the $solutiondirectory$ parameter cares about the project's file & directory, not the solution's.
So back to the question, how do we know if the user has ticked "Create directory for solution", when solution and project might both have the same name?
Two wrongs almost make a right in this case. Compare $SpecifiedSolutionName$ to the final path element in $solutiondirectory$. If these are different, the user has definitely unticked "Create directory for solution." (Because the former will be the project name, and the latter will be whatever the filesystem has a bit higher up.)
If they are the same, the user has probably ticked that box. But there is one more thing to consider. Perhaps for some reason the directory above all of this also has the same name as the project and/or solution directory. Users can be odd like that. I don't know a sure-fire way to account for this situation (perhaps there are more directories with the same name), so I just leave it as something to be aware of.
Here's what works in VS2019:
When the user checks the 'Place solution and project in the same directory' checkbox, $specifiedsolutionname$ is empty, and $solutiondirectory$ contains the path to the root folder where everything related to the new solution is placed. When unchecked, $specifiedsolutionname$ contains a 'solution name' specified by the user (which is the name of the sub-folder created under the solution root folder, and where project(s) are placed), and $destinationdirectory$ contains the correct path to the solution root folder.
HTH
Finally, for a multi-project solution, here's what got me working:-
Solution level (multi-project) template:-
<TemplateContent>
<ProjectCollection>
<ProjectTemplateLink ProjectName="$safeprojectname$.WebApp">
WebApp\MyTemplate.vstemplate
</ProjectTemplateLink> .....
Code level changes
namespace $safeprojectname$
Due to the 1st step, the project name now includes the solution name. At project level, the namespace and the assembly name should be ideally like that, without any requirement to separate out there.
Let me know if this helps
I need to check if a given folder has a special type. For example, I need to check if a folder is an outbox folder. I know I could retrieve the outbox folder with Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderOutbox);
but that way I could only access the outbox folder of my main mailbox. Since I'm working with multiple mailboxes, that won't be enough.
I know I could difference the folder by checking its name but since the name is localized and it should work in every language, that's not acceptable solution.
Or maybe there is a way to retrieve all folders of a special type like outbox that would bring me a step forward.
Thanks for any replies.
I use
HashSet<string> excludeFolderIds = new HashSet<string>();
Outlook.Stores stores = application.Session.Stores;
foreach(Outlook.Store store in stores){
//exclude outbox folder from event
Outlook.MAPIFolder exclude = store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderOutbox);
excludeFolderIds.Add(exclude.EntryID);
}
and check later if a folder has this type by calling excludeFolderIds.Contains(folder.EntryID)
so store.GetDefaultFolder(OlDefaultFolder) is the key to get Default folders from a different account
Sorry for bothering you - but maybe somebody can help me here!?
We are creating an Outlook 2013 VSTO Add-In to manage Corporate Signatures centrally and publish them to every user as a default signature.
We already managed to create the appropriate HTML files and store them in the correct folder.
All the same, there is no problem at all to modify the appropriate Registry keys, e. g.
HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\General
where we set the value of the "Signatures" element to the folder name of the signature file(s)
HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\MailSettings
where we set the value of the "NewSignature" and "ReplySignature" elements to the name of the default signature file
HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Outlook\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676
where - within the appropriate user profile folder - we need to set the values of the "New Signature" and "Reply-Forward Signature" elements to the binary-converted name of the default signature file.
All these operations work perfectly fine and afterwards, we find the correct files in the appropriate folders and the correct entries in the Registry keys.
However, when creating the very first eMail after the Outlook and eMail Signature Add-In setup, users do NOT see the default signature!
Only as soon as they once open the "Signatures" dialog in the mail editor screen - and it is really enough to only open it; no need to click "OK" or so! - then they get the signature!
So my question is: is there any other Registry key or whatever that need(s) to be set so that the signature appears right away - without having to make users open the "Signatures" dialog!? Does anybody know what happens in the background of this dialog!?
What do I overlook!?
Thank you very much everyone - I truly hope you can help me here!
Best regards,
Torsten
The "9375CFF0413111d3B88A00104B2A6676" part is profile and account specific (it is profile section uid). It will be different for different users, profiles, and different accounts within the same profile .
You can see the data in OutlookSpy (I am its author) - click IOlkAccountManager, double click on the account, New and reply signature names will be in properties 0x0016001F and 0x0017001F respectively.
These properties can be set using Extended MAPI (C++ or Delphi) on IOlkAccount interface. You can also set them using Redemption (I am also its author - any language) - RDOAccount object exposes NewMessageSignature and Reply properties as well as Fields[] (can be used to set any property).
I got a little pet project for work. We have three mail boxes where two of them we need to get told, when we get new emails. I wanted to make a program for that (mostly just for the learning experience) and dived into the Interop libraries of Microsoft.
The two mailboxes where we need notifications, I first need to locate those mailboxes and then I can assign things like event listeners, etc. But I don't know how to achieve this.
To find the root, I do this:
outlookNameSpace = outlookApplication.GetNamespace("MAPI");
And then I can start dragging out folders and assign them to variables like so:
supportInbox = outlookNameSpace.Folders["Omitted"].Folders["Inbox"];
pensionInbox = outlookNameSpace.Folders["Omitted"].Folders["Inbox"];
But the code says that it cannot find the folders with the names (that I replaced with "Omitted" just for sake of privacy).
What am I doing wrong?
If you are accessing multiple Mailboxes, you have to first ensure that they are both loaded in the current Outlook profile. Otherwise, you need to ensure that the currently logged on user has delegate access to the Mailbox you want to access and use the NameSpace.GetSharedDefaultFolder method to open their Inbox. However, you only have access to the Inbox with Delegate scenarios.
Otherwise, to get specific folders for a specific Mailbox in the current profile, you can try this approach:
How to: Obtain a Folder Object from a Folder Path
http://msdn.microsoft.com/en-us/library/ff868990(v=office.15).aspx
You may also need to loop through NameSpace.Stores to get a specific Store object for the Mailbox, and access a folder via Store.GetRootFolder or Store.GetDefaultFolder.