65.9K
CodeProject 正在变化。 阅读更多。
Home

EchoInst:WDK Echo 驱动程序的 Wix 安装示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (3投票s)

2013 年 4 月 9 日

CPOL

7分钟阅读

viewsIcon

28428

downloadIcon

364

本文提供了一个使用 Wix 安装驱动程序的示例,包括延迟自定义操作的使用。

引言

文章 DevMSI:C++/MSI/Wix 延迟自定义操作 DLL 示例 描述了如何创建 C/C++ DLL 以支持 Wix 安装中的延迟自定义操作。本文在此基础上,为 Windows WDK 中的 echo 示例提供了一个功能性的 MSI 安装。它根据需要利用 DevMSI 来创建和删除非 PnP 设备 'root\echo',以及删除服务 'echo'。

WiX 文件和构建脚本可在此处 下载

背景 

要完整安装 Echo 驱动程序,需要完成以下几个步骤:

  • 将驱动程序和相关应用程序复制(卸载时删除)到安装目录。此任务通过 WiX 完成。
  • 在系统上执行驱动程序文件预安装。这实际上并不会设置驱动程序加载:它只是执行必要步骤,告知 Windows 新驱动程序,并将其放入适当的系统路径中,以便在检测到适当的驱动程序时能够发现。MSDN 文章 驱动程序安装框架 API (DIFxAPI) 解释了 Microsoft 为此任务提供的 API。在 Wix V3 中,Wix 框架可以使用此 API。
  • 对于安装,将非 PnP 设备 'root\echo' 添加到将使用 Echo 驱动程序的系统。对于卸载,删除所有名为 'root\echo' 的非 PnP 设备,并删除 echo 服务。对于这些任务,DevMSI DLL 将使用所需的功能扩展 Wix。

Wix V3 和 DIFxAPI

Wix 和 DIFxAPI 是一个比本文旨在解决的更广泛的主题。但是,Koby Kahane 的精彩博文 "使用 DIFxApp 和 WiX v3 MSI 安装过滤器驱动程序" 是一个很好的起点,如果读者想进一步了解此处提供的 .wxs 脚本中正在进行的操作。

DevMSI

如上所述,配套文章  DevMSI:C++/MSI/Wix 延迟自定义操作 DLL 示例 描述了用于执行所需设置任务的 C++ DLL 扩展。简而言之,DevMSI 执行 WDK devcon.exe 示例的一个有限子集:此子集将根据请求添加或删除设备和相关服务。

使用 WIX 构建 MSI 所需的步骤

部署 MSI 需要按顺序完成以下步骤。提供了示例构建脚本供下载,但此处仅列出没有错误检查的基本命令以供参考。

  • 构建 WDK echo 驱动程序和示例应用程序
  • pushd %PROJECT_ROOT%\general\echo 
    build -ceZ 
    popd 
  • 将所需的构建输出复制到工作目录
  • set COPY_SOURCE="%PROJECT_ROOT%"\general\echo\kmdf\AutoSync\obj%_BuildType%_%DDK_TARGET_OS%_%_BUILDARCH%\%_BUILDARCH%
    set COPY_TARGET="."
    copy %COPY_SOURCE%\echo.inf %COPY_TARGET%\.
    copy %COPY_SOURCE%\echo.sys %COPY_TARGET%\.
    set COPY_SOURCE="%PROJECT_ROOT%"\general\echo\exe\obj%_BuildType%_%DDK_TARGET_OS%_%_BUILDARCH%\%_BUILDARCH%
    copy %COPY_SOURCE%\echoapp.exe %COPY_TARGET%\.
    set COPY_SOURCE="%PROJECT_ROOT%"\..\redist\wdf\%_BUILDARCH%
    copy %COPY_SOURCE%\WdfCoInstaller01009.dll %COPY_TARGET%\.
  • 签名驱动程序和测试可执行文件 - 本示例使用 signtool 和 Verisign
  • Signtool sign /v /ac "c:\verisign\VeriSign Class 3 Public Primary Certification Authority - 
       G5.cer" /i Verisign /t http://timestamp.verisign.com/scripts/timestamp.dll [filename] 
  • 从 INF 文件创建 .cat 文件
  • inf2cat /driver:.\ /os:7_X64 
    • 签名 .cat 文件 - 请参阅上面的示例用法
    • 在 .wxs 文件上运行 WiX 工具 candle
    • %WIX%\bin\candle -ext %WIX%\bin\WixUIExtension.dll -ext %WIX%\bin\WixUtilExtension.dll 
                    -ext %WIX%\bin\WixDifxAppExtension.dll *.wxs -arch x64  
    • 在 .wixobj 文件上运行 WiX 工具 light
    • %WIX%\bin\light -ext %WIX%\bin\WixUIExtension.dll -ext %WIX%\bin\WixUtilExtension.dll -ext 
          %WIX%\bin\WixDifxAppExtension.dll *.wixobj %WIX%\bin\difxapp_x64.wixlib -o echo.msi

以上所有内容都已脚本化到一组 .cmd 文件中,可供下载,使用 "build.cmd echo" 命令可以启动这些步骤序列。

推迟讨论自定义操作

此安装程序使用延迟自定义操作来利用 DevMSI 进行非 PnP 设备的安装和卸载。由于许多类型的驱动程序(PnP 设备驱动程序、过滤器驱动程序)在安装(或卸载)时不需要延迟自定义操作,因此本文将首先检查 echo.wxs 文件,重点关注非自定义操作部分。

检查 Echo.wxs

WiX 文件使用 XML 编写,并且可以通过少量搜索找到许多示例。此文件以与这些示例相似的样板开头:

<?xml version='1.0' encoding='Windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'
     xmlns:difx='http://schemas.microsoft.com/wix/DifxAppExtension'> 

请注意为 DIFxAPP 提供的额外命名空间,因为许多非驱动程序将不包含此扩展。接下来是一些稍加定制的样板,用于定义产品。

<Product Name='EchoInstaller' 
           Id='PUT-GUID-HERE' 
           Language="'1033'" Codepage='1252' Version='1.10' Manufacturer='CodeProject' 
           UpgradeCode='PUT-GUID-HERE'>
    <Package Id='*' Keywords='echo' Description='WDK Echo Sample Driver Installer'
             Comments='Installs WDK Echo Sample Drivers' Manufacturer='CodeProject' InstallerVersion='200'
             Languages='1033' Compressed='yes' SummaryCodepage='1252' />
    <Media Id='1' Cabinet='Installer.cab' EmbedCab='yes' DiskPrompt='WDK Echo Sample Driver Media' />
    <Property Id='DiskPrompt' Value='WDK Echo Sample Driver Install Media' /> 

这里描述的许多字段都可以,也应该针对特定的驱动程序安装进行自定义。接下来,文件描述了安装目录目标路径:

<Directory Id='TARGETDIR' Name='SourceDir'>
      <Directory Id='ProgramFiles64Folder'>
        <Directory Id='INSTALLDIR' Name='WDK Samples'> 

此示例期望在 Program Files 文件夹下有一个名为 "WDK Samples" 的基本安装目录(仅限 64 位,因为此示例需要 64 位驱动程序)。在此基本文件夹中,安装程序将放置 echoapp.exe 测试应用程序,并为驱动程序文件创建一个新文件夹:

<Component Id='SampleApp' Guid='PUT-GUID-HERE'>
<File Id='echoappEXE' Name='echoapp.exe' DiskId='1' Source='Driver\echoapp.exe' KeyPath='yes' />
</Component>
<Directory Id='DriverDir' Name='Drivers'> 

将 .INF、.CAT 和 .SYS 文件放在驱动程序文件夹中,KMDF 共同安装程序也放在那里。请注意,额外的 XML 告诉 DIFxAPI 这些是需要预安装的驱动程序文件:

<Component Id='EchoDriver' Guid='PUT-GUID-HERE'>
          <File Id='echoSYS' Name='echo.sys' DiskId='1' Source='Driver\echo.sys' KeyPath='yes' />
          <File Id='echoINF' Name='echo.inf' DiskId='1' Source='Driver\echo.inf' />
          <File Id='echoCAT' Name='KmdfSamples.cat' DiskId='1' Source='Driver\KmdfSamples.cat' />
          <File Id='wdfcoinstaller01009DLL' Name='wdfcoinstaller01009.dll' DiskId='1' Source='Driver\wdfcoinstaller01009.dll' />
          <difx:Driver AddRemovePrograms="no" Legacy="no" PlugAndPlayPrompt="no" Sequence='1' />
        </Component>
      </Directory>
    </Directory>
  </Directory>
</Directory> 

接下来,文件声明驱动程序和示例应用程序应在 "complete" 安装上安装,并为安装程序使用标准的简单 UI。

<Feature Id='Complete' Level='1'>
  <ComponentRef Id='SampleApp' />
  <ComponentRef Id='EchoDriver' />
</Feature>
<UIRef Id="WixUI_Minimal" /> 

暂时跳过与自定义操作相关的项目,.WXS 文件中只剩下关闭一些标签。

</Product>
</Wix> 

就是这样!

需要:延迟执行自定义操作

将非 PnP 设备添加到系统需要管理员权限。MSDN 文章 延迟执行自定义操作 包含以下重要说明:

Note that deferred custom actions, including rollback custom actions and commit custom actions, 
   are the only types of actions that can run outside the users security context. 

由于 DevMSI 需要额外的权限,这意味着所有 DevMSI 任务都必须使用延迟执行自定义操作。

检查 DevMSI.wxs

将 DevMSI 调用封装在延迟自定义操作中的代码包含在 DevMSI.wxs 中。此文件不包含任何项目设置和定义,而是仅定义所需的功能。在 WiX 术语中,这是一个片段:

 <?xml version='1.0' encoding='Windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
  <Fragment> 

需要定义一个二进制项,它表示 DLL 的 WiX 别名("DevMsi")以及二进制文件在 WiX 计算机上的路径。MSI 将在设置过程中提取并按需使用此二进制文件。

<Binary Id="DevMsi" SourceFile="..\DevMsi\x64\Release\DevMsi.dll" /> 

接下来定义了三个延迟自定义操作,它们可从 DevMsi 二进制文件获得:

<CustomAction Id="AddDevice"
              BinaryKey="DevMsi"
              DllEntry="CreateDevnode"
              Execute="deferred"
              Impersonate="no"
              />

<CustomAction Id="DelDevice"
              Return="ignore"
              BinaryKey="DevMsi"
              DllEntry="RemoveDevnode"
              Execute="deferred"
              Impersonate="no"
              />
    
<CustomAction Id="DelService"
              Return="ignore"
              BinaryKey="DevMsi"
              DllEntry="RemoveService"
              Execute="deferred"
              Impersonate="no"
              /> 

对于其中的每一个,Id 为自定义操作命名,以便在其他地方使用,BinaryKey 是上面指定的别名,DllEntry 是 DLL 的 C 入口点。Execute="deferred" 关键字使其成为延迟自定义操作,而 Impersonate="no" 允许自定义操作以管理员权限运行。

需要:(普通)自定义操作

如上所述,定义延迟执行自定义操作相对简单。然而,如何将参数传递给延迟自定义操作并不十分清楚。根据 MSDN 文章 获取延迟执行自定义操作的上下文信息,在延迟自定义操作期间可以检索的属性非常少(三个)。唯一真正可用于将参数传递给操作的属性是 CustomActionData 属性。

设置延迟自定义操作的 CustomActionData 属性的方法是,令人惊讶地,通过另一个自定义操作。这个操作不需要被延迟,因为它不需要特权安全上下文,实际上可能不应该被延迟,以便它能够访问其他属性。

因此,调用带参数的延迟自定义操作的步骤如下:

  • 定义一个自定义操作,该操作将为延迟执行自定义操作设置 CustomActionData 属性。
  • 定义一个延迟执行自定义操作。
  • 在安装或卸载序列中,根据需要安排自定义操作和延迟执行自定义操作的执行。

此 wxs 示例使用简单的命名约定,以帮助读者理解哪些自定义操作与其对应的延迟自定义操作相匹配。如果 Foo 是延迟自定义操作的 ID,那么 Foo.SetParam 是设置 Foo 的 CustomActionData 的相应自定义操作的 ID。

重新审视 Echo.wxs

回顾 echo.wxs 脚本的后半部分,可以看到自定义操作:

<CustomAction Id="AddDevice.SetParam"
          Return="check"
          Property="AddDevice"
          Value='"[DriverDir]echo.inf" root\Echo'
          />
<CustomAction Id="DelDevice.SetParam"
          Return="check"
          Property="DelDevice"
          Value="root\Echo"
          />
<CustomAction Id="DelService.SetParam"
          Return="check"
          Property="DelService"
          Value="Echo"
          /> 

如上所述,AddDevice.SetParamAddDevice 的 Custom Action Data 设置为值 - 在本例中,是展开的字符串 '"[DriverDir]echo.inf" root\Echo'。再次回顾 .wxs 文件前面的目录路径,可以找到 [DriverDir] 属性:

<Directory Id='DriverDir' Name='Drivers'> 

因此,当执行 CustomAction 时,DriverDir 将被展开为驱动程序文件的安装目录,并且 AddDeviceCustomActionData 将被设置为适当的字符串。当执行延迟自定义操作时,DLL 将能够提取并使用此字符串作为输入参数。

类似地,上面列出的其他两个自定义操作(DelDevice.SetParamDelService.SetParam)为其关联的延迟自定义操作设置字符串参数。一旦定义了所有延迟自定义操作和自定义操作,下一步就是声明何时执行这些操作。

<InstallExecuteSequence>
  <RemoveExistingProducts After="InstallInitialize" />
  <Custom Action ="AddDevice.SetParam" After="InstallFiles">NOT Installed</Custom>
  <Custom Action='AddDevice' After="AddDevice.SetParam">NOT Installed</Custom>
  
  <Custom Action ="DelDevice.SetParam" After="AddDevice">Installed</Custom>
  <Custom Action='DelDevice' After="DelDevice.SetParam">Installed</Custom>
  <Custom Action ="DelService.SetParam" After="DelDevice">Installed</Custom>
  <Custom Action='DelService' After="DelService.SetParam">Installed</Custom>
</InstallExecuteSequence>

请注意,延迟自定义操作设置为在其设置 CustomActionData 参数的自定义操作之后运行。NOT Installed 文本声明(延迟或普通)自定义操作在安装期间运行,而 Installed 文本声明该自定义操作仅在产品已安装时运行(假设是卸载)。本文没有研究许多其他可能性和组合:WiX 手册和教程可以提供更多信息。

结论

编写 WiX 安装程序实际上比解释如何编写更容易。作者希望未来的用户可以利用这里的信息来为自己带来优势。

历史

  • 2013-04-09:初始版本。
© . All rights reserved.