I am developing a c# desktop application.
We need to unpin our application tile based on number of conditions. this could happen anytime during the application life-cycle, and not only during installation.
I saw this question on how to unpin a tile in CPP. I tried to do that also in C# with no success.
any help?
Update:
I was able to write a C# code that sets the AppUserModel_StartPinOption to APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL but it didn't help :(
this is the code:
private static void InstallShortcut(string linkPath)
{
// Find the path to the current executable
// String exePath = Process.GetCurrentProcess().MainModule.FileName; //Path to the current exe file that is running. C:\\...
IShellLinkW newShortcut = (IShellLinkW)new CShellLink();
// Create a shortcut to the exe
ErrorHelper.VerifySucceeded(newShortcut.SetPath(targetPath));
ErrorHelper.VerifySucceeded(newShortcut.SetArguments(""));
// Open the shortcut property store, set the AppUserModelId property
IPropertyStore newShortcutProperties = (IPropertyStore)newShortcut;
var APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL = new PropVariant(0);
var StartPinOption = new PropertyKey(new Guid("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}"), 12);
ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(StartPinOption, APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL));
ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
// Commit the shortcut to disk
IPersistFile newShortcutSave = (IPersistFile)newShortcut;
ErrorHelper.VerifySucceeded(newShortcutSave.Save(linkPath, true));
}
I tried both: removing the tile and then recreating it, and changing the params of an existing tile, but nothing worked, the tile stays pinned to the start menu.
Are you talking about your main application tile or a secondary tile? If you are referring to a secondary tile, there is sample code for unpinning in this article. The meat of it is (and I'm modifying a bit for simplicity; see the article for the full code):
// Check to see if this restaurant exists as a secondary tile and then unpin it
string restaurantKey = this.m_ViewModel.Restaurant.Key;
Button button = sender as Button;
if (button != null)
{
if (Windows.UI.StartScreen.SecondaryTile.Exists(restaurantKey))
{
SecondaryTile secondaryTile = new SecondaryTile(restaurantKey);
bool isUnpinned = await secondaryTile.RequestDeleteForSelectionAsync(GetElementRect((FrameworkElement)sender), Windows.UI.Popups.Placement.Above);
if (!isUnpinned)
{
// Do error handling here
}
}
else
{
// If we ever get to this point, something went wrong or the user manually
// removed the tile from their Start screen.
Debug.WriteLine(restaurantKey + " is not currently pinned.");
}
}
According to the MSDN article: System.AppUserModel.StartPinOption (Windows), the No pin install option should be (1)
var APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL = new PropVariant(1);
I got it working by doing this.
Related
Im trying to translate this VBA code from an Outlook AddIn to C#
Private Sub objInspector_Activate() Handles objInspector.Activate
Dim wdDoc As Microsoft.Office.Interop.Word.Document = objInspector.WordEditor
wdDoc.Windows(1).Panes(1).View.Zoom.Percentage = lngZoom
End Sub
But I can't get access to the Panes.View.Zoom.Percentage property
The main idea is that when the user opens an email, he will get a custom zoom level.
What I got at the moment is:
void Inspector_Activate()
{
// this bool is true
// bool iswordMail = objInspector.IsWordMail();
//I get the word document
Document word = objInspector.WordEditor as Microsoft.Office.Interop.Word.Document;
word.Application.ActiveDocument.ActiveWindow.View.Zoom.Percentage = 150;
// at this point i'm getting an exception
// I've also tried with
// word.ActiveWindow.ActivePane.View.Zoom.Percentage = 150; getting the same exception
}
The exception is :
An exception of type 'System.Runtime.InteropServices.COMException'
occurred in OutlookAddInTest.dll but was not handled in user code
Additional information: This object model command is not available in
e-mail.
I'm quite new in C# and Office addins, any advise?
Use word.Windows.Item(1).View.Zoom.Percentage = 150 (where word comes from Inspector.WordEditor)
word.Application.ActiveDocument.ActiveWindow.View.Zoom.Percentage = 150;
What property exactly fires the exception?
Anyway, there is no need to call the Application and ActiveDocument properties in the code. The WordEditor property of the Inspector class returns an instance of the Document class (not Word Application instance).
Thanks to Eugene Astafiev for his help.
The square brackets did the trick
VBA
Private Sub objInspector_Activate() Handles objInspector.Activate
Dim wdDoc As Microsoft.Office.Interop.Word.Document = objInspector.WordEditor
wdDoc.Windows(1).Panes(1).View.Zoom.Percentage = 150
End Sub
C#
private void Inspector_Activate()
{
Document wdDoc = objInspector.WordEditor;
wdDoc.Windows[1].Panes[1].View.Zoom.Percentage = 150;
}
I've been wanting this forever, and then I stumbled on a nice project in the MSDN Gallery Outlook 2010: Developing an Inspector Wrapper. It has a set of wrappers for all the Outlook objects, so you get a true event for every item of interest. Not sure if it's the most efficient thing ever, but it seems to work.
I have trouble with my eyesight so want black everything, and zoom everything. I seem to be able to do that by overriding the Activate() method. It's all pretty new so we'll see if it survives long term.
protected virtual void Activate() {
var activeDocument = Inspector.WordEditor as Document;
if (activeDocument == null)
return;
var mailZoom = GetSetting("MailZoom", 125);
if (mailZoom != 0)
activeDocument.Windows[1].View.Zoom.Percentage = mailZoom;
if (GetSetting("MailBlack", true)) {
activeDocument.Background.Fill.ForeColor.RGB = 0;
activeDocument.Background.Fill.Visible = msoTrue;
activeDocument.Saved = true;
}
}
In this example, GetSetting is just a function that returns a setting from an INI file. you can use constants or some other storage method.
There might be a better way to get the white on black text, but this seems pretty good.
Thanks in advance.
Is it possible to activate a tab in another program using an IntPtr? If so, how?
SendKeys is not an option.
Perhaps what I need is a fishing lesson. I have exhausted Google and my lead developer.
I would appreciate an outright solution OR a recommendation to continue my Google efforts.
basic process is:
I drag a shortcut icon to the launcher
This opens the target application (Notepad++) and grabs IntPtr, etc.
I would like to programmatically select various items in Notepad++ such as Edit, menu items under Edit, or a doc tab.
The basic code I am running is:
the 'blob'
item 1: IntPtr of item
item 2: IntPtr of itemsChild
item 3: control text of item 1
item 4: is rectangle parameters of item 1
root contains similar info:
As others pointed out, the standard way of doing this is to use UI Automation. Notepad++ does support UI Automation (to some extent, as it's somehow automatically provided by the UI Automation Windows layers).
Here is a sample C# console app that demonstrates the following sceanrio (you need to reference UIAutomationClient.dll, UIAutomationProvider.dll and UIAutomationTypes.dll):
1) get the first running notepad++ process (you must start at least one)
2) open two files (note there may be already other opened tabs in notepad++)
3) selects all tabs in an infinite loop
class Program
{
static void Main(string[] args)
{
// this presumes notepad++ has been started somehow
Process process = Process.GetProcessesByName("notepad++").FirstOrDefault();
if (process == null)
{
Console.WriteLine("Cannot find any notepad++ process.");
return;
}
AutomateNpp(process.MainWindowHandle);
}
static void AutomateNpp(IntPtr handle)
{
// get main window handle
AutomationElement window = AutomationElement.FromHandle(handle);
// display the title
Console.WriteLine("Title: " + window.Current.Name);
// open two arbitrary files (change this!)
OpenFile(window, #"d:\my path\file1.txt");
OpenFile(window, #"d:\my path\file2.txt");
// selects all tabs in sequence for demo purposes
// note the user can interact with n++ (for example close tabs) while all this is working
while (true)
{
var tabs = GetTabsNames(window);
if (tabs.Count == 0)
{
Console.WriteLine("notepad++ process seems to have gone.");
return;
}
for (int i = 0; i < tabs.Count; i++)
{
Console.WriteLine("Selecting tab:" + tabs[i]);
SelectTab(window, tabs[i]);
Thread.Sleep(1000);
}
}
}
static IList<string> GetTabsNames(AutomationElement window)
{
List<string> list = new List<string>();
// get tab bar
var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab));
if (tab != null)
{
foreach (var item in tab.FindAll(TreeScope.Children, PropertyCondition.TrueCondition).OfType<AutomationElement>())
{
list.Add(item.Current.Name);
}
}
return list;
}
static void SelectTab(AutomationElement window, string name)
{
// get tab bar
var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab));
// get tab
var item = tab.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, name));
if (item == null)
{
Console.WriteLine("Tab item '" + name + "' has been closed.");
return;
}
// select it
((SelectionItemPattern)item.GetCurrentPattern(SelectionItemPattern.Pattern)).Select();
}
static void OpenFile(AutomationElement window, string filePath)
{
// get menu bar
var menu = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuBar));
// get the "file" menu
var fileMenu = menu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "File"));
// open it
SafeExpand(fileMenu);
// get the new File menu that appears (this is quite specific to n++)
var subFileMenu = fileMenu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Menu));
// get the "open" menu
var openMenu = subFileMenu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Open..."));
// click it
((InvokePattern)openMenu.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
// get the new Open dialog (from root)
var openDialog = WaitForDialog(window);
// get the combobox
var cb = openDialog.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox));
// fill the filename
((ValuePattern)cb.GetCurrentPattern(ValuePattern.Pattern)).SetValue(filePath);
// get the open button
var openButton = openDialog.FindFirst(TreeScope.Children, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
new PropertyCondition(AutomationElement.NameProperty, "Open")));
// press it
((InvokePattern)openButton.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
}
static AutomationElement WaitForDialog(AutomationElement element)
{
// note: this should be improved for error checking (timeouts, etc.)
while(true)
{
var openDialog = element.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
if (openDialog != null)
return openDialog;
}
}
static void SafeExpand(AutomationElement element)
{
// for some reason, menus in np++ behave badly
while (true)
{
try
{
((ExpandCollapsePattern)element.GetCurrentPattern(ExpandCollapsePattern.Pattern)).Expand();
return;
}
catch
{
}
}
}
}
If you wonder how this has been made, then you must read about UI Automation. The mother of all tools is called Inspect: https://msdn.microsoft.com/library/windows/desktop/dd318521.aspx
Make sure you get version at least 7.2.0.0. Note there is another one called UISpy but inspect is better.
Note, unfortunately, notepad++ tab text content - because it's based on the custom scintilla editor control - does not properly supports automation (we can't read from it easily, I suppose we'd have to use scintilla Windows messages for this), but it could be added to it (hey, scintilla guys, if you read this ... :).
In addition to the answer from Garath, you might also want to investigate the Windows automation API's i.e. the technology used to implement coded UI tests for GUI applications. As part of regular functional testing, I routinely control an external application from a set of NUnit tests using these API's.
Tools like UIAVerify will give you an indication of what controls are available in the application and you can use the Invoke Pattern (and many others) to interact with the controls at run-time.
If you want a detailed example of how to use the automation API's, the open source TestStack White project is pretty handy.
It is almost not possible if SendKeys is not an option but read more
Now more important part of the question- why:
We have to look how win32 application works: it has a WndProc/WindowProc method which is resposible for processing "events" form the UI.
So every event in the windows application must go through above method. SendKeys method is a special of SendMessage (MSDN), so you can use SendMessage to control other exe than your.
Simple code could look like:
IntPtr hwnd = FindWindow("Notepad++", null);
SendMessageA(hwnd, WM_COMMAND, SOMETHING1, SOMETHING2);
There is already on StackOverflow example how to do that with chrome: C# - Sending messages to Google Chrome from C# application , but this is only a start. You will have to find out what exactly message you want to send.
In exactly situation which you described I will try to send WM_MOUSE and WM_KEYBORD events to Notepad++ events, but it is only an idea :)
I have a requirement to capture the screen shot of the opened dialog with a particular html control highlighted ( whose static id is given ). currently I Implemented the code following manner :
public void Snapshot()
{
Image currentImage = null;
currentImage = GetOpenedDialogFrame().CaptureImage();
}
public UITestControl GetOpenedDialogFrame()
{
var dialogsFrames = new HtmlDiv(this.BrowserMainWindow.UiMobiControlDocument);
dialogsFrames.SearchProperties.Add(new PropertyExpression(HtmlControl.PropertyNames.Class, "mcw-dialog", PropertyExpressionOperator.Contains));
var dialogs = dialogsFrames.FindMatchingControls();
if (dialogs.Count == 0)
{
return null;
}
return dialogs[dialogs.Count - 1];
}
Now I have to write the code to highlight the particular html control while taking a screenshot. The DrawHighlight() method of Microsoft.VisualStudio.TestTools.UITesting.dll does not take any parameter so how can I highlight a particular html control in the screenshot.
DrawHighlight() is a method of a UI Control. It could be used in this style:
public void Snapshot()
{
Image currentImage = null;
var control = GetOpenedDialogFrame();
// TODO: protect the code below against control==null.
control.DrawHighlight();
currentImage = control.CaptureImage();
}
Whilst that answers your question about DrawHighlight, I am not sure it will achieve what you want. Please see this question the Microsoft forums where they are trying to do a similar screen capture.
Why not simply user the playback settings:
Playback.PlaybackSettings.LoggerOverrideState = HtmlLoggerState.AllActionSnapshot;
This will produce the html log file with all the screenshots that your codedui test went threw.
After searching for the matching controls you can try to highlight each one of them.
something like:
foreach( var control in controls)
{
control.drawhighlight();
}
that way you'll be able to which controls are located by the playback(qtagent to be more precise). furthermore this will help you decide which instance to refer to. (run and wait to see which controls are highlighted, pick the one you need and hard code it to be part of the test).
so after the test run you'll end up with something like:
var dialogs = dialogsFrames.FindMatchingControls();
dialogs[desiredLocation].drawhighlight();
hope this helps.
I already developed an C# .NET WindowsForms application using the Windows user component (user32.dll) that saves the title of the active window (the window that has focus) every time the user changes focus.
Now I'm planning to do the same using Mono C# on Linux. Is it possible?
If yes, for what I'm looking for?
I decided to take a look at the source of gnome-screenshot which has a feature like this (to take a screenshot of the active window, only):
static GdkWindow *
screenshot_find_active_window (void)
{
GdkWindow *window;
GdkScreen *default_screen;
default_screen = gdk_screen_get_default ();
window = gdk_screen_get_active_window (default_screen);
return window;
}
It has some logic to fallback to 'the window under the mouse pointer' when the above returns nothing:
GdkWindow *
do_find_current_window (void)
{
GdkWindow *current_window;
GdkDeviceManager *manager;
GdkDevice *device;
current_window = screenshot_find_active_window ();
manager = gdk_display_get_device_manager (gdk_display_get_default ());
device = gdk_device_manager_get_client_pointer (manager);
/* If there's no active window, we fall back to returning the
* window that the cursor is in.
*/
if (!current_window)
current_window = gdk_device_get_window_at_position (device, NULL, NULL);
if (current_window)
{
if (screenshot_window_is_desktop (current_window))
/* if the current window is the desktop (e.g. nautilus), we
* return NULL, as getting the whole screen makes more sense.
*/
return NULL;
/* Once we have a window, we take the toplevel ancestor. */
current_window = gdk_window_get_toplevel (current_window);
}
return current_window;
}
All of the above depends exclusive on libgdk-pixbuf as far as I can tell. If that's not an option, you could always look at the implementation of those functions in the source of Gdk.
I'm trying to test file download with Watin 2.1.0 against IE9. I used the suggested code from the accepted answer to the question Downloading a file with Watin in IE9, like this:
var downloadHandler = new FileDownloadHandler(fname);
WebBrowser.Current.AddDialogHandler(downloadHandler);
link.ClickNoWait();
downloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
downloadHandler.WaitUntilDownloadCompleted(200);
However, the downloadHandler.WaitUntilFileDownloadDialogIsHandled(15) call times out. What should I do?
File download dialog doesn't work in IE9 (Windows7) NetFramework 4.0.
Following code snippet might help you resolve the issue:
First you must add references UIAutomationClient and UIAutomationTypes to your test project.
After In Ie9 Tools -> View Downloads -> Options define path to your save folder.
The next method extends Browser class
public static void DownloadIEFile(this Browser browser)
{
// see information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
Window windowMain = new Window(WatiN.Core.Native.Windows.NativeMethods.GetWindow(browser.hWnd, 5));
System.Windows.Automation.TreeWalker trw = new System.Windows.Automation.TreeWalker(System.Windows.Automation.Condition.TrueCondition);
System.Windows.Automation.AutomationElement mainWindow = trw.GetParent(System.Windows.Automation.AutomationElement.FromHandle(browser.hWnd));
Window windowDialog = new Window(WatiN.Core.Native.Windows.NativeMethods.GetWindow(windowMain.Hwnd, 5));
// if doesn't work try to increase sleep interval or write your own waitUntill method
Thread.Sleep(1000);
windowDialog.SetActivate();
System.Windows.Automation.AutomationElementCollection amc = System.Windows.Automation.AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(System.Windows.Automation.TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
foreach (System.Windows.Automation.AutomationElement element in amc)
{
// You can use "Save ", "Open", ''Cancel', or "Close" to find necessary button Or write your own enum
if (element.Current.Name.Equals("Save"))
{
// if doesn't work try to increase sleep interval or write your own waitUntil method
// WaitUntilButtonExsist(element,100);
Thread.Sleep(1000);
System.Windows.Automation.AutomationPattern[] pats = element.GetSupportedPatterns();
// replace this foreach if you need 'Save as' with code bellow
foreach (System.Windows.Automation.AutomationPattern pat in pats)
{
// '10000' button click event id
if (pat.Id == 10000)
{
System.Windows.Automation.InvokePattern click = (System.Windows.Automation.InvokePattern)element.GetCurrentPattern(pat);
click.Invoke();
}
}
}
}
}
if you want click 'Save As' replace foreach code with this
System.Windows.Automation.AutomationElementCollection bmc = element.FindAll(System.Windows.Automation.TreeScope.Children, System.Windows.Automation.Automation.ControlViewCondition);
System.Windows.Automation.InvokePattern click1 = (System.Windows.Automation.InvokePattern)bmc[0].GetCurrentPattern(System.Windows.Automation.AutomationPattern.LookupById(10000));
click1.Invoke();
Thread.Sleep(10000);
System.Windows.Automation.AutomationElementCollection main = mainWindow.FindAll(System.Windows.Automation.TreeScope.Children
,System.Windows.Automation.Condition.TrueCondition);
foreach (System.Windows.Automation.AutomationElement el in main)
{
if (el.Current.LocalizedControlType == "menu")
{
// first array element 'Save', second array element 'Save as', third second array element 'Save and open'
System.Windows.Automation.InvokePattern clickMenu = (System.Windows.Automation.InvokePattern)
el.FindAll(System.Windows.Automation.TreeScope.Children, System.Windows.Automation.Condition.TrueCondition) [1].GetCurrentPattern(System.Windows.Automation.AutomationPattern.LookupById(10000));
clickMenu.Invoke();
//add ControlSaveDialog(mainWindow, filename) here if needed
break;
}
}
Edit:
Also if you need to automate the save as dialog specifying a path and clicking save you can do it by adding this code just before break;
private static void ControlSaveDialog(System.Windows.Automation.AutomationElement mainWindow, string path)
{
//obtain the save as dialog
var saveAsDialog = mainWindow
.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Save As"));
//get the file name box
var saveAsText = saveAsDialog
.FindFirst(TreeScope.Descendants,
new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, "File name:"),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)))
.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
//fill the filename box
saveAsText.SetValue(path);
Thread.Sleep(1000);
//find the save button
var saveButton =
saveAsDialog.FindFirst(TreeScope.Descendants,
new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, "Save"),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));
//invoke the button
var pattern = saveButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
pattern.Invoke();
}
IE9 no longer uses a dialog window for saving files. Instead, it uses the notification bar to prevent focus from being removed from the web site. See http://msdn.microsoft.com/en-us/ie/ff959805.aspx under "Download Manager" for reference.
Unfortunately, this means that the current FileDownloadHandler in WatiN will not work. It instantiates a "DialogWatcher" class per browser instance that is a basic message pump for any kind of child window. When child windows are encountered, the DialogWatcher checks to see if the window is specifically a dialog (which the notification bar is not). If it is a dialog, it then iterates over the registered IDialogHandler instances calling "CanHandleDialog." Even if the notification bar were a dialog, it is of a different Window Style (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx), which is how WatiN detects the type of dialog.
From what I can see, there is no support yet for detecting the IE 9 notification bar and its prompts in WatiN. Until that support is added, you will not be able to automate downloading files in IE9.