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
Related
I want to get the path of an existing folder SeleniumTestData inside the solution.
Why? My selenium tests should create at start of the test, temporary folder which are being ignored in Git, so each of my colleagues has their own TestData folders for their own TestExecutions on their machine (Like Save/Load Cookies) and dont pull TestData from other colleagues.
The folder where i want to create other folder by code is named SeleniumTestData folder and is inside:
..\source\repos\CoffeeTalk\src\Tests
I cant hardcore the path, as i'm facing here 2 problems:
Tests are being ran in Windows and Docker (Linux)
Co-Workers are saving the solution in different windows directories
Now i need a general solution which will work in any of these cases.
I already tried: var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
which returned: D:\source\repos\CoffeeTalk\src\Tests\Web\CoffeeTalk.Client.Selenium.Tests\bin\Debug\net6.0
and then tried to navigate back by executing the codeline currentDirectory?.Parent about 5-6 times. But its then again different in Linux.
Now im looking for a clean way. I suppose the first way i did it was not wrong by getting the CurrentDirectory and navigate back.
I already searched for solutions using stackoverflow, google. Either the solutions are outdated or im not getting the result im expecting.
Here i have the method which creates the folder, but im struggling with the GetFolderPath method.
public static void CreateFolder(string folderName, string newFolderName)
{
var folderPath = GetFolderPath(folderName);
var pathCombined = Path.Combine(folderPath, newFolderName);
var folderExists = Directory.Exists(pathCombined);
if (folderExists) return;
Directory.CreateDirectory(pathCombined);
}
Directory.GetCurrentDirectory isn't the directory with your executable file. It's something else (I don't know) that by the way depends on the OS. You should use this instead:
using System.Reflection;
// ...
string exeDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
And then go up the folders hierarchy as you want:
string neededFolder = new DirectoryInfo(exeDirectory).Parent.Parent.Parent.ToString(); // Or more "Parent" calls
As far as I know, it works on different OSs.
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
Is there anyway that a reference can be added to a solution programmatically?
I have an add-in button, when the user presses it, I want a reference to be added.
The reason is, I have created a piece of software that I want to be integrated into any given VS program (if the developer wants it), they would simply click the add-in button and the reference would be loaded in the current solution.
Is this possible?
Something like this I haven't tested it
get the environment
EnvDTE80.DTE2 pEnv = null;
Type myType = Type.GetTypeFromProgID("VisualStudio.DTE.8.0");
pEnv = (EnvDTE80.DTE2)Activator.CreateInstance(myType, true);
get the solution.
Solution2 pSolution = (Solution2)pEnv.VS.Solution;
get the project that you want
Project pProject = pSolution.Projects[0];
add the reference
pProject.References.Add(string referenceFilePath);
There is an example on CodeProject.
The functionality is contained within a single class elRefManager and the method to call is CheckReferences. The code can be looked at here by selecting the elRefManager.cs file on the left hand side.
As seen in the article you could do...
private void button1_Click(object sender, System.EventArgs e)
{
int ec;
ec=elRefManager.CheckReferences(null, new string[] {textBox1.Text});
if (ec<0)
MessageBox.Show("An error occurred adding this reference");
if (ec>0)
MessageBox.Show("Could not add " + textBox1.Text +
"\nCheck its spelling and try again");
}
System.Assembly.load Allows you to call functions in a library that were not built with your program.
If you want to add a reference to the project so that its in the solution you can use the following. Basically the same as #Scots answer.
I did it in a macro which is vb but I'm sure you can get the idea
DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
Dim objProject As EnvDTE.Project
Dim i As Long
i = DTE.Solution.Projects.Count
For Each objProject In DTE.Solution.Projects
If (objProject.Name() = "csCA") Then
Dim vsproj As VSLangProj.VSProject
vsproj = objProject.Object
vsproj.References.Add("C:\Users\test.dll")
End If
Next
After creating a web site, i notice that it sets the asp.net version to 1.1. I would like to in code change this to version 2.0.50727. I found that in the ScriptMaps property there are string list of all the file extensions and code mapping. But I have not figured out how to change all of the values that are connected to .net? Or is there a way to tell it to use an other verison with .invoke?
DirectoryEntry sited = new DirectoryEntry(string.Format("IIS://localhost/w3svc/{0}/Root", websiteID.ToString()));
sited.Properties["AccessRead"].Add(true);
PropertyValueCollection testScriptMap = sited.Properties["ScriptMaps"];
object[] allValues = (object[])testScriptMap.Value;
object[] newValues = new object[allValues.Length];
string oldVersion = "v1.1.4322";
string newVersion = "v2.0.50727";
for (int i = 0; i < allValues.Length; i++)
{
if (allValues[i] is string)
{
string temp = allValues[i] as string;
if (temp.Contains(oldVersion))
{
newValues[i] = temp.Replace(oldVersion, newVersion);
}
else
{
newValues[i] = allValues[i];
}
}
else
{
newValues[i] = allValues[i];
}
}
testScriptMap.Value = newValues;
sited.CommitChanges();
After little trial and error I found a solution. I took all the objects in the created site and made a copy where i changed the version part of the path string. Then I set the value property of the scriptMaps object to point to the new updated object array.
One easy way is to execute "aspnet_regiis -i". The aspnet_regiis.exe file will be located at - C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe.
Alternately, you can take the hard way, and take a look at an article on modification of IIS Metabase.
Taking the harder way, to me, is much cooler than the easy one!
The following command installs the ASP.NET version associated with the tool and updates the script maps of all existing ASP.NET applications. Note that only applications that are currently mapped to an earlier version of ASP.NET are affected.
Aspnet_regiis -i
the Aspnet_regiis.exe is under the following path:
C:\WINDOWS\Microsoft.NET\Framework\"dot net version you want to change to"
in your case will be under v2.0.50727:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
source: ASP.NET IIS Registration Tool
Back in .NET 1.0 days I wrote a method to return the target of a shortcut on MS Windows. It did this through using an interop to the Windows Script Hosting Object Model and brute forced through the COM interface:
private FileInfo GetFileFromShortcut(FileInfo shortcut)
{
FileInfo targetFile = null;
try
{
IWshRuntimeLibrary.WshShell wShell = new IWshRuntimeLibrary.WshShellClass();
IWshRuntimeLibrary.WshShortcut wShortcut = (IWshRuntimeLibrary.WshShortcut)wShell.CreateShortcut(shortcut.FullName);
// if the file wasn't a shortcut then the TargetPath comes back empty
string targetName = wShortcut.TargetPath;
if (targetName.Length > 0)
{
targetFile = new FileInfo(targetName);
}
}
catch (Exception)
{ // will return a null targetFile if anything goes wrong
}
return targetFile;
}
This still bugs me, and I was looking to replace this with something more elegant, but only if the replacement actually works at least as well. I still can't find a native C# way of finding the target of a shortcut. Is there one, or is this still the best way of doing this type of thing?
It looks like someone has written a class to manipulate shortcut files in C# called ShellLink, but it too uses COM.
Can't you just open the .lnk or .url file and parse it?
This talks about the same thing and shows what the files look like:
http://www.programmingtalk.com/showthread.php?t=7335
I got interested in this as well a while ago.
Here is the accepted response with a link to a (informal) description of the format of LNK files. Apparently, all available methods yet go through some API.