Which would be the proper way to install one publisher policy in to the GAC using WIX? - wix

Which would be the proper way to install one publisher policy in to the GAC using WIX 3.5?
I tried to do this:
<File
Id="LIBGAC"
Assembly=".net"
KeyPath="yes"
Vital="yes"
Name="ClassLibrary1.dll"
ProcessorArchitecture="msil"
DiskId="1"
Source="..\ClassLibrary1\bin\Release\ClassLibrary1.dll" >
</File>
</Component>
<Component Id="Config" Guid="F089B1AA-B593-4662-9DF4-F47EB9FBA1F4" >
<File
Id="LIBGACPolicy"
Assembly=".net"
KeyPath="yes"
Vital="yes"
Name="Policy.1.0.ClassLibrary1.dll"
DiskId="1"
Source="..\ClassLibrary1\policy.1.0.ClassLibrary1.dll" >
</File>
<File
Id="LIBGACPolicyConfig"
Source="..\ClassLibrary1\policy.1.0.ClassLibrary1.config"
CompanionFile="LIBGACPolicy">
</File>
</Component>
</Directory>
When compiling with VS2008 appears this error:
policy.1.0.ClassLibrary1.dll appears to be invalid. Please ensure this is a valid assembly file and that the user has the appropriate access rights to this file. More information: HRESULT: 0x8013101b
And lastly, when compiling with VS2010 doesn´t appear to be any problem. But
at finalizing the installation process, the DLL is well installed and the
publisher policy didn´t. Also I read the log generated during the installation and I wasn´t able to find a cause.
Thanks for reading.

I've been doing something similar and works well using Visual Studio 2010 and in a Build Server with MsBuild:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="Gac" Name="Gac">
<!-- The component with the assembly -->
<Component Id="MiClassDLL" Guid="*">
<File Id="MiClass.dll" Assembly=".net" KeyPath="yes"
Source="$(var.MiClass.TargetPath)" />
</Component>
<!-- The component with the policy -->
<Component Id="PolicyMiClassDLL" Guid="{YOUR_GUID_HERE}">
<File Id="PolicyMiClass.dll" KeyPath="yes"
Source="$(var.MiClass.TargetDir)Policy.1.0.MiClass.dll" />
<File Id="PolicyMiClass.config" KeyPath="no"
Source="$(var.MiClass.ProjectDir)Policy.1.0.MiClass.config" />
</Component>
</Directory>
</Directory>
</Directory
In my case I have the policy.config file in the same project directory and I build the policy dll in the same output to make easier the installer script.
I noticed that the policy component must have a guid and for some reason it requires internally that policy dll and config files in the same directory/component.
I build the policy assembly in the Post-Build event of MiClass project with this command:
"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\al.exe"
/link:"$(ProjectDir)Policy.1.0.MiClass.config"
/out:"$(TargetDir)Policy.1.0.MiClass.dll"
/keyfile:"$(SolutionDir)MyKeys.snk"
/comp:"My Company"
/prod:"My Product"
/productv:1.0
/version:1.0.0.0
I hope this works for you.

I did some work with policy dlls, and the only difference I can see is that your file naming convention is a little different than ours was.
Instead of
policy.1.0.ClassLibrary1.dll
policy.1.0.ClassLibrary1.config
We used
policy.1.0.ClassLibrary1.dll
ClassLibrary1.dll.config

instead of /link switch use /embed to compile the xml-config into publisher policy. then you can install the resulting assembly into GAC without problems

Related

WiX Shortcuts Not Detecting Files In Application Directory

Part of my application needs to read a config file, which I keep in the same directory as my application's exe. My issue is that the shortcuts created by WiX don't find this file.
I can create my shortcuts post install, and they work, but I would rather fix this issue instead of doing that.
This is what my component looks like:
<Component Id="MyApp.exe" Guid="G-U-I-D">
<File Id="MyApp.exe" Name="MyApp.exe" Source="$(var.MyApp_TargetDir)MyApp.exe">
<Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="My Application" Icon="Icon.ico" Advertise="yes" />
<Shortcut Id="StartMenuShortcut" Directory="ProgramMenuFolder" Name="My App" Icon="Icon.ico" Advertise="yes" />
</File>
</Component>
UPDATE: If I understand your comment correctly, I am wondering if you simply do not set the shortcut's WorkingDirectory attribute?
WiX Markup Sample:
<Directory Id="MyDir" Name="My Dir">
<Component Id="My.exe" Feature="Main">
<File Source="My.exe">
<Shortcut Id="DesktopShortcut"
Directory="DesktopFolder"
Name="My Product"
Advertise="yes"
WorkingDirectory="MyDir">
</Shortcut>
</File>
</Component>
</Directory>
Shortcut Properties:
If this is a settings file that you intend to write to you should put it in the user profile so that it is writeable for the launching user. Your application.exe file should be able to find the config file regardless if it is in your application installation folder or in the user profile?
C# mockup (should use Path.Combine, but this is just for illustration):
string filepath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + #"\MyFolder\MyFile.xml";
Is there a specific need to specify the file path in the shortcuts?
Some Links:
Various ways to deal with config files and writeability.

Can I use auto-generated GUIDS with a merge module?

I use auto-guids in my <Product> but can't figure out how to use them with <Module>. I only get this error:
The component X has a key file with path 'TARGETDIR\company...'.
Since this path is not rooted in one of the standard directories (like
ProgramFiles Folder), the component does not meet the criteria for
having an automatically generated guid.
Above, company is the value mapped to !(loc.ProductManufacturerFolderName).
The only problem is that's not true. My directories are rooted in ProgramFiles just like my product is and my product works fine:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="MODULEINSTALLLOCATION" Name="!(loc.ProductManufacturerFolderName)">
<Directory Id="Data" Name="Data">
All my component declarations look roughly like this:
<Component Id="DocumentationParty_Business_TestCases_v1xlsx.component" Guid="{YOURGUID-1234-1234-84B3-C595A63428AD}" MultiInstance="yes">
<File Source="../../Development/Integration/SSIS/Documentation/Party_Business_Test Cases_v1.xlsx" KeyPath="yes" Id="DocumentationParty_Business_TestCases_v1xlsx.file" />
</Component>
Breaking it is easy, you only have to change the GUID to * and the above error results. This is broken:
<Component Id="DocumentationParty_Business_TestCases_v1xlsx.component" Guid="*" MultiInstance="yes">
<File Source="../../Development/ClaimsIntegration/SSIS/Documentation/Party_Business_Test Cases_v1.xlsx" KeyPath="yes" Id="DocumentationParty_Business_TestCases_v1xlsx.file" />
</Component>
I have a .wxs file for each directory to which components will be installed. All my component-holding .wxs files have the following structure:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="DatabasePolicy_Files">
<ComponentRef Id="DatabasePolicyCreateDatabasecmdtemplate.component" />
</ComponentGroup>
<DirectoryRef Id="DataPolicy">
<Component Id="DatabasePolicyCreateDatabasecmdtemplate.component" Guid="*" MultiInstance="yes">
<File Source="../../Development/Database/Policy/CreateDatabase.cmd.template" KeyPath="yes" Id="DatabasePolicyCreateDatabasecmdtemplate.file" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>
Each <ComponentGroup> is included in my master .wxs file through a <ComponentGroupRef>. This works in all my MSI projects and breaks only now that I've started working with merge modules. Also, I've tried commenting out all components except for which matches the above definition and it still breaks on the same error.
What is the problem?
I've had this similar issue myself and based on your error message it's probably the same.
Try adding a ComponentGuidGenerationSeed, that should solve your issue. The ComponentGuidGenerationSeed acts on all subfolders as well so a single one at the top-level is sufficient for all folders.
Example:
<Directory Id="DOCUMENTATIONFOLDER" Name="Documentation" ComponentGuidGenerationSeed="a9f690d3-22b3-488f-bdac-bb665c25933c"/>
http://wixtoolset.org/documentation/manual/v3/xsd/wix/directory.html
The Component Guid Generation Seed is a guid that must be used when a
Component with the generate guid directive ("*") is not rooted in a
standard Windows Installer directory (for example, ProgramFilesFolder
or CommonFilesFolder).

How to create msi installer which can install file located near by it?

How to create msi installer which can install file located near by it or fetch this file over http?
We want to create an msi installer with wix toolkit 3.9 that should distribute our virtual machine (size is bigger than allowed in cab files), hypervisor, register(unregister) powershell scripts and something else.
We cannot create MSI with big file.
I see two approaches:
We can put virtual machine image located near by msi installed and programming this installer to install image if it exists near by it.
d:> dir
myapp.msi
vm.vdi
We can agree with client that he must put vm image located near the msi installer manually, before run it.
Download this vm image with http. What are the options for this?
How I can do this ?
I do this like this:
<!-- This is a list of directories that are used by this product as installation locations or custom -->
<!-- action file search locations. -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder" Name="AppData">
<Directory Id="AppRootDirectory" Name="Lookd"/>
</Directory>
</Directory>
<DirectoryRef Id="AppRootDirectory">
<Component Id="SupplementalScripts" Guid="31693357-578d-4dde-aefc-92f413942810" KeyPath="yes" DiskId="1">
<CreateFolder/>
<RemoveFolder Id="RemoveAppRootDirectory" On="uninstall" />
<File Id="SupplementalScripts_Register" DiskId="1" Vital="yes" Source="dst\Scripts\Register.ps1" Checksum="no"/>
<File Id="SupplementalScripts_UnRegister" DiskId="1" Vital="yes" Source="dst\Scripts\UnRegister.ps1" Checksum="no"/>
<File Id="SupplementalScripts_Throw" DiskId="1" Vital="yes" Source="dst\Scripts\Throw.ps1" Checksum="no"/>
<RegistryKey Root="HKCU" Key="Software\CVisionLab\Lookd" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Name="Version" Value="[ProductVersion]" Type="string"/>
</RegistryKey>
</Component>
<Component Id="VirtualMachineDiskImage" Guid="daa7375f-7bd8-4e97-846a-db5f6e6b025a">
<CopyFile Id="VDIFile" SourceName="lookd.vdi" SourceDirectory="SOURCEDIR" DestinationDirectory="TARGETDIR" />
</Component>
</DirectoryRef>
But I recive and error when build:
error LGHT0094 : Unresolved reference to symbol 'Directory:SOURCEDIR' in section 'Product:{7BBA165B-9A8A-40D1-97FA-233F93426F83}'.
If 1 will work for you, then a WiX CopyFile should work. The source location of the copy would be the [SourceDir] property, and the destination some directory defined in your WiX.
If it's really that big, download may be tedious, but if you use it then do it from an app you install rather than run it from the MSI install.
Clarifying in response to comment: there are just two recommendations here that are separate and not related:
Use WiX CopyFile if you choose to copy the file from next to the MSI file to the client system.
If you choose the download option, doing that from the MSI will be tedious and very error prone. It may not even work given that VS custom actions have very limited (or no) access to the network. So do a download from the app you're installing and not the MSI, if you do in fact decide to download.

WIX deploy two assemblies to GAC

Using WIX, and trying to install two of the same assemblies, one for .Net35 and the other .Net40. I am using two separate components, however WIX is preventing the project from compiling.
<Directory Id="GAC40" Name="GAC">
<Component Id="MyDllServicesModuleGac40Component" Guid="307675AA-8AEC-473B-A78A-FB362CCEDE2A" Win64="yes">
<File Id="MyDllNet40DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net40\MyDll.dll" />
</Component>
</Directory>
<Directory Id="GAC35" Name="GAC">
<Component Id="MyDllServicesModuleGac35Component" Guid="47E6BD1B-25CD-466D-945E-06DCF0F2A269" Win64="yes">
<File Id="MyDllNet35DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net35\MyDll.dll" />
</Component>
</Directory>
The error I receive is:
Error 29 ICE30: The target file 'MyDll.dll' is installed in '[TARGETDIR]\GAC\' by two different components on an SFN system: 'MyDllServicesModuleGac40Component.DDD7D974_FE9C_4BA3_BDD3_A1A3A23F8057' and 'MyDllServicesModuleGac35Component.DDD7D974_FE9C_4BA3_BDD3_A1A3A23F8057'. This breaks component reference counting. D:\PROJECTS\MyDll.Experimental.3.0.0\Project\MyDll\MyDll.Wix.Services\MergeModule.wxs 34 1 MyDll.Wix.Services
The installer should be able to detect that the .Net35 dll gets installed to the GAC at C:\Windows\assembly, while the .Net40 dll gets installed to the GAC at C:\Windows\Microsoft.NET\assembly.
Renaming the DLLs is not an option.
Thanks!
UPDATE
Naturally I came up with a solution just after posting, seem wrapping the components in additional elements allowed me to get this to work. Later I read Tom Blodget's post so that is correct.
<Directory Id="GAC1" Name="GAC">
<Directory Id="GAC40" Name="GAC">
<Component Id="MyDllServicesModuleGac40Component" Guid="307675AA-8AEC-473B-A78A-FB362CCEDE2A" Win64="yes">
<File Id="MyDllNet40DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net40\MyDll.dll" />
</Component>
</Directory>
</Directory>
<Directory Id="GAC2">
<Directory Id="GAC35" Name="GAC">
<Component Id="MyDllServicesModuleGac35Component" Guid="FD74504A-6FE9-488E-9086-9DAD3024B35D" Win64="yes">
<File Id="MyDllNet35DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net35\MyDll.dll" />
</Component>
</Directory>
</Directory>
Well, hope it helps someone!
As explained by Aaron Stebner,
When you use the attribute Assembly=".net" for a file in WiX, it will
create entries in the MsiAssembly and MsiAssemblyName table for this
component and mark it as a GAC component. That means that the file
will only be installed to the GAC by this component, and it will not
install to the directory that the component is a child of. That
directory will only be used by Windows Installer to stage a copy of
that file when creating an administrative install point.
So the directories for your two components must be different since the file names are the same. If nothing else is targeted for those directories, they won't even be created. I put my GAC components under a subdirectory of my install folder:
<Directory Id="tmp_to_GAC" Name="tmp_to_GAC">
You'd need one for each GAC.

WiX - How to change name of a directory after installation

Pretty simple question, suppose my app will be installed as
myApp
+-- bin
+-- lib
I'd like to rename "lib" to "plugins" after installation, how can i do that?
There is a MoveFiles Element that might help, but no idea how to use it.
EDIT:
The problem here is, in my case, source files could be installed into different paths, this scenario described in here.
The only way I can figure out is to create two component groups and install them conditionally. However, using heat to harvest same subdir twice will cause ID conflicting, so I'm thinking to use different paths(e.g. lib and another-lib), and then rename one of the path back after installation, so this question arised...
Don't. Install the files correctly up front. The way that the Windows Installer tracks things will fight you every step of the way. Just install the files in the correct folder from the beginning. Probably not the answer you wanted.
I finally wrote a C++ program to extend heat generated wxs with another directory structure. So we can decide which path to install under different situations. It worked just like changing name during installation.
Here is the wxs file patched by my program. Basically it creates another directory WEBIDR and different subdirs, then adds another component group webGroup for later reference by condition element.
You can do the same thing manually, but if there are thousands of files awaiting, and if they are frequently updating, maybe a program(or script) is a better choice.
<Fragment>
<DirectoryRef Id="INSTALLDIR">
<Directory Id="dirA5528701EE26FFBF346CCE20EE8ACE99" Name="bin">
<Component Id="cmpEBA9C2A32D81BA8646BD1A64DBB39DB1" Guid="{142C531A-C71C-4890-9318-0FC42026C8FC}">
<File Id="filDB56E052EC783676CEF361C0C5AA71F3" KeyPath="yes" Source="$(var.runDir)\bin\boost_date_time-vc100-mt-1_47.dll" />
</Component>
</Directory>
<Directory Id="dir3279BEF4E08D9A00D2F205F325F00A81" Name="modules">
<Component Id="cmpDECCAE13F8937500E4AC367A8EAC95F4" Guid="{85CC0C94-1BFB-4062-BC4E-FBF143921301}">
<File Id="filDD3B40D68D0437B18B1108FBA49ABC1B" KeyPath="yes" Source="$(var.runDir)\modules\HelloAPI.dll" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="WEBDIR">
<Component Id="webcmpEBA9C2A32D81BA8646BD1A64DBB39DB1" Guid="{fec110c5-a1a0-4b07-8a35-50f1af84001a}">
<File Id="webfilDB56E052EC783676CEF361C0C5AA71F3" KeyPath="yes" Source="$(var.runDir)\bin\boost_date_time-vc100-mt-1_47.dll" />
</Component>
<Directory Id="webdirpluginF4E08D9A00D2F205F325F00A81" Name="plugins">
<Component Id="webcmpDECCAE13F8937500E4AC367A8EAC95F4" Guid="{3ef79a47-7681-4991-9726-02db38c22f6d}">
<File Id="webfilDD3B40D68D0437B18B1108FBA49ABC1B" KeyPath="yes" Source="$(var.runDir)\modules\HelloAPI.dll" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="runGroup">
<ComponentRef Id="cmpEBA9C2A32D81BA8646BD1A64DBB39DB1" />
<ComponentRef Id="cmpDECCAE13F8937500E4AC367A8EAC95F4" />
</ComponentGroup>
<ComponentGroup Id="webGroup">
<ComponentRef Id="webcmpEBA9C2A32D81BA8646BD1A64DBB39DB1" />
<ComponentRef Id="webcmpDECCAE13F8937500E4AC367A8EAC95F4" />
</ComponentGroup>
</Fragment>