I am currently making changes to my company's enterprise library and I am looking into creating a deployment project that will allows developer to set up the library through the MSI installer or some type of set up executable.
I was looking into using a Merge Module project to accomplish this task. A basic google search did not produce any helpful resources for using Merge Module Product.
Do anyone know of useful resource/tutorial on creating Merge Module projects or do they have a better suggestion for accomplishing this task?
UPDATE
I was able to build my Merge Module project with the appropriate references to all the need assemblies. It produced a .MSM file. What is the next step to actually run and test it?
An MSM cannot be run or tested per se. However, you can embed it into an MSI and then simply try to install the MSI using the standard tools (i.e. either manually right-clicking on the MSI and selecting Install or Uninstall, do so using Visual Studio, or by executing the corresponding msiexec.exe commands).
To embed an MSM into an MSI, the easiest way is to create a setup project in Visual Studio and add the Merge Module from the merge module project you have just created in your solution. This will automatically reference the MSM file and include it into the MSI.
I faced the same lack of documentation when I built my only merge module using Visual Studio 2005. I had some experience with the MSI Setup projects, and I simply applied the information I had for the MSI Setup projects to the MSM.
In Visual Studio 2005 (or 2008), both MSI and MSM projects are handled in a very similar manner. Add files to the project (either explicitly or through a reference to another project found in the same solution), then use the right-click on the project to :
View the file system.
View the registry settings.
View the file types associations.
View the custom actions.
Custom actions can be implemented in a .NET assembly, for instance, by subclassing the Installer class. Here is an example which would, for instance, install or uninstall a printer when the MSM/MSI gets installed or uninstalled:
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
namespace Epsitec.PostScriptPrinterInstaller
{
[RunInstaller (true)]
public partial class PrinterInstaller : Installer
{
public PrinterInstaller()
{
this.InitializeComponent ();
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install (stateSaver);
string sysroot = System.Environment.GetEnvironmentVariable ("SystemRoot");
string infpath = #"""" + System.IO.Path.Combine (sysroot, #"inf\ntprint.inf") + #"""";
ProcessStartInfo info;
Process process;
info = new ProcessStartInfo ("rundll32.exe",
#"printui.dll,PrintUIEntry /if /b ""PostScript"" /m ""MS Publisher Color Printer"" /f "+infpath+#" /r ""FILE:""");
process = Process.Start (info);
process.WaitForExit ();
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall (savedState);
ProcessStartInfo info;
info = new ProcessStartInfo ("rundll32.exe",
#"printui.dll,PrintUIEntry /dl /n ""PostScript""");
Process process = Process.Start (info);
process.WaitForExit ();
info = new ProcessStartInfo ("rundll32.exe",
#"printui.dll,PrintUIEntry /dd /m ""MS Publisher Color Printer""");
process = Process.Start (info);
process.WaitForExit ();
}
}
}
I hope that with this information, you will be able to do some progress.
Related
I have a desktop application and its installer project produces two files in the Release folder: let's call them setup.exe and setup.msi.
In the post build event I sign the setup.msi with a self signed certificate. Then my final installation batch is composed of three steps
Adding user store certificate with a start.cmd (or start.exe)
Running the setup.exe. Notice that the important thing is that it shows a user account control for a verified author with my name and surname.
Removing (with a stop.cmd or stop.exe) the certificate at point 1 for security reasons/best practices since it is self signed
Now I'm perfectly fine with this solution, I only wished to include the commands 1 and 3 inside the setup.exe if it was possible in a standard way.
What I have tried to do is to define the start.exe and stop.exe as custom actions. In that case I only have the two files setup.exe and setup.msi but unfortunately I get an unkown publisher. I guess it is obviously because the custom actions go inside the .msi and not in the setup.exe. But I'm not an expert of installer projects so someone might suggest a better and standard solution.
Alternative approach
Is that something that I could much more easily do by switching to Inno Setup and maybe as suggested in this comment?
References
How do I create a self-signed certificate for code signing on
Windows? - Original Answer
Answer about certmgr.msc - Will a self signed code-signing
certificate get rid of “Unknown Publisher” warnings?
Sign tools downloadable from github
Updated answer
Sorry, I've tested my original answer below and it is "wrong" in a sense:
actually I get a single click installer but then the Windows operating system anticipates the user account control before such single click installer and it shows an unknown publisher, which defeats the purpose of point 1 (and 3).
So, short, updated answer: it is impossible(*) to do that in a standard single-click exe, like the ones produced by the SFX module mention below.
(Note *): though it is doable by compiling a custom C# code and by adding files to the Resources.resx, for example _7zr.exe, etc... like in this example:
using System.IO;
using System.Diagnostics;
namespace selfextractinstaller
{
class Program
{
static void Main(string[] args)
{
string file_path_7zr = #"_7zr.exe";
using (FileStream fs = new FileStream(file_path_7zr, FileMode.Create))
{
byte[] pgm_bytes = Properties.Resources._7zr;
fs.Write(pgm_bytes, 0, (int)pgm_bytes.Length);
}
string file_path_config = #"config.txt";
using (StreamWriter sw = new StreamWriter(file_path_config, false))
{
sw.Write(Properties.Resources.config);
}
string file_path_7zSD = #"_7zSD.sfx";
using (FileStream fs = new FileStream(file_path_7zSD, FileMode.Create))
{
byte[] pgm_bytes = Properties.Resources._7zSD;
fs.Write(pgm_bytes, 0, (int)pgm_bytes.Length);
}
Process.Start(file_path_7zr, "b");
}
}
}
A similar code can be actually used as a self extracting installer that is not elevated and does not require the UAC!
Further Readings
How does Windows decide whether to display the UAC prompt?
How do I add a manifest to an executable using mt.exe?
Original answer
In absence of other answers, I'll proceed with a SFX module for installers, by packaging all the three .exe at points 1-3 (plus an install_all.bat running them in sequence) into a self extracting installer, that will automatically extract all the needed files (certificate included) and finally run the install_all.bat
I want get dir my setup create by install shield.
I use command parametter Setup.exe /path=[SETUPEXEDIR]\log.txt
My setup location is Desktop\myapp\Setup.exe
When use [SETUPEXEDIR] return temp folder
I want when use [SETUPEXEDIR] return me my Setup.exe location.
I use installshield 2016 version 23 SP 2.
I use MSI Script.
I want get location and use in command parameter prerequisites.
A little hard to comprehend exactly what you are asking, but as far as I understand you want to know the location where setup.exe is running from?
Variables
The first question is: what version of Installshield are you using?
The second question is: are you using Basic MSI or Installscript MSI?
The third question is: what type of release media are you using?
There may be more relevant questions...
A word to the wise: if you are indeed using Installscript MSI you should know that it is a very buggy type of project, and you should seriously consider switching to Basic MSI to save yourself grief. I can provide more information on this if you like. I had to abandon Installscript MSI entirely to make my deployment problems go away.
Installshield Properties
It seems different versions of Installshield may behave differently and feature varying support for these folder properties / variables. It also seems the properties may not work with all types of release media. And finally they may only work in Basic MSI or Installscript MSI respectively. The properties I have found are: PACKAGE_LOCATION, SETUPEXEDIR and SRCDIR. There also appears to be an Installscript method called GetCurrentDir() available in recent versions of Installshield, but the documentation warns about using it (see link).
Please visit the links above in sequence and read in detail about each property's (or method's) limitations. It is very important that you use the option (if any) that matches your requirements and scenario. For example PACKAGE_LOCATION works only for Installscript MSIs, SETUPEXEDIR is set by Setup.exe. If the end user runs the .msi package directly, SETUPEXEDIR is not set.
MSI Built-in Property
It seems to me that getting the built-in MSI property SourceDir might be an option to try. My quick test indicates that it works for both InstallScript and Basic MSI. However, I do not know if this works for all versions of Windows Installer. Please test on various Windows versions to be sure.
You should also be aware of the potential problem using SourceDir which is described in the documentation for SETUPEXEDIR. This goes for setups that are compiled into a single, compressed setup.exe containing all files - this launcher will extract the MSI file to a temp location and run from there. When I tried with an uncompressed network image it worked fine to use SourceDir.
Finally, if you use a setup.exe to compress all files and enable the caching of the MSI on the system, then you will be running from somewhere inside: C:\WINDOWS\Downloaded Installations\{GUID}\.
All of this could be different on newer versions of Installshield. I am testing with an ancient version I have available. Please test thoroughly on your version.
I should also mention the OriginalDatabase built-in MSI property. Check the link for documentation on how it will be set.
Some links:
Installscript project - Get Setup.exe location.
How to find the setup.exe directory?
Installscript Function For Testing
And just for reference, here is a quick and dirty function to test these properties from an Installshield custom action (this is for other people who may find this without having tested as much as you):
function TestFolderProperties(hMSI)
STRING svName;
NUMBER nvSize;
begin
// MSI properties
nvSize = 256;
MsiGetProperty (hMSI, "SETUPEXEDIR", svName, nvSize);
MessageBox ("SETUPEXEDIR: " + svName, INFORMATION);
MsiGetProperty (hMSI, "SourceDir", svName, nvSize);
MessageBox ("SourceDir: " + svName, INFORMATION);
MsiGetProperty (hMSI, "OriginalDatabase", svName, nvSize);
MessageBox ("OriginalDatabase: " + svName, INFORMATION);
// System Variables
MessageBox ("SRCDIR: " + SRCDIR, INFORMATION);
// PACKAGE_LOCATION is not available in my version of Installshield, enable and test
//MessageBox ("PACKAGE_LOCATION: " + PACKAGE_LOCATION, INFORMATION);
end;
Remember to add the export to the top of the setup.rul file:
export prototype TestFolderProperties(HWND);
Test compile to verify, and then create an Installscript custom action and put it in a sequence. Make "Return Processing" Synchronous (Ignores exit code) for the custom action. I put it right before InstallFinalize in the sequence, using immediate mode execution. Rebuild your release and run it. Try different release build configurations (msi with external source files, MSI only with compressed files inside, setup.exe launcher with external files, setup.exe with all files compressed inside, setup.exe with caching, setup.exe without caching, etc... the behavior might be different).
I have a situation to pass connection string as a parameter to the msi file so that the installer picks it up and replace the connection string in .exe.config file.
I can easily achieve this by using a custom action to do the same thing. But I don't want to use it since I have some limitations of not using them. So is it possible to such thing without using custom action?
Hello you have no limitations I did on several projects. what I do is I also indexes my connection on an environment variable (other solution), to avoid to deploy multiple versions of the software.
There isn't any native support in Windows Installer for transforming XML files. You'll have to use a custom action of some sort or remove the requirement that the installer perform the update.
The cleanest way to do it while still using (mostly) visual studio setup and deployment projects would be to author a WiX merge module to encapsulate the XML change piece and consume the module in your installer.
I am making changes to a Visual Studio wizard that creates a project from a template, and needs to add a reference to an assembly to the project that also lives in the extension directory. So I need to set the <hintpath>.
I have not been able to figure out how a running VS extension can discover its extension directory, which is a directory name like this:
%USERPROFILE%\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\myCompany\myExtension
Using System.Reflection.Assembly.GetExecutingAssembly().CodeBase yields:
"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\myCompany.myExtension\v4.0_1.0.0.0__936015a19c3638eb\myCompany.myExtension.dll"
Unfortunately, not helpful. Using GetCallingAssembly() is no better--it points at another directory in the MSIL_GAC.
Is there a Visual Studio interface that returns this information? I haven't been able to find it.
If that's not possible, is it at least possible to determine if the extension is running in the experimental instance vs. non-experimental? I could use that information to locate the extension directory.
Maybe look at IInstalledExtension.InstallPath. You can get an IInstalledExtension via an IVsExtensionManager.
Unfortunately, the message in the remarks suggests this is not the right way to do things:
Although this API supports the Extension Manager infrastructure, we recommend that you do not use it because it is subject to change.
EDIT: Here's the code:
static IVsExtensionManager GetExtensionManager()
{
return myPackage.GetService(System.typeof(IVsExtensionManager)) as IVsExtensionManager;
}
static IInstalledExtension GetExtension(string identifier)
{
return GetExtensionManager().GetInstalledExtension(identifier);
}
static string GetExtensionDirectory(string identifier)
{
return GetExtension(identifier).InstallPath;
}
The string identifier is whatever you put in the "ID" field of your extension's source.extension.vsixmanifest file. It defaults to the package GUID.
Sorry for digging up an old answered question...
I was looking into a similar problem, and have implemented the Extension Manager, but decided this is just pretty awful, though if you do want to do use it these links will also help:
https://stackoverflow.com/a/24294185
http://blog.ninlabs.com/2011/04/auto-update-visual-studio-extensions/
However, I decided to look into how the CodeGenerator in Asp.Net.Scaffolding accessed template files. Turns out, very easily...
var path = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), "MyPath");
Simples
Context: I have a handful of plug-ins (which are really just DLLs with a different extension) that need to be installed in a sub-folder of a 3rd party application. Usually it's enough to simply copy them to said folder, but occasionally there are other libraries that need to be installed as well. I'd like to make this process less error-prone for users so I've looked in to using an installer project in visual studio to create a .msi, but I'm having trouble getting the install location configured correctly.
It seems that it assumes the installer is meant for a complete application and defaults to a location such as C:\Program Files\MyApp\, but what I really need is C:\Program Files\\Plugins. I'd rather not assume that the user has the 3rd party application installed in any particular location, so what I'd like is a way to locate where this other application has been installed. I've searched through Microsoft's documentation and experimented a bit on my own, but haven't had any success.
Assuming this is possible, does anyone know how to accomplish what I want?
Most applications will write their installation location somewhere in the registry. We read values under the following registry key to find the Microsoft Word install location.
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Winword.exe]
Unfortunately there's no standard way to retrieve the installation location of a particular application. You'll have to search the registry to find what you want.
If your application used the Windows installer you can try this method (C#):
Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer msi = (Installer)Activator.CreateInstance(type);
foreach (string productcode in msi.Products)
{
string productname = msi.get_ProductInfo(productcode, "InstalledProductName");
if (productname.Contains("<YOUR PRODUCT NAME HERE>"))
{
string installdir = msi.get_ProductInfo(productcode, "InstallLocation");
Console.WriteLine("{0}: {1} #({2})", productcode, productname, installdir);
}
}