В Wix# как избежать создания физической папки в целевой системе при развертывании только записей реестра?
У меня есть несколько связанных записей реестра Windows, которые я хочу упаковать в MSI, так что 1) происходит процесс удаления, и 2) тот факт, что эти записи реестра были применены к данному компьютеру, задокументирован записью "Установка и удаление программ".,
Проблема в том, что я могу заставить Wix# сделать это просто отлично, но я могу заставить MSI собирать только если все записи реестра находятся внутри блока "Dir", и это фактически приводит к созданию физической папки, которую я надеваю не хочу, на целевой системе.
В качестве временного решения я обернулся с помощью блока Dir, указав фиктивную папку "Temp". Инсталлятор фактически создает папку, которую я не хочу; все, что я хочу - это применить записи реестра.
В документации WiX описывается его базовая конструкция, TargetDir, как по существу указание установщику выполнить свои действия в целевой системе. См. http://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/write_a_registry_entry.html
В этом родном примере WiX XML кажется, что в целевой системе не будет создано никаких посторонних папок; будут применяться только нужные записи реестра. Какую синтаксическую конструкцию Wix# можно использовать для применения записей реестра, но при этом не нужно создавать фактическую папку в целевой системе?
Кажется, что все примеры Wix#, которые я видел до сих пор, имеют такой побочный эффект, как создание реальной папки в целевой системе, хотите ли вы одну или нет.
Я знаю, что, вероятно, мог бы сделать это, взяв.reg файлы записей реестра, собрав их в файлы.wxs с высокой температурой, а затем собрав их в msi со свечой и светом. Я действительно пытаюсь сохранить это в мире C#/Wix#. C# - это хорошо понятный набор навыков в моей организации; WiX меньше так. (Признание того, что Wix# построен на основе функций WiX, и некоторая степень понимания WiX и установщика Windows является существенной; это удобная зона, возможность использовать C# вместо XML, а не полностью логичная вещь.) В настоящее время мы выполняем многие из этих типов задач настройки реестра вручную, без каких-либо следов и без простой и надежной деинсталляции.
/// <summary>
/// Configure the Event Log on a Windows (server) to have MyApplication Log settings and record an entry for it in Programs and Features.
/// Note that this program creates the Windows Installer MSI that accomplishes this.
/// This program creates a WiX XML file that is then compiled by the WiX Toolkit (Candle and Light) into the MSI file.
/// </summary>
internal class Script
{
public static void Main()
{
// Define a new Installer Project object
var project = new Project("SetupMyApplicationEventLog" ,
// Provide dummy "Temp" install directory to satisfy WiX# Syntactical requirement. There are no actual files being installed.
new Dir(@"Temp"),
/*
* Event Log Registration Entries, translated from .reg file
*/
// First, add the root level key of the tree of keys
//[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log]
//"EventMessageFile"="C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll"
new RegValue(
RegistryHive.LocalMachine,
@"SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log",
"",
"") { AttributesDefinition = "Component:Win64=yes" },
//[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\STV.DSD.HQSYS.SERVICE2]
//"EventMessageFile"="C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll"
new RegValue(
RegistryHive.LocalMachine,
@"SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\" + "STV.DSD.HQSYS.SERVICE2",
"EventMessageFile",
"C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll") { AttributesDefinition = "Component:Win64=yes" },
//[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\STV.VFS.ONLINE]
//"EventMessageFile"="C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll"
new RegValue(
RegistryHive.LocalMachine,
@"SYSTEM\CurrentControlSet\Services\Eventlog\MyApplication Log\" + "STV.VFS.ONLINE",
"EventMessageFile",
"C:\\Windows\\Microsoft.NET\\Framework64\\v2.0.50727\\EventLogMessages.dll") { AttributesDefinition = "Component:Win64=yes" } );
// Set the properties of the setup project
// Set UI to minimal; there are no choices to be made here.
project.UI = WUI.WixUI_ProgressOnly;
project.Manufacturer = "STV";
project.OutFileName = "SetupMyApplicationEventLog";
project.GUID = new Guid("037C625A-609C-4C2C-9689-62A075B88AD7");
// Assign version # to setup MSI property of type System.Version
project.Version = new Version(4, 0, 0, 0);
// Add the Win64 attribute to the package, to force a 64-bit MSI to be created
project.Package.AttributesDefinition = "Platform=x64";
// Trigger the MSI file build
Compiler.BuildMsi(project);
//// Also create the .wxs file so we can see what was sent to WiX to build the MSI
Compiler.BuildWxs(project);
Console.WriteLine("productVersion=" + project.Version);
Console.ReadLine();
}
}
}
2 ответа
Вы можете достичь того, что вы хотите, добавив <RemoveFolder>
пометьте свой компонент в каталоге, который вы не хотите хранить. Смотрите ссылку.
Полученный MSI будет создан light
с предупреждением LGHT1079
что у вас нет файлов, но их можно игнорировать, если это так.
Простой пример XML, показывающий каталог с компонентом, который удаляет папку при установке / удалении и создает ключи реестра, заставляя удалить при удалении.
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="ApplicationRegistry" Guid="YOUR-GUID-HERE">
<RemoveFolder Id="RemoveTarget" Directory="TARGETDIR" On="both"/>
<RegistryKey Root="HKCU"
Key="Software\Microsoft\[ProductName]"
ForceDeleteOnUninstall="yes">
<RegistryValue Type="integer" Name="SomeIntegerValue" Value="1" KeyPath="yes"/>
<RegistryValue Type="string" Value="Default Value"/>
</RegistryKey>
</Component>
</Directory>
Вы бы просто использовали это имя для своего каталога или заменили Directory="TARGETDIR"
с названием вашего каталога.
Результатом после установки является раздел реестра без папки на целевом компьютере.
Вы должны выяснить, как вставить этот тег в ваш сгенерированный XML, но это тот эффект, который вам нужен.
Используя код Wix XML, предоставленный Райаном Дж, плюс пример "InjectXML" из кода примеров Wix#, я успешно создал файл wxs и получил работающий MSI, все еще оставаясь в среде кодирования Wix# в Visual Studio.
Вот соответствующий XML.wxs, который был сгенерирован ранее, под элементом:
<Directory Id="TARGETDIR" Name="SourceDir" >
<Directory Id="INSTALLDIR" Name="%Temp%">
<Component Id="INSTALLDIR.EmptyDirectory" Guid="037c625a-609c-4c2c-9689-62a075b88ae9">
<CreateFolder />
</Component>
Итак, что должно произойти: 1) Удалите элемент "", который находится в Product/Directory/Directory/Component. Пример Райана Дж ясно показал, что он относится к "Компоненту", связанному с первым "Каталогом", который должен быть создан, что в свою очередь относится к "TARGETDIR" в XML, который генерирует Wix#.
2) Вставьте синтаксис элемента "" под элементом Product/Directory/Directory/Component. Хотя я полагаю, что в этом элементе также можно ссылаться на идентификатор "INSTALLDIR.EmptyDirectory", я использовал идентификатор "TARGETDIR", и он работал так, как я хотел.
Вот результирующий код Wix#, который внедряет XML, предоставленный Райаном Дж.
internal class Script
{
public static void Main()
{
// Define a new Installer Project object
var project = new Project("SetupMyApplicationEventLog" ,
// Provide dummy "Temp" install directory to satisfy WiX# Syntactical requirement. There are no actual files being installed.
new Dir(@"TempDeleteMe"),
...
// Hook up a delegate to the "WixSourceGenerated" event, fires when .wxs file is fully created
Compiler.WixSourceGenerated += InjectXMLElement;
// Trigger the MSI file build
Compiler.BuildMsi(project);
...
/// Insert XML elements and attributes into the generated .wxs file
static void InjectXMLElement(System.Xml.Linq.XDocument document)
{
// Remove the <CreateFolder /> tag from Directory element -- we don't want to create it
var createFolderElement = document.Root.Select("Product/Directory/Directory/Component/CreateFolder");
createFolderElement.Remove();
// To cause the folder to not be created on the target system, add this element:
// <RemoveFolder Id="RemoveTarget" Directory="TARGETDIR" On="both"/>
var componentElement = document.Root.Select("Product/Directory/Directory/Component");
componentElement.Add(new XElement("RemoveFolder",
new XAttribute("Id", "RemoveTarget"),
new XAttribute("Directory", "TARGETDIR"),
new XAttribute("On","both")));
}