How to programmatically select a folder to view in Outlook 2010? - c#

I am programmatically creating a search folder via Search.Save method. After I save the search (it creates a new folder in the Search Folders directory), I would like to set to focus on this newly created folder such that the view changes to this folder.
This is the code I have thus far....
searchFolders = inboxFolder.Store.GetSearchFolders();
foreach (Outlook.Folder folder in searchFolders)
{
if (folder.Name == "Expiring Retention Policy Mail")
{
folder.ShowItemCount = Microsoft.Office.Interop.Outlook.OlShowItemCount.olShowTotalItemCount;
//folder.SetCustomIcon(new Bitmap(32, 32));
folder.Display();
}
}
When I do folder.Display() it opens up an entirely new inspector window... I don't want this to happen, I simply want to select it (like via set focus?) and have it viewed in the same inspector window it exists in. Does anybody know how to do this?
Thank you.

This should work for you...
Get access to your Application object (or from the main add-in class). And then
this.Application.ActiveExplorer().CurrentFolder = folder;
i.e. you can use CurrentFolder of the ActiveExplorer
Of course, always make sure to properly release your COM objects (the ones that need releasing) - and
you should never do it like I did here (for simplicity) - i.e. chaining properties like
that. Save each (property) into a variable, and release via
Marshal.ReleaseComObject on your way out.

Related

What is the best way to store some data in VSTO addin?

I have developed one outlook add-in, that has to be On or Off.
to do that i have declared one static variable as shown below,
ThisAddIn.cs
public static bool isAddInOn = false;
RibbonButton.cs
private void btnRibbon_Click(object sender, RibbonControlEventArgs e)
{
if (ThisAddIn.isAddInOn )
{
ThisAddIn.isAddInOn = false;
btnRibbon.Label = "Disabled";
}
else
{
ThisAddIn.isAddInOn = true;
btnRibbon.Label = "Enabled";
}
}
It is working. But the static variable reset again when i close outlook and open it again. That means when i open outlook by default my add-in is in disabled state.
I just want to store that value at some place. so i can check that value when outlook reopened.
Scenario:
1) open outlook
2) Enable add-in by clicking on its logo (that is in ribbon)
3) now close the outlook
4) when i open outlook again it must enabled
so how can i achieve this ?
There are several techniques you can use to achieve this result. For sure your settings must be serialized to some storage/deserialized during startup of add-in.
One of possible solution could be to use registry for that (in this case probably HKCU (Current user, then it will be private for each user using your add-in) and no special permission is needed.
For storing variable:
public void StoreInRegistry(string keyName, string value)
{
RegistryKey rootKey = Registry.CurrentUser;
string registryPath = #"Software\YourCompanyName\YourAddInName";
using (RegistryKey rk = rootKey.CreateSubKey(registryPath))
{
rk.SetValue(keyName, value, RegistryValueKind.String);
}
}
For reading variable:
public string ReadFromRegistry(string keyName, string defaultValue)
{
RegistryKey rootKey = Registry.CurrentUser;
string registryPath = #"Software\YourCompanyName\YourAddInName";
using (RegistryKey rk = rootKey.OpenSubKey(registryPath, false))
{
if (rk == null)
{
return defaultValue;
}
var res = rk.GetValue(keyName, defaultValue);
if (res == null)
{
return defaultValue;
}
return res.ToString();
}
}
Such stored/retrieved variable should be used during add-in initialization to set your properties. So modification could look like:
ThisAddin.cs
public static bool isAddInOn = ReadFromRegistry("MySetting1", "0") == "1";
RibbonButton.cs
private void btnRibbon_Click(object sender, RibbonControlEventArgs e)
{
if (ThisAddIn.isAddInOn )
{
ThisAddIn.isAddInOn = false;
btnRibbon.Label = "Disabled";
}
else
{
ThisAddIn.isAddInOn = true;
btnRibbon.Label = "Enabled";
}
StoreInRegistry("MySetting1", ThisAddIn.isAddInOn ? "1" : "0");
}
Other options could serialization to file - some class with settings serialized to i.e. isolated storage, database (local or central) etc.
I've used several methods over the years to store configuration data for users.
Properties.Settings.Default.Properties, so writing in the application project properties. It's solid, never had an issue with it, for hundreds of users over several years.
Local config files in text, so writing to a known area for the user with fallback. In a stable environment, one can choose the home area for the user, and read/write to the local config file, which also makes it accessible to support if it breaks and needs manual changes. As a fallback, one could write to the local temp folder.
Registry is an option i have not used in this case, but it is likely to be a good choice.
Performance is likely a key concern considering it will impact the UI for users. Another concern is ease of use for the developer. For both, my choice would be setting it in the application's properties, where reading and writing is very simple and handled within code, and likely very fast.
Write
Properties.Settings.Default.PropertyName = propertValue;
Read
var propertValue = Properties.Settings.Default.PropertyName;
2018 UPDATED ANSWER
The recommended way to achieve this is now to use the already configured settings files in your project's properties. These files are auto-generated when create your project :
And open the following window when clicked :
You can access your settings value programmatically into Properties.Settings.Default.Properties anywhere.
The header bar at the top of the Settings page contains several controls:
Synchronize
Synchronize restores user-scoped settings that the application uses at run time or during debugging to their default values as defined at design time. To restore the data, remove run-time generated application-specific files from disk, not from project data.
Load Web Settings
Load Web Settings displays a Login dialog box that enables you to load settings for an authenticated user or for anonymous users. This button is enabled only when you've enabled client application services on the Services page and specified a Web settings service location.
View Code
For C# projects, the View Code button enables you to view the code in the Settings.cs file. This file defines the Settings class, which enables you to handle specific events on the Settings object. In languages other than Visual Basic, you must explicitly call the Save method of this wrapper class in order to persist the user settings. You usually do this in the Closing event handler of the main form. Following is an example of a call to the Save method:
C#
Properties.Settings.Default.Save();
For Visual Basic projects, the View Code button enables you to view the code in the Settings.vb file. This file defines the MySettings class, which enables you to handle specific events on the My.Settings object. For more information about accessing application settings by using the My.Settings object, see Access application settings.
For more information about accessing application settings, see Application settings for Windows Forms.
Access modifier
The Access modifier button specifies the access level of the Properties.Settings (in C#) or My.Settings (in Visual Basic) helper classes that Visual Studio generates in Settings.Designer.cs or Settings.Designer.vb.
For Visual C# projects, the access modifier can be Internal or Public.
For Visual Basic projects, the access modifier can be Friend or Public.
By default, the setting is Internal in C# and Friend in Visual Basic. When Visual Studio generates helper classes as Internal or Friend, executable (.exe) applications cannot access the resources and settings that you have added to class libraries (.dll files). If you have to share resources and settings from a class library, set the access modifier to Public.
For more information about the settings helper classes, see Manage application settings.
Settings grid
Settings Grid is used to configure application settings. This grid includes the following columns:
Name
Enter the name of the application setting in this field.
Type
Use the drop-down list to select a type for the setting. The most frequently used types appear in the drop-down list, for example, String, (Connection string), and System.Drawing.Font. You can choose another type by selecting Browse at the end of the list, and then selecting a type from the Select a Type dialog box. After you choose a type, it's added to the common types in the drop-down list (for the current solution only).
Scope
Select either Application or User.
Application-scoped settings, such as connection strings, are associated with the application. Users can't change application-scoped settings at run time.
User-scoped settings, such as system fonts, are intended to be used for user preferences. Users can change them at run time.
Value
The data or value associated with the application setting. For example, if the setting is a font, its value could be Verdana, 9.75pt, style=Bold.
Documentation link
Reading settings
Writing settings
Settings can be stored as a hidden (associated) item in a folder, such as the Inbox or the Calendar folder. For example, Outlook stores the list of categories as a hidden item in the Calendar folder. POP3 message ids are stored in a hidden item in the Inbox. The advantage of the hidden items is the roaming capability - Exchange mailbox user can see the data from any computer.
You can see the hidden items in OutlookSpy (I am its author) - click IMAPIFolder button, go to the "Associated Contents" tab.
Programmatically, such items can be accessed using MAPIFolder.GetStorage in the Outlook Object Model.

c# customizing controls on a save dialog -- how to disable parent folder button?

I am working from the sample project here: http://www.codeproject.com/Articles/8086/Extending-the-save-file-dialog-class-in-NET
I have hidden the address/location bar at the top and made other modifications but I can't for the life of me manage to disable the button that lets you go up to the parent folder. Ist is in the ToolbarWindow32 class which is the problem. This is what I have at the moment but it is not working:
int parentFolderWindow = GetDlgItem(parent, 0x440);
//Doesn't work
//ShowWindow((IntPtr)parentFolderWindow, SW_HIDE);
//40961 gathered from Spy++ watching messages when clicking on the control
// doesn't work
//SendMessage(parentFolderWindow, TB_ENABLEBUTTON, 40961, 0);
// doesn't work
//SendMessage(parentFolderWindow, TB_SETSTATE, 40961, 0);
//Comes back as '{static}', am I working with the wrong control maybe?
GetClassName((IntPtr)parentFolderWindow, lpClassName, (int)nLength);
Alternatively, if they do use the parent folder button and go where I don't want them to, I'm able to look at the new directory they land in, is there a way I can force the navigation to go back?
Edit: Added screenshot
//Comes back as '{static}', am I working with the wrong control maybe?
You know you are using the wrong control, you expected to see "ToolbarWindow32" back. A very significant problem, a common one for Codeproject.com code, is that this code cannot work anymore as posted. Windows has changed too much since 2004. Vista was the first version since then that added a completely new set of shell dialogs, they are based on IFileDialog. Much improved over its predecessor, in particular customizing the dialog is a lot cleaner through the IFileDialogCustomize interface. Not actually what you want to do, and customizations do not include tinkering with the navigation bar.
The IFileDialogEvents interface delivers events, the one you are looking for is the OnFolderChanging event. Designed to stop the user from navigating away from the current folder, the thing you really want to do.
While this looks good on paper, I should caution you about actually trying to use these interfaces. A common problem with anything related to the Windows shell is that they only made it easy to use from C++. The COM interfaces are the "unfriendly" kind, interfaces based on IUnknown without a type library you can use the easily add a reference to your C# or VB.NET project. Microsoft published the "Vista bridge" to make these interfaces usable from C# as well, it looks like this. Yes, yuck. Double yuck when you discover you have to do this twice, this only works on later Windows versions and there's a strong hint that you are trying to do this on XP (judging from the control ID you found).
This is simply not something you want to have to support. Since the alternative is so simple, use the supported .NET FileOk event instead. A Winforms example:
private void SaveButton_Click(object sender, EventArgs e) {
string requiredDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
using (var dlg = new SaveFileDialog()) {
dlg.InitialDirectory = requiredDir;
dlg.FileOk += (s, cea) => {
string selectedDir = System.IO.Path.GetDirectoryName(dlg.FileName);
if (string.Compare(requiredDir, selectedDir, StringComparison.OrdinalIgnoreCase) != 0) {
string msg = string.Format("Sorry, you cannot save to this directory.\r\nPlease select '{0}' instead", requiredDir);
MessageBox.Show(msg, "Invalid folder selection");
cea.Cancel = true;
}
};
if (dlg.ShowDialog() == DialogResult.OK) {
// etc...
}
}
}
I don't this is going to work. Even if you disable the button they can type ..\ and click save and it will take them up one level. You can't exactly disable the file name text box and maintain the functionality of the dialog.
You'd be better off either using the FolderBrowserDialog and setting it's RootFolder property and asking the user to type the filename in or auto generating it.
If the folder you are wanting to restrict the users to isn't an Environment.SpecialFolder Then you'll need to do some work to make the call to SHBrowseForFolder Manually using ILCreateFromPath to get a PIDLIST_ABSOLUTE for your path to pass to the BROWSEINFO.pidlRoot
You can reflect FolderBrowserDialog.RunDialog to see how to make that call.
Since you want such custom behaviors instead of developing low level code (that is likely yo break in the next versions of windows) you can try to develop your file picker form.
Basically it is a simple treeview + list view. Microsoft has a walk-through .
It will take you half a day but once you have your custom form you can define all behaviors you need without tricks and limits.

Check if the current document in Visual Studio 2012 is a Code Window

I am looking for a way to have my extension check if the currently opened window in visual studio 2012 is one, where the user can write code (or any kind of text, really).
To check if the currently opened window has changed, I use
_DTE.Events.WindowEvents.WindowActivated.
This gives me the EnvDTE.Window that received the focus.
When I look at the properties of that window while debugging, and I look at EnvDTE.Window.Document.Type and it's value is "Text".
However, if I stop debugging and try to access the Document.Type property, it does not exist.
If I look for this property in the documentation of EnvDTE.Window.Document, its description says
Infrastructure. Microsoft Internal Use Only.
So now I am looking for any advice on how I could check if the currently active window is one, where I can write code (or anything else), or some other kind of document (like the solution properties for example).
Edit:
I also tried checking Window.Type and Window.Kind of the active window, but they just tell me that it's a document, not making any differentiation between a resource file, an image file or an actual source file, which is what I'm trying to find out.
Edit²:
The reason why I want to check if the current document is one where I can write code in, is because I want my extension to store information about some of those documents and I want to modify the right-click context menu based on the information I have stored, if any.
It is not a "real" answer, but you can follow status of VS GoTo command - it is available only for text editors:
bool isCodeWindow = IsCommandAvailable("Edit.GoTo");
private bool IsCommandAvailable(string commandName)
{
EnvDTE80.Commands2 commands = dte.Commands as EnvDTE80.Commands2;
if (commands == null)
return false;
EnvDTE.Command command = commands.Item(commandName, 0);
if (command == null)
return false;
return command.IsAvailable;
}
You can check to see if the document is a 'TextDocument'
bool isCodeWindow = dte.CurrentDocument.Object() is EnvDTE.TextDocument;

Using Coded UI to Simulate File Drag and Drop Operation

I have a WinForm application which is a drop target for files and folders. I'd like to use Coded UI to have an automated tests that verifies the application does what I think it should do when files were dropped on it.
I used the Coded UI recorder to record this operation, but I need to generalize it and make it work on CI server. So I basically want to init the test with some pre-setup file paths (the files can be created as part of the test setup), and then just trigger the drop event passing in the paths to those files on the file system.
Coded UI records the test but produces a test like:
WinListItem uIContactcshtmlListItem = this.UIProgramManagerWindow.UIDesktopList.UIContactcshtmlListItem;
WinText uIDragDropFilesHereText = this.UIMyApp.UIDragDropFilesHereWindow.UIDragDropFilesHereText;
uIDragDropFilesHereText.EnsureClickable(new Point(84, 13));
Mouse.StartDragging(uIContactcshtmlListItem, new Point(17, 35));
Mouse.StopDragging(uIDragDropFilesHereText, new Point(84, 13));
The "uIContactcshtmlListItem" appears to represent the source files I dropped. (A contacts.cs file happens to be one of the things I dragged/dropped during the recording.) I want to replace this with just some file paths, but this appears to essentially be a list item type control from Explorer.
Is there a way to accomplish what I want? Perhaps by creating a WinListItem in the code manually?
This is how I would do it (requires some coding):
Record opening a windows explorer, writing in the address bar and pressing enter. Then record dragging a file to your application (drag it by its icon to avoid future frustrations). Add your assertions. Record closing the windows explorer. These should be four methods plus the assertions: open explorer, set address, drag file, close explorer.
Now you have your base methods. Call the method that opens the explorer first then loop thru your input file paths. In the loop: set the parameters for the 'set address' and 'drag files' methods for the file (you can check the current directory in the explorer and only call 'set address' if needed) and the name search property for the ListItem UIControl (the control/file you want to drag). Call Find() on the ListItem/Image UIControl or set AlwaysSearch for this control in the UIMap (you need this because we are reusing a UIControl here which is cached on a previous object) then call the 'drag file' method. Then check your assertions.
Finally call the 'close explorer' method. You will probably have to tweak around a bit in the UIMap to make things work properly (change search properties and stuff).
Of course this is not the only way to do it, not the best either but might be a good start.
Change the search parameter
WinListItem uIContactcshtmlListItem = this.UIProgramManagerWindow.UIDesktopList.UIContactcshtmlListItem;
WinText uIDragDropFilesHereText = this.UIMyApp.UIDragDropFilesHereWindow.UIDragDropFilesHereText;
uIContactcshtmlListItem.SearchProperties.Remove(UITestControl.PropertyNames.Name);
uIContactcshtmlListItem.SearchProperties.Add("Name", "ItemName" or variable);
or uIContactcshtmlListItem.SearchProperties.Add("Name", "PartOfTheName", PropertyExpressionOperator.Contains);
uIDragDropFilesHereText.EnsureClickable(new Point(84, 13));
Mouse.StartDragging(uIContactcshtmlListItem, new Point(17, 35));
Mouse.StopDragging(uIDragDropFilesHereText, new Point(84, 13));

How to get the (.lnk) shortcut filepath in a program which started by the shortcut?

I have a c# program which open *.postfix file.
If a user runs a (.lnk)shortcut which points to my type of file, my program will open the target.
So, how could my program know it is started by a (.lnk)shortcut (and get it's file path)?
In some circumstances,i need to replace the .lnk file.
Thanks!
Edited
First, thanks to guys who answered my question.
By following #Anders answer, i find out my problem lays here.
I made some changes to windows registry, so browser knows to throw customized protocol string to certain program.
some thing like this..
[InternetShortcut]
URL=myProtocol://abcdefg.....
That's maybe why i lost lpTitle. :(
I'm going to try this way:
Whenever my program invoked, of course fed with %1, program checks current opened explorer(Window), and try to get it's current path with IWebBrowserApp. With that path and desktop of course, scan and analyze *.lnk to determine which one to replace.
I think this will probably work, but not be sure. I will try.
continued
In native code you can call GetStartupInfo, if the STARTF_TITLEISLINKNAME bit is set in STARTUPINFO.dwFlags then the path to the .lnk is in STARTUPINFO.lpTitle. I don't know if there is a .NET way to get this info, you probably have to P/Invoke...
You don't. There's no way to do it. End of story.
So this has been brought to my attention due to a recent downvote. There's an accepted answer showing an idea that gets the path to the launching shortcut most of the time. However my answer is to the whole. OP wants the link to the shortcut so he can change it. That is what can't be done most of the time.
Most likely case is the shortcut file exists in the start menu but is unwritable. However other cases involve the shortcut coming from another launching application that didn't even read it from a disk but from a database (I've seen a lot of corporate level restricted application launch tools). I also have a program that launches programs from shortcuts not via IShellLink but by parsing the .lnk file (because it must not start COM for reasons) and launching the program contained. It doesn't pass STARTF_TITLEISLINKNAME because it's passing an actual title.
If you're using Visual Studio Setup Project to build an installer and do the file type association, you should follow these instructions http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Open up your solution in Visual studio.
Add a Setup Project to your solution by file , add project,New project, Setup & Deployment projects,Setup project
Right-click on your setup project in the "Solution Explorer" window,Select view,then select file types.
you'll see the "file types" window displayed in Visual studio.At the top of the window will be "File types on target machine"
Right-click on "File types on target machine".the menu will pop up with Add "file type" Click on this.
you'll see "New document Type#1" added,and "&open"underneath it.
The "new document type#1" can be anything you want - change it to something descriptive.although the user never sees this,never use something common- be as unique as possible,Because you can overlay current file associations without even realizing it.For example,you might think"pngfile" might be a useful name- but using that will now send all"*.png" files to your application,instead of to an image viewer.A good practice maybe "YourCompantName.Filetype",where your company name is your name of your company's name, and "Filetype" is a descriptive text of your file.
In the "properties" window for your new type,you will need to change a few properties.:
Command:Change to the application that you want to run.If you click on the "..." and you will proberly want to locate and use the "primary Output..." File
Description: This is the description of the file type(if it doesn't describe it's self"
Extensions:This your list of extensions for you chosen Program.Separate each one with a ","
Icon:This will associate the icon with your file type,This shows up in the window explorer.
Now we move to that "&open ".This is an action that is available if your right-click on the file.The default action("&Open" is currently set as the default) is what happens when you double click on the file.Right click on your "New document type#1" to add actions,but for the moment,lets define our "&open" action
Click on "&Open".You will see in the properties window "Name","Arguments","Verbs". Verb is hidden from the user,but is the key that is stored in the registry.Leave it same as the name,But without the "&".The default for"Arguments" is "%1",Which means to pass the full path and filename to your application.You can add other stuff here as well,if you need to pass flags to your application to do special stuff.All this infomaton is getting passed to your application on the command line,so you'll need to be familiar with the "Environment.CommandLine" object.
If you need to set a different action as your default,just right click on the action and "set as default"
Basically, you'll pass the file path as an argument to your program. Then if it's a console application or Windows Forms , you should check the arguments in Program.Main
static void Main(string[] args)
{
//if file association done with Arguments %1 as per forum post above
//you file path should be in args[0]
string filePath = null;
if(args != null && args.Length > 0)
filePath = args[0];
}
For a WPF application you'll need to handle that in the StartUp event for your Application
void App_Startup(object sender, StartupEventArgs e)
{
string filePath = null;
if ((e.Args != null) && (e.Args.Length > 0))
{
filePath = e.Args[0];
}
}

Categories

Resources