Using Coded UI to Simulate File Drag and Drop Operation - c#

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));

Related

Register context menu verbs for specific file types

I'm registering extended verbs for all video file types on my system by doing something like this:
foreach (var ext in FileTypes.VideoTypes)
{
var progId = Registry.GetValue($#"HKEY_CLASSES_ROOT\.{ext}", null, null);
if (progId == null)
{
continue;
}
Registry.SetValue(
$#"HKEY_CURRENT_USER\SOFTWARE\Classes\{progId}\shell\dlsub",
null,
"Download subtitle");
Registry.SetValue(
$#"HKEY_CURRENT_USER\SOFTWARE\Classes\{progId}\shell\dlsub\command",
null,
#"""D:\myapp.exe"" ""%1""");
}
Resulting in something like this (mpeg_auto_file for mkv):
[HKEY_CLASSES_ROOT\mpg_auto_file\shell\dlsub]
#="Download subtitle"
[HKEY_CLASSES_ROOT\mpg_auto_file\shell\dlsub\command]
#="\"D:\\myapp.exe\" \"%1\""
and mplayerc.mp4 for mp4:
[HKEY_CLASSES_ROOT\mplayerc.mp4\shell\dlsub]
#="Download subtitle"
[HKEY_CLASSES_ROOT\mplayerc.mp4\shell\dlsub\command]
#="\"D:\\myapp.exe\" \"%1\""
The problem is that the registered verb shows up for mkv (and a couple of other filetypes), but the context menus for the other file types (like mp4) are unaffected. Adding my verb to HKEY_CLASSES_ROOT\*\shell does work for these filetypes, but this is obviously not what I want!
Any ideas on the difference between these filetypes? Perhaps it has something to do with the registered ProgID (all mplayerc types do not seem to work...).
The default value (aka ProgId) that can be found for specific file extension doesn't always point to correct class (the one that will affect menu entries). During my tests, even on fresh copy of Windows 10 - WMP11.AssocFile.AVI is a ProgId for .avi file extension, however when added entry in WMP11.AssocFile.AVI\Shell\ (either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER) it didn't affect menu at all. I was about to give up but then i found that HKEY_CLASSES_ROOT\.avi\OpenWithProgids store few more values, including WMP11.AssocFile.AVI but also other that starts with word App, i.e. AppX6eg8h5sxqq90pv53845wmnbewywdqq5h. By editing Shell\ for that one, i was able to add menu entry. The downside was - it also affected other file extensions that are somehow linked with AppX6eg8h5sxqq90pv53845wmnbewywdqq5h. I couldn't accept solution that would force me to iterate through all classes found in OpenWithProgids, plus my menu entry had to be shown only for very specific file extensions and not the other. I decided to go with HKEY_CLASSES_ROOT\*\shellex and DLLs that create menu entry dynamically, based on clicked file type (check for extension).

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.

How to programmatically select a folder to view in Outlook 2010?

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.

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];
}
}

How to read in text from the visual studio debug output window

I've read several articles that tell you how to add text to the output window in visual studio from within an Add-On (specifically, a visual studio 2008 integration package, via the visual studio 2008 SDK 1.1), but no examples of how to read text from the output window. My goal is to parse text from the debug output window while debugging a certain application (TRACE output and possibly stdin/stdout). The IVsOutputWindowPane interface has no methods for reading in text from the output window. The documentation seems to imply that it is possible, but it doesn't provide an example:
http://msdn.microsoft.com/en-us/library/bb166236(VS.80).aspx
Quote: In addition, the OutputWindow and OutputWindowPane objects add some higher-level functionality to make it easier to enumerate the Output window panes and to retrieve text from the panes.
Preferably I'd like to be able to subscribe to an event that fires when a new line of text arrives, similar to a StreamReader's asynchronous reads.
It is possible, it is just a long winding path to get to it:
ServiceProvider -> IVsOutputWindow -> GetPane( debugwindow ) -> IVsUserData -> GetData( wpftextviewhost ) -> IWpfTextViewHost -> IWpfTextView -> TextBuffer -> Changed event.
Presuming you have a VS IServiceProvider from somewhere else (vsix extension/whatever, global service provider), and without any error checking, it looks like this:
IVsOutputWindow outWindow = ServiceProvider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
IVsOutputWindowPane pane;
outWindow.GetPane(ref debugPaneGuid, out pane);
// from here up you'll find in lots of other stackoverflow answers,
// the stuff from here down is interesting to this question
IVsUserData userData = (IVsUserData)pane;
object o;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out o);
IWpfTextViewHost viewHost = (IWpfTextViewHost)o;
IWpfTextView textView = viewHost.TextView;
textView.TextBuffer.Changed += YourTextChangedHandlerHere;
Your text changed handler will then get called every time the output window gets more data. you won't necessarily get it line by line, but you'll probably more likely than not get big chunks you'll need to deal with on your own.
It is highly likely that some of the above did not even exist in VS in 2010. But it exists now!
The default behavior (when you don’t set the listener explicitly) of VS is to display trace massages in the debugger output window, which you appreciate if you want a simple solution and do no other actions with the massages.
Unfortunately this is not your case. So you have to define a trace listener to send (and store) your trace massages where you then will be able to read them. The trace listener could be a file (for example XML) or you can create a custom listener by deriving a class from the base class TraceListener if you don't want to bother yourself with an additional file.
I don't know that what you ask is possible. But, you can register your add-in as a debugger for your application so that you get the output the trace messages. These are typically routed to OutputDebugString, and can be captured as described in this article: http://www.drdobbs.com/showArticle.jhtml?articleID=184410719. It does not give you the normal output, only debug, but it does not depend on the technology of the debugged application.
The solution on this page selects the text in order to read it. I'm hoping there's a better way.
Automatically stop Visual C++ 2008 build at first compile error?
Private Sub OutputWindowEvents_OnPaneUpdated(ByVal pPane As OutputWindowPane) Handles OutputWindowEvents.PaneUpdated
pPane.TextDocument.Selection.SelectAll()
Dim Context As String = pPane.TextDocument.Selection.Text
pPane.TextDocument.Selection.EndOfDocument()
End Sub

Categories

Resources