web-dev-qa-db-ja.com

WiXのトリックとヒント

私たちはしばらくの間WiXを使用してきました、そして使いやすさについての通常の不満にもかかわらず、それはかなりうまくいっています。私が探しているのは、以下に関する有用なアドバイスです。

  • WiXプロジェクトの設定(レイアウト、参照、ファイルパターン)
  • WiXをソリューションに統合し、プロセスを構築/リリースする
  • 新規インストールおよびアップグレード用のインストーラの設定
  • 良いWiXハックを共有したい
264
si618
  1. 変数は別のwxiインクルードファイルに保存します。再利用を可能にし、変数は見つけやすく、(必要ならば)外部ツールによるより簡単な操作を可能にします。

  2. X86およびx64ビルド用のプラットフォーム変数を定義する

    <!-- Product name as you want it to appear in Add/Remove Programs-->
    <?if $(var.Platform) = x64 ?>
      <?define ProductName = "Product Name (64 bit)" ?>
      <?define Win64 = "yes" ?>
      <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
    <?else ?>
      <?define ProductName = "Product Name" ?>
      <?define Win64 = "no" ?>
      <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
    <?endif ?>
    
  3. インストール場所をレジストリに保存し、アップグレードで正しい場所を見つけられるようにします。たとえば、ユーザーがカスタムインストールディレクトリを設定したとします。

     <Property Id="INSTALLLOCATION">
        <RegistrySearch Id="RegistrySearch" Type="raw" Root="HKLM" Win64="$(var.Win64)"
                  Key="Software\Company\Product" Name="InstallLocation" />
     </Property>
    

    :WiXの達人 Rob Mensching優秀なブログエントリを投稿しました コマンドラインからプロパティが設定されている場合に、より詳細に説明し、Edgeのケースを修正します。

    1. 2.および3を使用した例.

    <?include $(sys.CURRENTDIR)\Config.wxi?>
    <Product ... >
      <Package InstallerVersion="200" InstallPrivileges="elevated"
               InstallScope="perMachine" Platform="$(var.Platform)"
               Compressed="yes" Description="$(var.ProductName)" />
    

    そして

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
    
  4. 最も簡単な方法は、新規インストールと単一MSIでのアップグレードの両方を可能にするため、常にメジャーアップグレードを行う ことですUpgradeCode は固有のGuidに固定されており、既存の製品をアップグレードしたくない限り、決して変更されません。

    :WiX 3.5には、寿命を延ばす新しい MajorUpgrade 要素があります もっと簡単

  5. [プログラムの追加と削除]でアイコンを作成する

    <Icon Id="Company.ico" SourceFile="..\Tools\Company\Images\Company.ico" />
    <Property Id="ARPPRODUCTICON" Value="Company.ico" />
    <Property Id="ARPHELPLINK" Value="http://www.example.com/" />
    
  6. リリースビルドでは、msiファイルをデプロイメントディレクトリにコピーしてインストーラをバージョンアップします。 AfterBuildターゲットから呼び出されたwixprojターゲットを使用した例です。

    <Target Name="CopyToDeploy" Condition="'$(Configuration)' == 'Release'">
      <!-- Note we append AssemblyFileVersion, changing MSI file name only works with Major Upgrades -->
      <Copy SourceFiles="$(OutputPath)$(OutputName).msi" 
            DestinationFiles="..\Deploy\Setup\$(OutputName) $(AssemblyFileVersion)_$(Platform).msi" />
    </Target>
    
  7. ワイルドカード(*)Guidを使用してファイルを収穫するために熱を使用してください。複数のプロジェクトでWXSファイルを再利用したい場合に便利です(同じ製品の複数のバージョンに関する私の回答を参照)。たとえば、このバッチファイルはRoboHelpの出力を自動的に取得します。

    @echo off  
    robocopy ..\WebHelp "%TEMP%\WebHelpTemp\WebHelp" /E /NP /PURGE /XD .svn  
    "%WIX%bin\heat" dir "%TEMP%\WebHelp" -nologo -sfrag -suid -ag -srd -dir WebHelp -out WebHelp.wxs -cg WebHelpComponent -dr INSTALLLOCATION -var var.WebDeploySourceDir 
    

    少し進んでいます、robocopyは、収穫前にSubversionの作業コピーのメタデータを取り除いています。 -drルートディレクトリ参照は、デフォルトのTARGETDIRではなく、インストール場所に設定されています。 -varは、ソースディレクトリを指定するための変数を作成するために使用されます(Web配置の出力)。

  8. ローカライズにStrings.wxlを使用することで、ウェルカムダイアログのタイトルに製品バージョンを含める簡単な方法。 (Credit: saschabeaumont 。この素晴らしいヒントはコメントに隠されているので追加しました)

    <WixLocalization Culture="en-US" xmlns="http://schemas.Microsoft.com/wix/2006/localization">
        <String Id="WelcomeDlgTitle">{\WixUI_Font_Bigger}Welcome to the [ProductName] [ProductVersion] Setup Wizard</String>
    </WixLocalization>
    
  9. 自分自身の手間を省き、ファイルごとに1つのコンポーネントについて Wim Coehenのアドバイス に従ってください。これにより、 コンポーネントのGUID を省略(またはワイルドカード*)することもできます。

  10. Rob Menschingにはvalue 3を検索することでMSIログファイルの問題を素早く追跡するための きちんとした方法 があります。国際化に関するコメントに注意してください。

  11. 条件付き機能を追加するときは、デフォルトの機能レベルを0(無効)に設定してから、条件レベルを希望の値に設定する方がより直感的です。デフォルトの機能レベルを> = 1に設定した場合、それを無効にするには条件レベルを0にする必要があります。つまり、条件ロジックは予想したものとは反対にする必要があります。

    <Feature Id="NewInstallFeature" Level="0" Description="New installation feature" Absent="allow">
      <Condition Level="1">NOT UPGRADEFOUND</Condition>
    </Feature>
    <Feature Id="UpgradeFeature" Level="0" Description="Upgrade feature" Absent="allow">
      <Condition Level="1">UPGRADEFOUND</Condition>
    </Feature>
    
157
si618

IISがインストールされているかどうかを確認します。

<Property Id="IIS_MAJOR_VERSION">
    <RegistrySearch Id="CheckIISVersion" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="MajorVersion" Type="raw" />
</Property>

<Condition Message="IIS must be installed">
    Installed OR IIS_MAJOR_VERSION
</Condition>

Vista [+]にIIS 6メタベース互換性がインストールされているかどうかを確認します。

<Property Id="IIS_METABASE_COMPAT">
    <RegistrySearch Id="CheckIISMetabase" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp\Components" Name="ADSICompatibility" Type="raw" />
</Property>

<Condition Message="IIS 6 Metabase Compatibility feature must be installed">
    Installed OR ((VersionNT &lt; 600) OR IIS_METABASE_COMPAT)
</Condition>
38
Simon Steele

すべてのIDを別々の名前空間に入れてください

  • 機能はF.で始まります。例:F.Documentation、F.Binaries、F.SampleCode。
  • コンポーネントはC.で始まります。例:C.ChmFile、C.ReleaseNotes、C.LicenseFile、C.IniFile、C.Registry
  • CustomActionsはCA.です。例:CA.LaunchHelp、CA.UpdateReadyDlg、CA.SetPropertyX
  • ファイルはFi.です
  • ディレクトリはDi.です
  • 等々。

私はこれがすべてのさまざまなカテゴリのすべてのさまざまなIDを追跡するのに非常に役立ちます。

34
Cheeso

素晴らしい質問です。いくつかのベストプラクティスを見せていただきたい.

たくさんのファイルを配布しているので、プロジェクトをいくつかのwxsソースファイルに設定しました。

私はProduct.wxsと呼ぶトップレベルのソースファイルを持っています。これは基本的にインストールのための構造を含みますが、実際のコンポーネントは含みません。このファイルにはいくつかのセクションがあります。

<Product ...>
  <Package ...>
    <Media>... 
   <Condition>s ...
   <Upgrade ..>
   <Directory> 
        ...
   </Directory>
   <Feature>
      <ComponentGroupRef ... > A bunch of these that
   </Feature>
   <UI ...>
   <Property...>
   <Custom Actions...>
   <Install Sequences....
  </Package>
</Product>

残りの.wixファイルは、Product.wxsのFeatureタグで参照されるComponentGroupを含むフラグメントで構成されています。私のプロジェクトは私が配布するファイルのNice論理グループを含んでいます

<Fragment>
   <ComponentGroup>
     <ComponentRef>
     ....
    </ComponentGroup>
    <DirectoryRef>
      <Component... for each file
      .... 
    </DirectoryRef>
</Fragment>

フラグメントはProduct.wxsファイル(たとえばDirectoryRef)内の名前を参照する必要があるため、これは完璧ではありません。私のOOクモの感覚はちょっとだけいじりますが、単一の大きなソースファイルを維持する方が簡単です。

私はこれについてのコメントを聞きたいです、または誰かにも何か良いヒントがあるならば!

25
Peter Tate

アプリケーションを起動するための終了ダイアログ、またはヘルプファイルにチェックボックスを追加します。

...

<!-- CA to launch the exe after install -->
<CustomAction Id          ="CA.StartAppOnExit"
              FileKey     ="YourAppExeId"
              ExeCommand  =""
              Execute     ="immediate"
              Impersonate ="yes"
              Return      ="asyncNoWait" />

<!-- CA to launch the help file -->
<CustomAction Id         ="CA.LaunchHelp"
              Directory  ="INSTALLDIR"
              ExeCommand ='[WindowsFolder]hh.exe IirfGuide.chm'
              Execute    ="immediate"
              Return     ="asyncNoWait" />

<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT"
          Value="Launch MyApp when setup exits." />

<UI>
  <Publish Dialog  ="ExitDialog"
           Control ="Finish"
           Order   ="1"
           Event   ="DoAction"
           Value   ="CA.StartAppOnExit">WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT</Publish>
</UI>

このようにすると、「標準」の外観はまったく正しくありません。チェックボックスは常に灰色の背景で、ダイアログは白です。

代替テキストhttp://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_1.gif

これを回避する1つの方法は、 別の場所にあるチェックボックスを使用して、独自のカスタムExitDialogを指定する です。これは機能しますが、1つのコントロールの色を変更するだけの作業が多いようです。同じことを解決するもう1つの方法は、生成されたMSIを後処理して、その特定のCheckBoxコントロールのControlテーブルのX、Yフィールドを変更することです。 JavaScriptコードは次のようになります。

var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
var sql = "UPDATE `Control` SET `Control`.`Height` = '18', `Control`.`Width` = '170'," +
          " `Control`.`Y`='243', `Control`.`X`='10' " +
          "WHERE `Control`.`Dialog_`='ExitDialog' AND " + 
          "  `Control`.`Control`='OptionalCheckBox'";
var view = database.OpenView(sql);
view.Execute();
view.Close();
database.Commit();

(light.exeから)MSIが生成された後に(cscript.exeを使用して)コマンドラインスクリプトとしてこのコードを実行すると、よりプロフェッショナルに見えるExitDialogが生成されます。

代替テキストhttp://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_2.gif

20
Cheeso

同じソースファイルを使用してLive、Test、Trainingなどのバージョンを作成します。

一言で言えば:各インストーラに対して一意のUpgradeCodeを作成し、各インストーラに対して各Guidの最初の文字を自動的に定義し、残りの31を一意にします。

前提条件

仮定

  • WiX変数はUpgradeCode、ProductName、InstallNameを定義するために使用されます。
  • あなたはすでに動くインストーラーを持っています。あなたがするまで私はこれを試みないでしょう。
  • すべてのコンポーネントは1つのファイル(Components.wxs)に保存されています。あなたが複数のファイルを持っているなら、このプロセスはうまくいくでしょう。

ディレクトリ構造

  • Setup.Library
    • すべてのwxsファイル(コンポーネント、機能、UIダイアログなど)
    • Common.Config.wxi(ProductCode = "*"、ProductVersion、PlatformProgramFilesFolder、...)
  • Setup.Live(wixproj)
    • "Add Existing File" - > "Add As Link"を使用して、すべてのSetup.Libraryファイルをリンクします(Visual Studioの[追加]ボタンの横にある小さな下向き矢印ボタン)。
    • Config.wxi(一意のUpgradeCode、ProductName、InstallNameなどがあります)
  • Setup.Test、...
    • ライブと同じですが、Config.wxiはテスト環境用に設定されています。

プロセス

  • Setup.Libraryディレクトリを作成し、既存のプロジェクトからすべてのwxsファイルとwxiファイル(Config.wxiを除く)を移動します。
  • 通常のwixprojに従ってSetup.Live、Setup.Testなどを作成します。
  • Setup.LiveなどのwixprojにBeforeBuildターゲットを追加して、MSBuildコミュニティタスクFileUpdateを実行してGuidsを変更します(私はAをLiveに、Bをテストに、Cをトレーニングに使用)
  • After.Buildターゲットを追加してComponents.wxs Guidsを0に戻します。
  • 各MSIの各コンポーネントに修正済みのguidがあることをOrcaで確認します。
  • 元のGUIDが復元されたことを確認します。
  • 各MSIが正しい製品と場所をインストール(およびアップグレード)していることを確認します。

例Config.wxi

<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Upgrade code should not change unless you want to install 
     a new product and have the old product remain installed, 
     that is, both products existing as separate instances. -->
<?define UpgradeCode = "YOUR-GUID-HERE" ?>

<!-- Platform specific variables -->
<?if $(var.Platform) = x64 ?>
  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?define ProductName = "Foo 64 Bit [Live]" ?>
<?else ?>
  <?define ProductName =  "Foo [Live]" ?>
<?endif ?>

<!-- Directory name used as default installation location -->
<?define InstallName = "Foo [Live]" ?>

<!-- Registry key name used to store installation location -->
<?define InstallNameKey = "FooLive" ?>

<?define VDirName = "FooLive" ?>
<?define AppPoolName = "FooLiveAppPool" ?>
<?define DbName = "BlahBlahLive" ?>
</Include>

例Config.Common.wxi

<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Auto-generate ProductCode for each build, release and upgrade -->
<?define ProductCode = "*" ?>

<!-- Note that 4th version (Revision) is ignored by Windows Installer -->
<?define ProductVersion = "1.0.0.0" ?>

<!-- Minimum version supported if product already installed and this is an upgrade -->
<!-- Note that 4th version (Revision) is ignored by Windows Installer -->
<?define MinimumUpgradeVersion = "0.0.0.0" ?>

<!-- Platform specific variables -->
<?if $(var.Platform) = x64 ?>
   <?define Win64 = "yes" ?>
   <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
   <?define Win64 = "no" ?>
   <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>

<?define ProductManufacturer = "Foo Technologies"?>

<!-- Decimal Language ID (LCID) for the Product. Used for localization. -->
<?define ProductLanguage = "1033" ?>

<?define WebSiteName = "DefaultWebSite" ?>
<?define WebSitePort = "80" ?>

<?define DbServer = "(local)" ?>
</Include>

例Components.wxs

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.Microsoft.com/wix/2006/wi">
  <!-- The pre-processor variable which allows the magic to happen :) -->
  <?include $(sys.CURRENTDIR)\Config.wxi?>
  <?include ..\Setup.Library\Config.Common.wxi?>
  <Fragment Id="ComponentsFragment">
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
          <Component Id="ProductComponent" Guid="0XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" KeyPath="yes">
          ...

注:コンポーネントごとに1つのファイルを使用し、そのファイルをキーパスとして設定して、Guid属性をComponentから除外する(*と同等)ことをお勧めします。これにより、以下に示すModifyComponentsGuidsおよびRevertComponentsGuidsターゲットを呼び出す必要がなくなります。ただし、これはすべてのコンポーネントにとって不可能な場合があります。

例Setup.Live.wixproj

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
  <CallTarget Targets="ModifyComponentsGuids" />
</Target>
<Target Name="AfterBuild">
  <CallTarget Targets="RevertComponentsGuids" />
</Target>
<!-- Modify the first character of every Guid to create unique value for Live, Test and Training builds -->
<Target Name="ModifyComponentsGuids">
  <FileUpdate Files="..\Setup.Library\Components.wxs" Regex="Guid=&quot;([a-f]|[A-F]|\d)" ReplacementText="Guid=&quot;A" />
</Target>
<!-- Revert the first character of every Guid back to initial value -->
<Target Name="RevertComponentsGuids">
  <FileUpdate Files="..\Setup.Library\Components.wxs" Regex="Guid=&quot;([a-f]|[A-F]|\d)" ReplacementText="Guid=&quot;0" />
</Target>

最後の考え

  • このプロセスは、同じインストーラーのマージモジュール(Live、Testなど)用に異なるインストーラーを作成する場合にも機能します。より安全なオプションのように思われるので、私は異なるインストーラーを使いました。彼らが同じボックスにいて、あなたが異なるマージモジュールのための機能を使うのであれば、誰かがTrainingの代わりにLiveをアップグレードするかもしれません。
  • MSIを使用してアップグレードと新規インストール、つまりメジャーアップグレードのみのアプローチを実行し、インストール場所をレジストリに保存する場合は、インストールごとにキー名の変数を必ず作成してください。
  • また、各Config.wxiに変数を作成して、インストーラごとに一意の仮想ディレクトリ名、アプリケーションプール、データベース名などを有効にします。

UPDATE 1:自動生成コンポーネントGuid Guid = "*"でコンポーネントを作成する場合、FileUpdateタスクを呼び出す必要がなくなります。ファイルごとに、ファイルをキーパスとして設定します。

UPDATE 2:私たちが直面している問題の1つは、あなたがあなたのコンポーネントのGuidのものを自動生成せずにビルドが失敗した場合です。一時ファイルは手動で削除する必要があります。

UPDATE 3:svnへの依存を取り除く方法を見つけました:外​​部ファイルと一時ファイルの作成。これはビルドプロセスをより弾力的にし(そしてあなたがあなたのGuidをワイルドカードにすることができないならば最良の選択肢です)そしてライトまたはろうそくでビルド失敗があればもろくなりません。

UPDATE 4:複数インスタンス のサポートインスタンス変換の使用はWiX 3.0以降で、間違いなく一見の価値があります。

18
si618

Msi診断ログを使用して詳細な障害情報を取得する

msiexec /i Package.msi /l*v c:\Package.log

どこで

Package.msi
c:\ Package.log

Msiエラーコード

Wixイントロビデオ
"Mr. WiX" Rob MenschingをフィーチャーしたOh and Random Wixの紹介ビデオは、 "概念的な全体像"として役立ちます

17
Terrance

Javascript CustomActionsを使用するのは簡単です。

JavascriptはMSI CustomActionsに使用するのは間違ったことです 。与えられた理由:デバッグするのが難しい、それを信頼できるものにするのが難しい。同意しません。デバッグするのは難しくありません、確かにC++ほど難しくありません。ちょっと違います。私はJavascriptでCustomActionsを書くのはとても簡単で、C++を使うよりもずっと簡単であることがわかりました。はるかに高速。そして同様に信頼できます。

ただ1つ欠点があります。JavascriptCustomActionsはOrcaを介して抽出できますが、C/C++ CAはリバースエンジニアリングを必要とします。あなたがあなたのインストーラの魔法を知的財産権で保護されていると考えるならば、あなたはスクリプトを避けたいと思うでしょう。

あなたがスクリプトを使用する場合、あなたはただ何らかの構造から始める必要があります。ここにあなたが始めるためのいくつかがあります。


CustomActionのJavascript「ボイラープレート」コード:

//
// CustomActions.js 
// 
// Template for WIX Custom Actions written in Javascript.
// 
// 
// Mon, 23 Nov 2009  10:54
// 
// ===================================================================


// http://msdn.Microsoft.com/en-us/library/sfw6660x(VS.85).aspx
var Buttons = {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
};

var Icons = {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
};

var MsgKind = {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
};

// http://msdn.Microsoft.com/en-us/library/aa371254(VS.85).aspx
var MsiActionStatus = {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
};


function MyCustomActionInJavascript_CA() {
    try {
        LogMessage("Hello from MyCustomActionInJavascript");
        // ...do work here...
        LogMessage("Goodbye from MyCustomActionInJavascript");
    }
    catch (exc1) {
        Session.Property("CA_EXCEPTION") = exc1.message ;
        LogException(exc1);
        return MsiActionStatus.Abort;
    }
    return MsiActionStatus.Ok;
}

// Pop a message box.  also spool a message into the MSI log, if it is enabled. 
function LogException(exc) {
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "CustomAction: Exception: 0x" + decimalToHexString(exc.number) + " : " + exc.message;
    Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}


// spool an informational message into the MSI log, if it is enabled. 
function LogMessage(msg) {
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "CustomAction:: " + msg;
    Session.Message(MsgKind.Log, record);
}


// http://msdn.Microsoft.com/en-us/library/d5fk67ky(VS.85).aspx
var WindowStyle = {
    Hidden : 0,
    Minimized : 1,
    Maximized : 2
};

// http://msdn.Microsoft.com/en-us/library/314cz14s(v=VS.85).aspx
var OpenMode = {
    ForReading : 1,
    ForWriting : 2,
    ForAppending : 8
};

// http://msdn.Microsoft.com/en-us/library/a72y2t1c(v=VS.85).aspx
var SpecialFolders = {
    WindowsFolder : 0, 
    SystemFolder :  1, 
    TemporaryFolder : 2
};

// Run a command via cmd.exe from within the MSI
function RunCmd(command)
{
    var wshell = new ActiveXObject("WScript.Shell");
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var tmpdir = fso.GetSpecialFolder(SpecialFolders.TemporaryFolder);
    var tmpFileName = fso.BuildPath(tmpdir, fso.GetTempName());

    LogMessage("Shell.Run("+command+")");

    // use cmd.exe to redirect the output
    var rc = wshell.Run("%comspec% /c " + command + "> " + tmpFileName, WindowStyle.Hidden, true);
    LogMessage("Shell.Run rc = "  + rc);

    // here, optionally parse the output of the command 
    if (parseOutput) {
        var textStream = fso.OpenTextFile(tmpFileName, OpenMode.ForReading);
        while (!textStream.AtEndOfStream) {
            var oneLine = textStream.ReadLine();
            var line = ParseOneLine(oneLine);
                ...
        }
        textStream.Close();
    }

    if (deleteOutput) {
        fso.DeleteFile(tmpFileName);
    }

    return {
        rc : rc,
        outputfile : (deleteOutput) ? null : tmpFileName
    };
}

次に、カスタムアクションを次のように登録します。

<Fragment>
  <Binary Id="IisScript_CA" SourceFile="CustomActions.js" />

  <CustomAction Id="CA.MyCustomAction"
              BinaryKey="IisScript_CA"
              JScriptCall="MyCustomActionInJavascript_CA"
              Execute="immediate"
              Return="check" />
</Fragmemt>

もちろん、複数のカスタムアクションに対して、好きなだけJavascript関数を挿入できます。 1つの例:私はJavascriptを使ってIIS上でWMIクエリを実行し、ISAPIフィルタをインストールできる既存のWebサイトのリストを取得しました。その後、このリストを使用して、後のUIシーケンスで表示されるリストボックスにデータを入力しました。とても簡単です。

IIS 7では、IIS用のWMIプロバイダーがないため、作業を実行するためにappcmd.exeを呼び出すためにShell.Run()アプローチを使用しました。簡単です。

関連質問: Javascript CustomActionsについて

17
Cheeso

Heat.exeを使用して顔を粉砕し、大規模なインストールで "Epic Pwnage"を実行する

Si's および Robert-P's に展開すると、熱に関する回答が得られます。

翻訳:(個別のファイルを手作業でプロジェクトに入力することを避け、全体的により簡単なプロセスのためにビルドを自動化するためにheatを使用しています。)

WiX 2.0 Heat構文の詳細

新しいバージョン(古いバージョンとの違いはそれほど多くありませんが、煩わしい構文の変更がある可能性があります...)に移動します。Heatはcmd.exeから入力し、heatと入力するだけです。必要に応じて新しいバージョンで。

ビジュアルスタジオ2010のビルドイベントに以下を追加します。
(右クリック[プロジェクト] - > [プロパティ] - > [ビルドイベント] - > [ビルド前イベント])

$(WIX)bin\heat.exe" dir "$(EnviromentVariable)" -cg GroupVariable -gg -scom -sreg -sfrag - srd -dr INSTALLLOCATION -var env.LogicPath -out "$(FragmentDir)\FileName.wxs

-gg 

Heatが実行されたときにGuidを生成します(上記のコマンドを実行したときのように)

-scom 

「COMファイル」を取得しないでください

-sreg 

「レジストリファイル」を取得しないでください。

-sfrag 

「フラグメント」をつかまえてはいけない

-srd 

"ルートディレクトリ"をつかんではいけない

dir

dirはHeatがフォルダーを調べたいことを示します

"$(環境変数)"

(右クリックプロジェクト、[プロパティに移動])プロジェクトプロパティ - > [ビルド]セクションの[プリプロセッサ変数の定義](Visual Studio 2010を想定)で[プリプロセッサ変数]に追加する変数の名前。

例:
 EnviromentVariable = C:\ Project\bin\Debug;
-cg GroupVariable 

作成されたフラグメントからメインのwxsファイルに参照されるComponentGroup

FragmentDir

出力wxsフラグメントが格納されるフラグメントディレクトリ

FileName.wxs

ファイルの名前

ここに完全なチュートリアル、とてもfreakin参考になった

パート1パート2

12
Terrance

Peter Tateは、再利用可能なComponentGroup定義を別々のwixフラグメントで定義する方法を既に示しました。これに関連するいくつかの追加のトリック:

ディレクトリエイリアス

コンポーネントグループのフラグメントは、メインの製品wxsによって定義されているディレクトリについて知る必要はありません。コンポーネントグループの断片の中で、あなたはこのようなフォルダについて話すことができます:

<DirectoryRef Id="component1InstallFolder">
...
</DirectoryRef>

そうすれば、メイン製品はそのディレクトリの1つ(例えば "productInstallFolder")を次のようにエイリアスすることができます。

<Directory Id="productInstallFolder" Name="ProductName">
   <!-- not subfolders (because no Name attribute) but aliases for parent! -->
   <Directory Id="component1InstallFolder"/> 
   <Directory Id="component2InstallFolder"/> 
</Directory>

依存グラフ

ComponentGroup要素には、ComponentGroupRef子要素を含めることができます。あなたがそれらの間に複雑な依存グラフを持つ再利用可能なコンポーネントの大きなプールを持っているなら、これは素晴らしいです。各コンポーネントに対してComponentGroupを独自のフラグメントで設定し、依存関係を次のように宣言するだけです。

<ComponentGroup Id="B">
   <ComponentRef Id="_B" />
   <ComponentGroupRef Id="A">
</ComponentGroup>

アプリケーションの直接の依存関係であるためにセットアップでコンポーネントグループ "B"を参照すると、アプリケーションの作成者が "B"の依存関係であることを認識しなかったとしても、コンポーネントグループ "A"を自動的に取り込みます。循環的な依存関係がない限り、それは "正しく動作"します。

再利用可能なwixlib

上のディペンデンシーグラフの考えは、big-pool-o-reusable-componentsをlit.exeを使って再利用可能なwixlibにコンパイルした場合に最もうまくいきます。アプリケーションのセットアップを作成するときには、wixobjファイルのようにこのwixlibを参照できます。 candle.exeリンカは、メイン製品のwxsファイルに「引き込まれ」られていないフラグメントを自動的に削除します。

12
Wim Coenen

ビルド中にT4を使用してWXSファイルを生成することについて言及したことがある人は誰も驚いています。私はHenry Lee @ New Age Solutions によってこれについて学びました。

基本的には、T4テンプレートを実行するためのカスタムMSBuildタスクを作成します。そのテンプレートは、Wixプロジェクトがコンパイルされる直前にWXSを出力します。これにより、(実装方法に応じて)別のソリューションをコンパイルしたときにすべてのアセンブリ出力を自動的に含めることができます(つまり、新しいアセンブリを追加するたびにwxを編集する必要がなくなります)。

12

COMオブジェクトを含める:

heatは、すべてではないにしても、ほとんどすべてのレジストリエントリとそれらに必要なその他の設定を生成します。喜ぶ!

マネージCOMオブジェクト(別名、.NETまたはC#COMオブジェクト)を含める

マネージCOMオブジェクトでheatを使用すると、ほぼ完全なwixドキュメントが得られます。

GACでライブラリを入手する必要がない場合(つまり、世界的に入手可能な場合:.NETアセンブリではこれを使用する必要はほとんどありません)、意図していない場合はおそらくこの時点で何か問題があります。共有ライブラリ)CodeBaseレジストリキーを必ず[#ComponentName]に設定するように更新します。 GACへのインストールを計画している場合(たとえば、誰もが使用する新しい共通のライブラリを作成した場合)、このエントリを削除し、File要素に2つの新しい属性AssemblyKeyPathを追加する必要があります。アセンブリは ".net"に設定し、KeyPathは "yes"に設定する必要があります。

ただし、一部の環境(特にスクリプト言語などの管理対象メモリがある環境)では、Typelibにもアクセスする必要があります。 必ずtypelibでheatを実行してください そしてそれをインクルードしてください。 heatは、必要なすべてのレジストリキーを生成します。それはどれぐらいクールですか?

9
Robert P

C:\ProductNameへのインストール

一部のアプリケーションはC:\ProductNameまたは同様のものにインストールする必要がありますが、C:\Program Files\CompanyName\ProductNameへのネットインストールの例の99.9%(100%ではない場合)です。

次のコードを使用して、TARGETDIRプロパティをC:ドライブのルートに設定できます( WiX-usersリスト から取得)。

<CustomAction Id="AssignTargetDir" Property="TARGETDIR" Value="C:\" Execute="firstSequence" />
<InstallUISequence>
    <Custom Action="AssignTargetDir" Before="CostInitialize">TARGETDIR=""</Custom>
</InstallUISequence>
<InstallExecuteSequence>
    <Custom Action="AssignTargetDir" Before="CostInitialize">TARGETDIR=""</Custom>
</InstallExecuteSequence>

注:デフォルトでは、TARGETDIRdoes notC:\を指します!むしろROOTDRIVEを指し、これは空き容量が最も多いドライブのルートを指します( こちらを参照 )-これは必ずしもC:ではありませんドライブ。別のハードドライブ、パーティション、またはUSBドライブがある可能性があります。

次に、<Product ...>タグの下のどこかに、通常どおり次のディレクトリタグが必要です。

<Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="APPLICATIONFOLDER" Name="$(var.ProductName)">
        <!-- your content goes here... -->
    </Directory>
</Directory>
8
gehho

環境変数

あなたのWxsドキュメントをwixobjコードにコンパイルするとき、あなたは様々な情報を決定するために環境変数を利用することができます。たとえば、プロジェクトに含めるファイルを変更したいとします。 MSIをビルドする直前に設定したRELEASE_MODEという環境変数があるとしましょう(スクリプトを使っても手動でもかまいません)。wixソースでは、次のようなことができます。

<define FILESOURCE = c:\source\output\bin\$(env.RELEASE_MODE) >

そして、後であなたのコードの中で、その場であなたのwxs文書を変更するためにその場でそれを使ってください、例えば:

<Icon Id="myicon.ico" SourceFile="$(var.FILESOURCE)" />
7
Robert P
7
BozoJoe

Votiveなしでマネージコード(C#)で書かれたWIX用のカスタムアクションを作成する

http://www.codeproject.com/KB/install/wixcustomaction.aspx

7
user431821

ダイアログの編集

ダイアログを編集するための優れた機能の1つは、バージョン4.0.1.7090(またはそれ以降)でSharpDevelopを使用することです。このツールの助けを借りて、スタンドアロンダイアログ(例えばInstallDirDlg.wxsのようなWiXソースからのwxsファイル)はデザインビューで開かれ、プレビューされそして編集されることができる。

7
user432758

IIS enable32BitAppOnWin64フラグを設定する http://trycatchfail.com/blog/post/WiX-Snippet-change-enable32BitAppOnWin64.aspx

<InstallExecuteSequence>
   <RemoveExistingProducts After="InstallFinalize" />
   <Custom Action="ConfigureAppPool" After="InstallFinalize" >
     <![CDATA[NOT Installed AND VersionNT64 >= 600]]>         
   </Custom>
</InstallExecuteSequence>

<CustomAction Id="ConfigureAppPool" Return="check" Directory="TARGETDIR" ExeCommand="[SystemFolder]inetsrv\appcmd set apppool /apppool.name:[APPPOOLNAME] /enable32BitAppOnWin64:false" />
6
EdmundYeung99

インストールパッケージを展開する前に、その内容を常に管理します。

これは、(Terrencesの記事によると)コマンドラインを開いてコマンドラインを呼び出すだけの簡単な呼び出しです。

msiexec /a Package.msi /qb TARGETDIR="%CD%\Extract" /l*vx "%CD\install.log%"

これはパッケージの内容を現在のパスを持つサブディレクトリ 'Extract'に抽出します。

5
tobaer
  • GUIの最初の画面のどこかに(小さい)製品バージョンを表示します。人々は正しいバージョンを選ぶたびに間違いを犯す傾向があるからです。 (そして開発者たちが年齢を探し続けるようにしてください。)

  • TFSBuildをセットアップして、さまざまな環境用の構成を使用して変換(.mstファイル)も生成します。 (私たちは展開する必要があるすべての環境について知っています)。

Grant Hollidayによるオリジナルのウェブログ投稿が停止しているので、ここにその内容をコピーして貼り付けます。


XMLMarch 11 2008からMSI変換ファイルを生成するMSBuildタスク

前回の投稿で、MSI変換(* .mst)ファイルを使用して一般的なMSIパッケージから環境固有の構成設定を分離する方法について説明しました。

これにより、設定の柔軟性が高まりますが、変換ファイルには2つの欠点があります。

  1. それらはバイナリフォーマットです
  2. 変換ファイルを「編集」または「表示」することはできません。どのような変更が含まれているのかを確認するには、適用するか再作成する必要があります。

幸いなことに、Microsoft Windowsインストーラオブジェクトライブラリ(c:windowssystem32msi.dll)を使ってMSIの「データベース」を開き、変換ファイルを作成することができます。

Alex Shevchuk - MSIからWiXへ - パート7 - VbScriptでこれを実現する方法を示すためのTransformsを使用したインストールのカスタマイズ。基本的に私がしたことはすべてAlexの例を取り、Interop.WindowsInstaller.dllを使用してMSBuildタスクを実装したことです。 MSBuildタスク

ダウンロード ソースコードとサンプルtransforms.xmlはこちら(〜7Kb Zip形式のVS2008ソリューション)


5
thijs

個別にパッチを当てることができるコンポーネントを独自のフラグメントの中に入れる

フラグメントにコンポーネントを含める場合はallそのフラグメントに含まれるコンポーネントを含める必要があるということは、製品のインストーラとパッチの両方を作成するのに役立ちます。インストーラをビルドする場合、コンポーネントの参照を見逃した場合は、light.exeからリンクエラーが発生します。ただし、パッチを作成するときに、フラグメントに単一のコンポーネント参照を含めると、そのフラグメントからall変更されたコンポーネントがパッチに表示されます。

このような:

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent1" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}" DiskId="1">
            <File Id="SampleFile1" Source=".\$(var.Version)f\Sample1.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent2" Guid="{6CEA5599-E7B0-4D65-93AA-0F2F64402B22}" DiskId="1">
           <File Id="SampleFile2" Source=".\$(var.Version)f\Sample2.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent3" Guid="{4030BAC9-FAB3-426B-8D1E-DC1E2F72C2FC}" DiskId="1">
           <File Id="SampleFile3" Source=".\$(var.Version)f\Sample3.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

これの代わりに:

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent1" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}" DiskId="1">
            <File Id="SampleFile1" Source=".\$(var.Version)\Sample1.txt" />
        </Component>

        <Component Id="SampleComponent2" Guid="{6CEA5599-E7B0-4D65-93AA-0F2F64402B22}" DiskId="1">
           <File Id="SampleFile2" Source=".\$(var.Version)\Sample2.txt" />
        </Component>

        <Component Id="SampleComponent3" Guid="{4030BAC9-FAB3-426B-8D1E-DC1E2F72C2FC}" DiskId="1">
           <File Id="SampleFile3" Source=".\$(var.Version)\Sample3.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

また、WiX.chmヘルプファイルの「Using Purely WiX」トピックを使用してパッチを適用する場合は、次の手順に従ってパッチを生成します。

torch.exe -p -xi 1.0\product.wixpdb 1.1\product.wixpdb -out patch\diff.wixmst
candle.exe patch.wxs
light.exe patch.wixobj -out patch\patch.wixmsp
pyro.exe patch\patch.wixmsp -out patch\patch.msp -t RTM patch\diff.wixmst

コンポーネントを別々のフラグメントで使用して1.1バージョンのproduct.wixpdbをビルドするだけでは不十分です。出荷前に製品を正しく断片化するようにしてください。

5
Dave Andersen

Wix3.0以降からEULAを印刷する

1)wixのソースコードをコンパイルするとき、light.exeはコマンドラインでWixUIExtension.dllを参照しなければなりません。これにはコマンドラインスイッチ-extを使用してください。

2)WixUIExtension.dllへの参照を追加したときにプロジェクトがコンパイルに失敗した場合、これはおそらくDialog IDの衝突、つまりWixUIExtension.dllの標準ダイアログと同じダイアログのIDを使用していたためです。あなたの対話に異なったIDを与えなさい。これは非常に一般的な問題です。

3)ライセンスダイアログには、 "LicenseText"というIDを持つScrollableTextコントロールが必要です。 Wixは印刷時にこのコントロール名を正確に検索します。

<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="160" Sunken="yes" TabSkip="no">
    <Text SourceFile="License.rtf" />
</Control>

カスタムアクションを参照するPushButton

<Control Type="PushButton" Id="PrintButton" Width="57" Height="17" X="19" Y="244" Text="Print">
    <Publish Event="DoAction" Value="PrintEula">1</Publish>
</Control>

4)Id = "PrintEula"でCustomActionを次のように定義します。

<CustomAction Id="PrintEula" BinaryKey="WixUIWixca" DllEntry="PrintEula" Return="ignore" Execute="immediate" />

注:BinaryKeyはWix2.0と比較してWix3.0では異なり、正確に "WixUIWixca"でなければなりません(大文字と小文字を区別する)。

ユーザーがボタンを押すと、標準のプリンター選択ダイアログが表示され、そこから印刷することができます。

5
farfareast

「インストールする準備はできましたか?」を変更します。行われた選択の要約を提供するダイアログ(別名VerifyReadyDlg)

それはこのように見えます:
代替テキストhttp://i46.tinypic.com/s4th7t.jpg

Javascript CustomActionでこれを行います。


JavaScriptコード:

// http://msdn.Microsoft.com/en-us/library/aa372516(VS.85).aspx
var MsiViewModify = 
    {
        Refresh          : 0,
        Insert           : 1,
        Update           : 2,
        Assign           : 3,
        Replace          : 4,
        Merge            : 5,
        Delete           : 6,
        InsertTemporary  : 7,   // cannot permanently modify the MSI during install
        Validate         : 8,
        ValidateNew      : 9,
        ValidateField    : 10,
        ValidateDelete   : 11
    };


// http://msdn.Microsoft.com/en-us/library/sfw6660x(VS.85).aspx
var Buttons = 
    {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
    };

var Icons= 
    {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
    }

var MsgKind =
    {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
    };

// http://msdn.Microsoft.com/en-us/library/aa371254(VS.85).aspx
var MsiActionStatus = 
    {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
    };

function UpdateReadyDialog_CA(sitename)
{
    try 
    {
        // can retrieve properties from the install session like this:
        var selectedWebSiteId = Session.Property("MSI_PROPERTY_HERE");

        // can retrieve requested feature install state like this:
        var fInstallRequested   = Session.FeatureRequestState("F.FeatureName");

        var text1 = "This is line 1 of text in the VerifyReadyDlg";

        var text2 = "This is the second line of custom text";

        var controlView     = Session.Database.OpenView("SELECT * FROM Control");
        controlView.Execute();

        var rec             = Session.Installer.CreateRecord(12);
        rec.StringData(1)   = "VerifyReadyDlg";    // Dialog_
        rec.StringData(2)   = "CustomVerifyText1"; // Control - can be any name
        rec.StringData(3)   = "Text";              // Type
        rec.IntegerData(4)  = 25;                  // X
        rec.IntegerData(5)  = 60;                  // Y
        rec.IntegerData(6)  = 320;                 // Width
        rec.IntegerData(7)  = 85;                  // Height
        rec.IntegerData(8)  = 2;                   // Attributes
        rec.StringData(9)   = "";                  // Property
        rec.StringData(10)  = vText1;              // Text
        rec.StringData(11)  = "";                  // Control_Next
        rec.StringData(12)  = "";                  // Help
        controlView.Modify(MsiViewModify.InsertTemporary, rec);

        rec                 = Session.Installer.CreateRecord(12);
        rec.StringData(1)   = "VerifyReadyDlg";    // Dialog_
        rec.StringData(2)   = "CustomVerifyText2"; // Control - any unique name
        rec.StringData(3)   = "Text";              // Type
        rec.IntegerData(4)  = 25;                  // X
        rec.IntegerData(5)  = 160;                 // Y
        rec.IntegerData(6)  = 320;                 // Width
        rec.IntegerData(7)  = 65;                  // Height
        rec.IntegerData(8)  = 2;                   // Attributes
        rec.StringData(9)   = "";                  // Property
        rec.StringData(10)  = text2;               // Text
        rec.StringData(11)  = "";                  // Control_Next
        rec.StringData(12)  = "";                  // Help
        controlView.Modify(MsiViewModify.InsertTemporary, rec);

        controlView.Close();
    }
    catch (exc1)
    {
        Session.Property("CA_EXCEPTION") = exc1.message ;
        LogException("UpdatePropsWithSelectedWebSite", exc1);
        return MsiActionStatus.Abort;
    }
    return MsiActionStatus.Ok;
}


function LogException(loc, exc)
{
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "Exception {" + loc + "}: " + exc.number + " : " + exc.message;
    Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}

Javascript CAを宣言します。

<Fragment>
  <Binary Id="IisScript_CA" SourceFile="CustomActions.js" />

  <CustomAction Id="CA.UpdateReadyDialog"
              BinaryKey="IisScript_CA"
              JScriptCall="UpdateReadyDialog_CA"
              Execute="immediate"
              Return="check" />
</Fragment>

CAをボタンに取り付けます。この例では、CustomizeDlgからNextがクリックされたときにCAが起動されます。

<UI ...>
  <Publish Dialog="CustomizeDlg" Control="Next" Event="DoAction" 
           Value="CA.UpdateReadyDialog" Order="1"/>
</UI>

Related SO Question: 実行時にVerifyReadyDlgに表示されるテキストをどうやって設定できますか?

5
Cheeso

ORCAの代わりに InstEd を使用します。これはMSIテーブルを表示するのに適したツールです。また、Transform - > Compare To ...で2つのパッケージを比較することもできます。

さらに プラス版 追加の機能を追加したものもあります。しかし、無料版もOrcaの代わりになるでしょう。

4
user432758

X86/x64互換性を持つCOM相互運用機能用の.NETアセンブリの登録

注意このフラグメントは、REGASM Assembly.dll/codebaseと基本的に同じです。

このサンプルではいくつかのことが行われているので、ここにコードを示し、後で説明します。

  <Wix xmlns="http://schemas.Microsoft.com/wix/2006/wi">
  <?include $(sys.CURRENTDIR)\Config.wxi?>
  <?if $(var.Win64) ?>
  <?define CLSIDRoots = "CLSID;Wow6432Node\CLSID"?>
  <?else ?>
  <?define CLSIDRoots = "CLSID"?>
  <?endif?>
  <!-- ASCOM Driver Assembly with related COM registrations -->
  <Fragment>
    <DirectoryRef Id="INSTALLLOCATION" />
  </Fragment>
  <Fragment>
    <ComponentGroup Id="cgAscomDriver">
      <Component Id="cmpAscomDriver" Directory="INSTALLLOCATION" Guid="{0267031F-991D-4D88-A748-00EC6604171E}">
        <File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly"  />
        <RegistryKey Root="HKCR" Key="$(var.DriverId)"  Action="createAndRemoveOnUninstall">
          <RegistryValue Type="string" Value="$(var.DriverTypeName)"/>
          <RegistryKey Key="CLSID">
            <RegistryValue Type="string" Value="$(var.DriverGuid)" />
          </RegistryKey>
        </RegistryKey>
        <?foreach CLSID in $(var.CLSIDRoots) ?>
        <RegistryKey Root="HKCR" Key="$(var.CLSID)" Action="none">
          <RegistryKey Key="$(var.DriverGuid)" Action="createAndRemoveOnUninstall">
            <RegistryValue Type="string" Value="$(var.DriverTypeName)"/>
            <RegistryKey Key="InprocServer32">
              <RegistryValue Type="string" Value="mscoree.dll" />
              <RegistryValue Type="string" Name="ThreadingModel" Value="Both"/>
              <RegistryValue Type="string" Name="Class" Value="$(var.DriverTypeName)"/>
              <RegistryValue Type="string" Name="Assembly" Value="!(bind.assemblyFullname.filDriverAssembly)" />
              <RegistryValue Type="string" Name="RuntimeVersion" Value="v2.0.50727"/>
              <RegistryValue Type="string" Name="CodeBase" Value="file:///[#filDriverAssembly]" />
              <RegistryKey Key="!(bind.fileVersion.filDriverAssembly)" >
                <RegistryValue Type="string" Name="Class" Value="$(var.DriverTypeName)"/>
                <RegistryValue Type="string" Name="Assembly" Value="!(bind.assemblyFullname.filDriverAssembly)" />
                <RegistryValue Type="string" Name="RuntimeVersion" Value="v2.0.50727"/>
                <RegistryValue Type="string" Name="CodeBase" Value="file:///[#filDriverAssembly]" />
              </RegistryKey>
            </RegistryKey>
            <RegistryKey Key="ProgId" Action="createAndRemoveOnUninstall">
              <RegistryValue Type="string" Value="$(var.DriverId)" />
            </RegistryKey>
            <RegistryKey Key="Implemented Categories" Action="createAndRemoveOnUninstall" >
              <RegistryKey Key="{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Action="createAndRemoveOnUninstall" />
            </RegistryKey>
          </RegistryKey>
        </RegistryKey>
        <?endforeach?>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

ご参考までに、これは実際のところ ASCOM Telescope Driver 用です。

最初に、私は上からアドバイスを受けて、別々のファイルにいくつかのplatforma変数を作成しました、あなたはXMLを通して散在するそれらを見ることができます。

先頭に近いif-then-elseの部分は、x86とx64の互換性を扱います。私のアセンブリは 'Any CPU'をターゲットとしているので、x64システムでは、64ビットレジストリに1回、32ビットWow6432Node領域に1回ずつ登録する必要があります。 if-then-elseでこれを設定します。値は後でforeachループで使用されます。このように、私は一度だけレジストリキーをオーサリングする必要があります(DRY原則)。

File要素は、インストールおよび登録されている実際のアセンブリDLLを指定します。

<File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly"  />

革命的なことは何もありませんが、Assembly=".net"に注意してください - この属性だけでアセンブリがGACに入れられることになります。これは私が望んでいたことではありません。自分自身を指し示すためにAssemblyApplication属性を使用することは、単にWixがファイルをGACに入れるのを止める方法です。 Wixが.netアセンブリであることを認識したので、アセンブリのフルネームを取得するための!(bind.assemblyFullname.filDriverAssembly)など、XML内の特定のバインダー変数を使用できます。

4
Tim Long

DISABLEADVTSHORTCUTSプロパティを設定して、インストーラでアドバタイズされているすべてのショートカットが通常のショートカットになるようにします。キーパスとして使用するためにダミーのregキーを含める必要はありません。

<Property Id="DISABLEADVTSHORTCUTS" Value="1"/>

Windowsインストーラ4.0以上が 必須 だと思います。

3
Dave Andersen

こちら 大規模なWebプロジェクトで、デプロイされたファイルの数がMSI(またはマージモジュール)に組み込まれているファイルの数と一致することを確認する方法。私たちのメインアプリケーションに対してカスタムMSBuildタスクを(まだ開発中の)実行したところ、不足しているファイル、画像など、かなりの数のファイルが削除されました。

このアプローチ(WiXプロジェクトのAfterBuildターゲットにフックすることによってMSIのファイルテーブルを覗く)は、予想されるファイルの完全なリストにアクセスできる他のアプリケーションタイプにも有効です。

2
si618

インストールでアンインストールまたは再インストールが許可されず、ロールバックされないときに強制再インストールを実行する。

何らかの理由でアンインストールされないインストールを上書きするために使用されるVBスクリプトスクリプト。

Dim objShell
set objShell = wscript.createObject("wscript.Shell")

iReturn = objShell.Run("CMD /K MsiExec.exe /I ""C:\Users\TheUser\Documents\Visual Studio 2010\Projects\InstallationTarget\HelloInstaller\bin\Debug\HelloInstaller.msi"" REINSTALLMODE=vomus REINSTALL=ALL",,True)
2
Terrance

それは素晴らしい構造ですが、私の経験に基づいて、私はあなたがこれらの条件にどう対処するか疑問に思います:

A.あなたのインストールはすべて同じ目的地に着陸しているように見えます。ユーザーが一度に3つすべてのバージョンをインストールする必要がある場合、あなたのプロセスはこれを可能にするでしょう。トリガーしているすべての実行可能ファイルのどのバージョンを明確に伝えることができますか?

B. TESTやTRAININGに存在するがまだLIVEには存在しない新しいファイルをどのように処理しますか。

2
Blaine Wheeler

変数を設定するカスタムアクションを持つUIを作成します。UIはカスタムアクションで設定された変数に基づいて[次へ]ボタン(または同様のボタン)を無効または有効にします。

あなたが思っているほど簡単ではなく、どこにも文書化されていないので難しすぎません!

Wixと条件、プロパティ、カスタムアクションの相互作用

2
Daniel Powell

ProgressDlgが正しく表示されるように修正してください。

私は私のインストーラのフォントサイズを8から10に増やしました。これはフォントをより人間的な、高解像度のモニタで使えるスケールにするためです。私はこのXMLマジックでこれを行います。

<UI Id="MyCustomUI">
  <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="10" />
  <TextStyle Id="WixUI_Font_Big"    FaceName="Tahoma" Size="12" />
  <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="14" />
  <TextStyle Id="WixUI_Font_Title"  FaceName="Tahoma" Size="12" Bold="yes" />

  <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
</UI>

しかし、これはProgressDlgが正しく表示されなくなったことを意味します。これは、インストールの進行状況を表示するもので、最後にあります。 ActionTextは切り取られるので、gやjのような文字の子孫は表示されません。後処理JavascriptでProgressdialogのさまざまなコントロールのサイズと位置を調整してこれを修正します。 MSIを生成した後にこのスクリプトを実行します。

var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

// The text on the exit dialog is too close to the title.  This 
// step moves the text down from Y=70 to Y=90, about one line. 
sql = "UPDATE `Control` SET `Control`.`Y` = '90' " +
    "WHERE `Control`.`Dialog_`='ExitDialog' AND `Control`.`Control`='Description'";
view = database.OpenView(sql);
view.Execute();
view.Close();

// The progressbar is too close to the status text on the Progress dialog. 
// This step moves the progressbar down from Y=115 to Y=118, about 1/3 line. 
sql = "UPDATE `Control` SET `Control`.`Y` = '118' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ProgressBar'";
view = database.OpenView(sql);
view.Execute();
view.Close();

// The StatusLabel and ActionText controls are too short on the Progress dialog,
// which means the bottom of the text is cut off.  This step
// increases the height from 10 to 16.
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='StatusLabel'";
view = database.OpenView(sql);
view.Execute();
view.Close();
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ActionText'";
view = database.OpenView(sql);
view.Execute();
view.Close();

database.Commit();
1
Cheeso