VSIX extension - closing windows that do not seem to have vsWindowKind constants - c#

In my Visual Studio extension, I can close a window in the IDE by doing this:
var dte = (DTE)GetService(typeof(EnvDTE.DTE));
dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput).Close();
(That closes the output window)
There are windows which do not seem to have a "vsWindowKind" constant (all of which are listed here: https://msdn.microsoft.com/en-us/library/envdte.constants.aspx) - you can still close them if you know the GUID. For example:
dte.Windows.Item("{131369F2-062D-44A2-8671-91FF31EFB4F4}").Close();
closes the Team Explorer window (I found that GUID from another SO question: How do I run a TFS Work Item Query with Visual Studio Macros.
My question is, where can I find a complete list of IDE window GUIDs?
EDIT: so for VS2015 and below I can find a list of tool windows in the registry by doing the following:
var keyname = #"Software\Microsoft\VisualStudio\14.0_Config\ToolWindows";
using (var key = Registry.CurrentUser.OpenSubKey(keyname))
{
foreach (var subkey in key.GetSubKeyNames())
{
var fullkey = #"HKEY_CURRENT_USER\" + keyname + "\\" + subkey;
var name = (string)Registry.GetValue(fullkey, "Name", "");
if (!string.IsNullOrWhiteSpace(name))
{
Console.WriteLine($"{subkey} {name}");
}
}
}
However, there are no such entries for VS2017 (probably because it allows you to install multiple copies on the same PC).
Anyway, the documented list is still missing!

You can get the current window GUID with DTE.ActiveWindow.ObjectKind. This way you can build the list of IDE window GUIDs yourself.

Is this you're looking for? The vsWindowType Enumeration documentation.
https://msdn.microsoft.com/en-us/library/envdte.vswindowtype.aspx

Related

C# Selenium Edge Driver unable to download file - Keep file prompt shows up

I am using C# with Selenium for QA automation, and I am having issues with downloading an .xml file, because a prompt is always showing up asking if I want to keep the file. It also opens a second tab to execute the download, closing it after the prompt shows up.
[keep file prompt][1]
Using Chrome I do not see this behavior.
I searched all over and could not find a EdgeOptions() and/or AddArguments() capable of taking care of this issue.
Any ideas?
You need to use JS to interact with elements in another browser. I have had such experience and I used if else statement in my method to handle that problem. Just look trough the Selenium documentation, JS with selenium examples and so long so for.
Just add this to your OneTimeSetup method. Make sure to run Visual Studio as administrator. This works since Edge 105+:
public void SetEdgeXmlDownloadPolicy()
{
var keyName = "Software\\Policies\\Microsoft\\Edge\\";
var valueName = "ExemptFileTypeDownloadWarnings";
var valueData = #"{""domains"": ["" * ""], ""file_extension"": ""xml""}";
var currentUser = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
var currentKey = currentUser.OpenSubKey(keyName, true);
if (currentKey == null)
currentKey = currentUser.CreateSubKey(keyName);
if (currentKey.GetValue(valueName) == null)
currentKey.SetValue(valueName, valueData);
}

Installshield Automation Interface - Always Overwrite

I am trying to automate the creation of install packages for the company i work for and am using the Installshield Automation Interface to create an MSI project. One of the things we have done up to now (manually if you can believe it) is go through all of the files we want to release after importing them into installshield and setting them to "Always overwrite" on a folder by folder basis since it seems you cant do it recursively on a parent folder. When creating a Basic MSI on the installshield GUI it lets you do this, however when creating an MSI via the COM object it appears this option is only available to InstallScript which i cant make an MSI with.
Anywho my code kinda looks like this
static void AddFiles(string[] aFiles, ISWiAuto24.ISWiProject oISProj, string sProjName, string ePackName)
{
oISProj.OpenProject(sProjName, false);
string installdirectory = "[ProgramFilesFolder]" + ePackName;
oISProj.INSTALLDIR = installdirectory;
Console.WriteLine("Adding ePack files");
for (int i = 0; i < aFiles.Length;i++ )
{
Console.WriteLine(aFiles[i]);
ISWiComponent NewComponent = oISProj.AddComponent("Component_"+i);
string string_PathToFile = aFiles[i].Substring(0,aFiles[i].LastIndexOf("\\"));
string string_RelativeToInstallDir = string_PathToFile.Substring(aFiles[i].LastIndexOf(ePackName) + ePackName.Length);
NewComponent.Destination = installdirectory+string_RelativeToInstallDir ;
NewComponent.AddFile(aFiles[i]);
/*----------------------------Fails Here--------------------------------------*/
NewComponent.OverwriteMainOptions=0;
/*----------------------------------------------------------------------------*/
}
oISProj.SaveProject();
oISProj.CloseProject();
Console.WriteLine("Done");
}
static voidMain(string[] args){
ISWiAuto24.ISWiProject oISProj = new ISWiAuto24.ISWiProject();
string ePackName = "ThisMonthsBundle"
string[] aFiles = new[] {#"c:/Foo/Roo/Goo/"+ePackName+"/File0",#"c:/Foo/Roo/Goo/"+ePackName+"/File1",#"c:/Foo/Roo/Goo/"+ePackName+"/File2",#"c:/Foo/Roo/Goo/File3"}
string sProjName = "C:/Foo/Bar.ism"
oISProj.CreateProject(sProjName, ISWiProjectType.eptMsi);
AddFiles(aFiles,oISProj,sProjName);
}
does anyone know a way around this?
the error is: COM Exception was unhandled - This property is not supported for Basic MSI Project. You need to remove the line that calls the property from your automation code.
I found an old forum post back in 2010 on the flexera community forum where a flexera developer responded to a user saying that this can be done like so:
ISWiComponent NewComponent = oISProj.AddComponent("Component_1");
NewComponent.Destination = "[ProgramFilesFolder]" + "ProgramName";
NewComponent.AddFile("c:\File1");
ISWiFiles Files = NewComponent.ISWiFiles;
foreach (ISWiFile File in Files)
{
File.OverrideSystemVersion = true;
File.Version = "65535.0.0.0";
}
the developer in question recognised the need for the automation interface to support the ISWiFile.AlwaysOverwrite property and raised a work order for it. i guess they just havent gotten around to it in the 8 years since
https://community.flexerasoftware.com/showthread.php?194448-installshield-2009-automation-File-property-quot-Always-overwrite-quot
Anyway, The above appears to work

Is there a way to programmatically see what solution an instance of Visual Studio has open (not as a plugin)?

Pretty straight-forward, but don't really know if it's even feasible. Basically I'd like to have a winform (NOT a plugin to VS) that retrieves a list of of solutions that are currently loaded in open instances of Visual Studio.
EDIT: To clarify per comments below, I'm looking for the loaded solutions full path (e.g., C:\projects\myrandomproject.sln
You can enumerate the running instances of Visual Studio through the running object table (ROT). See IRunningObjectTable and GetRunningObjectTable.
You can then get a reference to the DTE2 object for each running instance using the identifier from the ROT.
Use DTE2.Solution. You can get its path from its FullName property.
This is something just to get you started.. you will have to tweak it to which ever way you want..
4.If you just want to get the names of programs not the opened folders, then use the following code
foreach (Process p in Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero && p.ProcessName != "explorer"))
{
Console.WriteLine(p.ProcessName);
}
Console.ReadKey();
2.If you just want to get the process started by User not by the Windows then use the following code
foreach (Process p in Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero))
{
Console.WriteLine(p.ProcessName);
}
Console.ReadKey();

How can I get another application's installation path programmatically?

I'd like to know where the installation path for an application is. I know it usually is in ...\Program Files... but I guess some people install it in different locations. I do know the name of the application.
Thank you.
The ideal way to find a program's installation path (on Windows) is to read it from the registry. Most installers will create a registry key for that program that contains the installation path. Exactly where this key is and what it will be named varies depending on the program in question.
To find if the program has a key in the registry, open 'regedit' and use the Edit > Find option to try and locate a key with the program name. If such a key exists, you can read it using the RegistryKey class in the .NET Framework library.
If the program does not have a registry key then another option is just to ask the user to locate the .exe file with the OpenFileDialog, although this is obviously not ideal.
Many (most?) programs create an App Paths registry key. Have a look at
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
If you know the application in question (as compared to any application) registry key is the probably the best option (if one exists).
The install might put in its own custom "install path key" somewhere (so do a find as Fara mentioned) or it might be in the uninstall section for installed programs, so you could check:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
But be aware that any new version of an install could change the key it writes out, both for a custom key or for the uninstall entry. So checking the registry should probably be only for a known install\version.
tep
Best way is to use Installer APIs to find the program location.
You can write a Managed wrapper over the APIs
Search for MsiGetProductInfo
Reference: http://msdn.microsoft.com/en-us/library/aa369558(VS.85).aspx
You can use MSI (I wrote a C# wrapper for it here https://github.com/alialavia/MSINet). Here is a simple example:
var location = "";
foreach (var p in InstalledProduct.Enumerate())
{
try
{
if (p.InstalledProductName.Contains("AppName"))
{
location = p.InstallLocation;
break;
}
}
catch { }
}
Take a look in the registry.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
or
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
Each of the above contain a list of sub-keys, one for each installed application (as it appears, for example, in the "Programs and Features" applet)
You can search for your application there, or if you know the product code, access it directly.
public string GetInstallPath(string applicationName)
{
var installPath = FindApplicationPath(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", applicationName);
if (installPath == null)
{
installPath = FindApplicationPath(#"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall", applicationName);
}
return installPath;
}
private string FindApplicationPath(string keyPath, string applicationName)
{
var hklm = Registry.LocalMachine;
var uninstall = hklm.OpenSubKey(keyPath);
foreach (var productSubKey in uninstall.GetSubKeyNames())
{
var product = uninstall.OpenSubKey(productSubKey);
var displayName = product.GetValue("DisplayName");
if (displayName != null && displayName.ToString() == applicationName)
{
return product.GetValue("InstallLocation").ToString();
}
}
return null;
}

Monitor file selection in explorer (like clipboard monitoring) in C#

I am trying to create a little helper application, one scenario is "file duplication finder". What I want to do is this:
I start my C# .NET app, it gives me an empty list.
Start the normal windows explorer, select a file in some folder
The C# app tells me stuff about this file (e.g. duplicates)
How can I monitor the currently selected file in the "normal" windows explorer instance. Do I have to start the instance using .NET to have a handle of the process. Do I need a handle, or is there some "global hook" I can monitor inside C#. Its a little bit like monitoring the clipboard, but not exactly the same...
Any help is appreciated (if you don't have code, just point me to the right interops, dlls or help pages :-) Thanks, Chris
EDIT 1 (current source, thanks to Mattias)
using SHDocVw;
using Shell32;
public static void ListExplorerWindows()
{
foreach (InternetExplorer ie in new ShellWindowsClass())
DebugExplorerInstance(ie);
}
public static void DebugExplorerInstance(InternetExplorer instance)
{
Debug.WriteLine("DebugExplorerInstance ".PadRight(30, '='));
Debug.WriteLine("FullName " + instance.FullName);
Debug.WriteLine("AdressBar " + instance.AddressBar);
var doc = instance.Document as IShellFolderViewDual ;
if (doc != null)
{
Debug.WriteLine(doc.Folder.Title);
foreach (FolderItem item in doc.SelectedItems())
{
Debug.WriteLine(item.Path);
}
}
}
You can do this with the shell automation interfaces. The basic process is to
Run Tlbimp on Shdocwv.dll and
Shell32.dll (or directly add a
reference from VS).
Create an
instance of the ShellWindows
collection and iterate. This will
contain both Windows Explorer and
Internet Explorer windows.
For
Windows Explorer windows, the
IWebBrowser2.Document property will
return a IShellFolderViewDual
reference.
The IShellFolderViewDual
has a SelectedItems method you can
query and an event for changes you
can handle.

Categories