I'm working with Wix v4 to create a msi package. I had the problem, that I must set a Property in a CustomAction (C#) at the beginning of the installation.
This works fine, but now I'm a little bit confused. The property can't be used in all my cases.
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
<Property Id="ANUMMER" Value="A2000-0000" />
<Binary Id='CustomActionReadConfig' SourceFile='...'/>
<InstallUISequence>
<!-- Set the property over session["ANUMMER"] = "..." -->
<Custom Action="CustomActionReadConfig" Before="AppSearch" />
</InstallUISequence>
The ini file hasn't a problem
<IniFile Id="Programm.ini" Action="createLine" Key="ANUMMER" Name="Programm.ini" Section="Programm" Value="[ANUMMER]" Directory="Dir" />
For the directory I found the follow workaround
<SetDirectory Action="SetApplicationFolder" Id="APPLICATIONFOLDER" Value="[ProgramFilesFolder]\[COMPANYNAME]\[MYPROGRAMM]\[ANUMMER]" Sequence="ui"/>
But the shortcuts can' use it and I didn't find a workaround
<Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="Programm [ANUMMER]" WorkingDirectory="Dir" Advertise="yes" Icon="DesktopIcon.exe" IconIndex="0" />
<Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="Programm" WorkingDirectory="Dir" Advertise="yes" Icon="StartMenuIcon.exe" IconIndex="0">
<ShortcutProperty Key="Name" Value="Programm [ANUMMER]"/>
</Shortcut>
Like this, I need this property in some further cases. Do I use it wrong or do I have to use an special escape combination? Can't I use properties in Name attributes? Is there an other way, to use the input as variable witch I can set in the CustomAction? Or what is the basic problem, that I can't use such a custom runtime property in sutch ways?
Thanks for help
After searching for further options I found the reason for the problem for this in an other question here: Dynamically assigning name to shortcut at run time in WIX
The property value can be used in Formatted type. I wanted to use it in LongFileNameType (Simple Type) or in strings.
If someone knows a way, to fill a variable at runtime to solve this problem, it would be nice to share it with us.
Info: The value could also be a localization variable with the format !(loc.VARIABLE).
Related
For an MSBuild project, I would like to output some kind of a .config file that would be redistributed along the generated binary so the parameters used at build time can be checked by the users of the binary, programmatically.
Output file format:
PropertyName1=ValueA
PropertyName2=ValueB
...
Ideally, the list of properties to write would contain just their names. Maybe like:
<ItemGroup>
<MyExposedDictionary Include="Configuration" />
<MyExposedDictionary Include="Platform" />
<MyExposedDictionary Include="PropertyName1" />
...
</ItemGroup>
With MyExposedDictionary being the argument to give to some DotConfigFileWriter task, as well as the path of the destination file.
I found several ways to write down values to a file, including a sub-target with some C# code in it, but I'm new to MSBuild and I'm not sure how I can merge those requirements into a single Target to make it re-usable.
In case someone comes here with the same requirement, here is what I ended up with. Not really happy with the result as I was hoping for something more generic but at least it does the job and blends well in my project:
<Target Name="WriteBuildProperties" BeforeTargets="PreBuildEvent">
<WriteLinesToFile File="$(DotConfigFile)" Overwrite="true" Lines="" />
<WriteLinesToFile File="$(DotConfigFile)" Lines="ProjectName=$(ProjectName)" />
<WriteLinesToFile File="$(DotConfigFile)" Lines="Configuration=$(Configuration)" />
...
</Target>
If someone happen to have a more elegant solution, please jump in!
I am not sure where your problem is located. I have a similar requirement that a file is created by the program which just was compiled. I edited the properties of the project: in the build events enter a Post-build action like
REM create special file
"$(ProjectDir)$(OutDir)MyProgram.exe" /WriteFile MyFile.xml
Of course, you must also change your program such that it does the right thing when called with that parameter (and stops after having completed that action - does not show a GUI or start as a Windows Service).
I need to enable IE feature for WebBrowser control. To emulate IE11, I need to write a value to registry key
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
This manipulation need to be done during installation.
Here is my code in WIX script:
<?define var.IEFeatureEmulationKey = "Software\Microsoft\Internet Explorer\FeatureControl\FEATURE_BROWSER_EMULATION" ?>
....
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="registryValues" Guid="{some-guid}" >
<RegistryKey Root="HKCU" Key="$(var.IEFeatureEmulationKey)" Action="create">
<RegistryValue Name="MyApp.EXE" Value="11000" Type="integer" Action="write"/>
</RegistryKey>
</Component>
</Fragment>
This code work only if $(var.IEFeatureEmulationKey) contains no spaces. But I need to write a value to this specific key.
Please help, how tell WiX to write value to registry even in registry key contains spaces.
UPD:
Added appropriate issue in WiX repository
This Blogpost uses some special syntax I have not seen before either. It states that variable can be defined this way, even if it contains a white space character like so:
<!–?define var.IEFeatureEmulationKey = "Software\Microsoft\Internet Explorer\FeatureControl\FEATURE_BROWSER_EMULATION" ?>
The !- let aside, it looks quite similar to what you got. However, your value contains more than one whitespaces. I'm not sure if thats the value you truly want or if it was just for pointing the whitespace out clearly...
Still cannot overcome the issue, however I want to show a workaround that helped me.
I used custom action that allowed in WiX. First of all I added custom .NET assembly with following method within it
[CustomAction]
public static ActionResult SetRegistryItems(Session session)
{
session.Log("Begin SetRegistryItems");
try
{
// this private method actually does manipulation with registry
SetRegistry();
}
catch (Exception e)
{
session.Log(e.ToString());
}
return ActionResult.Success;
}
Then this method should be referenced in WiX config file (.wxs)
<Fragment>
...
<CustomAction Id='SetRegistryItems' BinaryKey='<NameOfTheAssemblyWithoutExtension>' DllEntry='SetRegistryItems' Execute='immediate'/>
...
<InstallExecuteSequence>
...
<Custom Action="SetRegistryItems" Before="LaunchConditions"/>
...
</InstallExecuteSequence>
...
</Fragment>
By using include tag I am trying to put comments for my code in separate file "docs.xml".
But it does not work. I have been trying both C# and VB.NET projects.
Here is my comments file:
<?xml version="1.0" encoding="utf-8" ?>
<d>
<summary>Demo summary</summary>
</d>
I have a class ABC with one single property Demo. before this property I write:
/// <include file="docs.xml" path="d/*" />
or in VB.NET:
''' <include file="docs.xml" path="d/*" />
However summary for ABC.Demo never appears in InteliSense / Object browser / another project (if I reference my project).
I have a strong feeling I am missing something here.
P.S. I have tried following "path[#name=]" pattern of XML file, but it does not help.
Perhaps you already saw this in the documentation then, but if I understand correctly, you have to do the following:
In Visual Studio, you specify the XML doc comments option in the Build
pane of the Project Designer. When the C# compiler sees the
tag, it will search for documentation comments in xml_include_tag.doc
instead of the current source file.
WiX first timer here.
I am building an installer for my product using WiX, and I am attempting to validate that MSMQ is installed before continuing the installation, following this SO answer. I am using a Condition element, defined like this:
<Condition Message="MSMQ must be installed in order to proceed.">
<![CDATA[MSMQ_INSTALLED<>"false"]]>
</Condition>
My Property and RegistrySearch look like this:
<Property Id="MSMQ_INSTALLED" Value="false" Secure="yes">
<RegistrySearch Id="Msmq.RS"
Root="HKLM"
Key="SOFTWARE\Microsoft\MSMQ"
Name="Values"
Type="raw"/>
</Property>
But it never evaluates properly. The installation stops with the message, regardless that the Registry Key does exist. So my questions are:
Am I using the Condition element correctly?
What have I defined incorrectly in the evaluation?
On further testing, I have found that the MSMQ_INSTALLED property contains the value "1: 0 2:", regardless of the Registry Key that I search for, either existing or fake.
EDIT: The Condition element exists inside the Product element; that is an important distinction as the Condition element is overloaded.
EDIT: Modified Condition to use CDATA directive, and invert Inner Condition logic, to more accurately reflect issue.
Well, the answer was on SO the whole time. Apparently, searching for a Registry Key is not supported out of the box with WiX, so I created a Custom Actions project and used the Binary tag to import it into my MSI, then run the Custom Action at the appropriate spot during the install. In my case, it was before LaunchConditions.
For reference, the code is:
public class CustomActions
{
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
session.Log("Begin CustomAction1");
var key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\MSMQ");
session["MSMQ_INSTALLED"] = key == null ? "-1" : "1";
return ActionResult.Success;
}
}
(The only class in the Custom Actions project)
<Binary Id="WixCustomAction" SourceFile="C:\work\RelayMed\src\dev\WixCustomAction\bin\Debug\WixCustomAction.CA.dll"/>
<CustomAction Id="CheckMsmq" BinaryKey="WixCustomAction" DllEntry="CustomAction1" Execute="immediate" Return="check"/>
(The import of the Binary into WiX, under the Product node.)
<InstallUISequence>
<Custom Action="CheckMsmq"
Before="LaunchConditions"/>
</InstallUISequence>
(The running of the Custom Action before LaunchConditions)
The Condition and the Property remained the same from the original post. The RegistrySearch was removed completely.
EDIT: Noted removal of the RegistrySearch tag.
Your authoring says "if HKLM\SOFTWARE\Microsoft\MSMQ#Values has the literal value 'false', then the install can continue."
Just use "MSMQ_INSTALLED" to check for any string found in the registry value.
Hello again stackoverflowians,
I thought it was about time that I learnt how to use a DI framework. I've heard a lot of good things about Castle Windsor so I decided to go with that. Now there are PLENTY of tutorials out there on how to use it, however, I cannot find much useful information about what to do when Generics get involved. Here is my issue.
I have a BaseDAO
namespace Utilities.DataAccess
{
public class BaseDAO<T> : IBaseDAO<T>
{
public BaseDAO(IConnectionProvider _connectionProvider)
{
// Stuff
}
}
}
Im a little bit new to generics in this context and I have seen some tutorials which have a 'BaseDAO' with no generic declaration and simply the interface it implements with the generics on it. I have used the above way of doing things on many previous projects (without IoC) and its worked fine for me...anyways, onwards to the App.config !
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"></section>
</configSections>
<castle>
<components>
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1, Utilities.DataAccess"
type="Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess" />
<component
id="NHibernateConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.NHibernateConnection" />
<component
id="XMLConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.XMLConnection, Utilities" />
</components>
</castle>
</configuration>
Now as some of you may of figured by now, this is a utility library. I intend to use this assembly for each project I create so that I don't have to write the same data access code which remains the same across all solutions. The implications of such of course is that I cannot tell castle exactly what type parameter I will pass to the BaseDAO, in one project it might be a Customer object, another entirely different. I have read on other forums that this is entirely possible as when you request the object from the container you can specify the type then like;
BaseDAO<Customer> baseDao = container.Resolve<BaseDAO<Customer>>();
Although it is against my design efforts, I have tried to use the following notation in the App.config
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtills.DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtils.DataAccess" />
However, this has not worked either, in any case I get the following error:
Utilities.Testing.DataAccess.Unit.Testing_BaseDAO (TestFixtureSetUp):
System.Exception : The type name Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess could not be located.
----> System.IO.FileNotFoundException : Could not load file or assembly 'Utilities.DataAccess' or one of its dependencies. The system cannot find the file specified.
Reading this error, I think it could be one of two things:
I am missing something from the config file to do with the generics of the types and services.
I have named something incorrectly I.E an assembly name.
I have treated the assembly name as the project that item is contained within, in other words, at no point have i used <solution name>.<project name>.<item folder>.<item name> but merely started at the project level...I assume that any config option would know what solution it is being called from.
Thank you for any help you may be able to give on this subject.
The assembly name can be found in Visual Studio thus:
In the solution explorer, double-click the properties node
Open the Application tab
Assembly name is near the top right corner
Or, if you're compiling at the command line, you use the /out argument.
Also, you need to specify the assembly for the type arguments (inside the square brackets). So, assuming all your types are in the DataAccess assembly, and that the assembly is called (for brevity's sake) "DataAccess":
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess" />
But I agree with other commenters that it's better to do the registrations in code. You don't have to use the verbose type syntax, for one, and you get compiler checking of your types. There are some disadvantages, however: it's harder to tell if you have unused types because the registration call counts as using the type.