Bootstrapper 应用程序 UI - 如何在页面之间移动

Bootstrapper Application UI - How To move between pages

我正在编写一个 Bootstrapper 应用程序,并希望使用 WixStandardBootstrapperApplication 为其创建 UI。我想要 UI 这样在第一页(安装页面)上,我看到标准 EULA 和一个表示我接受的复选框以及一个按钮以在下一页(选项页面)上继续,只有在我 select 复选框。在下一页上,我列出了一些文本并希望有另一个复选框,这再次表示我接受和一个安装按钮,只有在我 select 复选框后才会启用。

<Page Name="Install">
  <Text X="154" Y="12" Width="-65" Height="21" DisablePrefix="yes">#(loc.Title)</Text>
  <Image X="120" Y="20" Width="54" Height="325" ImageFile="logo.png"/>
  <Richedit Name="EulaRichedit" X="154" Y="60" Width="-21" Height="-76" TabStop="yes" FontId="0" HexStyle="0x800000" />
  <Checkbox Name="OptionsCheckbox" X="-11" Y="-41" Width="246" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">I accept.</Checkbox>
  <Button Name="WelcomeCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
  <Button Name="OptionsButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" Text="Proceed" HideWhenDisabled="yes">Next</Button>
</Page>
<Page Name="Options">
  <Text X="185" Y="11" Width="-11" Height="32" FontId="1">#(loc.OptionsHeader)</Text>
  <Image X="0" Y="0" Width="177" Height="325" ImageFile="logoside.png"/>
  <Text X="180" Y="61" Width="-11" Height="17" FontId="3">Some text.</Text>
  <Checkbox Name="EulaAcceptCheckbox" X="180" Y="251" Width="246" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.OptionsButton)</Checkbox>
  <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" Text="Proceed">#(loc.InstallInstallButton)</Button>
  <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
</Page>

第二页(选项页面)正在根据我的需要工作 - 复选框和安装按钮已禁用,只有在 select 选中复选框后才会启用。但是在第一页(安装页)我无法让它工作。即使未选中该复选框,该按钮也会启用。我为复选框和按钮名称尝试了不同的选项,但我无法使其工作。我该怎么做才能让它发挥作用?此外,如果您对不同选项的任何文档有任何 link,请分享。我找到了带有 Thmutil 架构的帮助文件,但它没有列出复选框或按钮的各种选项。

欢迎提出任何建议。如果有任何不清楚的地方,请随时询问。提前感谢您的帮助。

为此,您需要深入研究引导程序应用程序 (WixStdBootstrapperApplication.cpp) 的代码。

幸运的是,您是基于我花了很长时间才了解的 WixStdBootstrapperApplication。

您需要做的第一件事是将 EulaAcceptCheckbox 放回带有实际 Eula 的页面上。当您要控制 UI 元素成为 enabled/disabled 时,您需要从引导程序应用程序的代码中执行此操作。广管局拥有 UI.

现在我们需要更改 EulaAcceptCheckbox 的行为,使其 enables/disables OptionsButton。

在 WndProc 中,我们处理用户单击按钮、滚动或执行任何操作时生成的所有消息。在 WM_COMMAND 下,我们有一个基于 LOWORD(wParam) 的开关,它是引发消息的控件的 ID。

找到 "WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX" 并看到它调用了 pBA->OnClickAcceptCheckbox();

方法在这里

void OnClickAcceptCheckbox()
{
    BOOL fAcceptedLicense = ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX);
    ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAcceptedLicense);
}

看起来超级简单吧?在这里,您只需将 WIXSTDBA_CONTROL_INSTALL_BUTTON 更改为 WIXSTDBA_CONTROL_OPTIONS_BUTTON

我们还需要将选项按钮设置为默认禁用。为此,我们进入 "OnChangeState" 并寻找 WIXSTDBA_PAGE_INSTALL

的 if
if (m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL] == dwNewPageId) // on the "Install" page, ensure the install button is enabled/disabled correctly.
{
    LONGLONG llElevated = 0;
    if (m_Bundle.fPerMachine)
    {
        BalGetNumericVariable(WIXBUNDLE_VARIABLE_ELEVATED, &llElevated);
    }
    ThemeControlElevates(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, (m_Bundle.fPerMachine && !llElevated));

    // If the EULA control exists, show it only if a license URL is provided as well.
    if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK))
    {
        BOOL fEulaLink = (m_sczLicenseUrl && *m_sczLicenseUrl);
        ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK, fEulaLink);
        ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX, fEulaLink);
    }

    BOOL fAcceptedLicense = !ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || !ThemeControlEnabled(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX);
    ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAcceptedLicense);

    // If there is an "Options" page, the "Options" button exists, and it hasn't been suppressed, then enable the button.
    BOOL fOptionsEnabled = m_rgdwPageIds[WIXSTDBA_PAGE_OPTIONS] && ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_BUTTON) && !m_fSuppressOptionsUI;
    ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_BUTTON, fOptionsEnabled);

    // Show/Hide the version label if it exists.
    if (m_rgdwPageIds[WIXSTDBA_PAGE_OPTIONS] && ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_VERSION_LABEL) && !m_fShowVersion)
    {
        ThemeShowControl(m_pTheme, WIXSTDBA_CONTROL_VERSION_LABEL, SW_HIDE);
    }
}

我们需要将此块更新为

if (m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL] == dwNewPageId) // on the "Install" page, ensure the install button is enabled/disabled correctly.
{                    
    // If the EULA control exists, show it only if a license URL is provided as well.
    if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK))
    {
        BOOL fEulaLink = (m_sczLicenseUrl && *m_sczLicenseUrl);
        ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK, fEulaLink);
        ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX, fEulaLink);
    }

    BOOL fAcceptedLicense = !ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || !ThemeControlEnabled(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX);

    // If there is an "Options" page, the "Options" button exists, and it hasn't been suppressed, then enable the button.
    BOOL fOptionsEnabled = m_rgdwPageIds[WIXSTDBA_PAGE_OPTIONS] && ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_BUTTON) && !m_fSuppressOptionsUI;
    ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_BUTTON, fOptionsEnabled & fAcceptedLicense);

    // Show/Hide the version label if it exists.
    if (m_rgdwPageIds[WIXSTDBA_PAGE_OPTIONS] && ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_VERSION_LABEL) && !m_fShowVersion)
    {
        ThemeShowControl(m_pTheme, WIXSTDBA_CONTROL_VERSION_LABEL, SW_HIDE);
    }
}

这里我们删除了提升的东西,因为它出现在安装按钮上,取而代之的是 enable/disable 选项按钮,这取决于它是否在主题中定义以及是否选中了接受复选框。

接下来您需要添加一种方法来定位新的 OptionsPage 复选框。

你的 cpp 文件中应该有一个枚举

enum WIXSTDBA_CONTROL

它应该被排序到页面上的控件中。在这里您需要为新的选项复选框控件添加一个新条目,可能 WIXSTDBA_CONTROL_OPTIONS_CHECKBOX

在此枚举下方,您将有一个二维数组

static THEME_ASSIGN_CONTROL_ID vrgInitControls[] = 

您需要在此处添加一个新条目,该条目插入到您插入枚举 的相同位置。插入的数组项应该是这样的

{ WIXSTDBA_CONTROL_OPTIONS_CEHCKBOX, L"OptionsCheckbox" },  //The string should match the Name of the checkbox in the theme xml.

现在我们需要一种方法来处理来自该控件的消息。返回 WndProc 并在 WM_COMMAND 下的开关中添加一个新案例,它应该是

case WIXSTDBA_CONTROL_OPTIONS_CHECKBOX:
    pBA->OnClickOptionsCheckbox();
    return 0;

现在将 OnClickOptionsCheckbox 方法添加到您的引导程序应用程序,就像 OnClickAcceptCheckbox()

void OnClickOptionsCheckbox()
{
    BOOL fAccepted = ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_CHECKBOX);
    ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAccepted);
}

最后,我们需要将我们从 OnChangeState WIXSTDBA_PAGE_INSTALL 案例中删除的 llElevated 内容添加到 WIXSTDBA_PAGE_OPTIONS 并设置安装按钮的默认状态

else if (m_rgdwPageIds[WIXSTDBA_PAGE_OPTIONS] == dwNewPageId)
{
    HRESULT hr = BalGetStringVariable(WIXSTDBA_VARIABLE_INSTALL_FOLDER, &sczUnformattedText);
    if (SUCCEEDED(hr))
    {
        // If the wix developer is showing a hidden variable in the UI, then obviously they don't care about keeping it safe
        // so don't go down the rabbit hole of making sure that this is securely freed.
        BalFormatString(sczUnformattedText, &sczText);
        ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_FOLDER_EDITBOX, sczText);
    }
}

将更改为

else if (m_rgdwPageIds[WIXSTDBA_PAGE_OPTIONS] == dwNewPageId)
{
    LONGLONG llElevated = 0;
    if (m_Bundle.fPerMachine)
    {
        BalGetNumericVariable(WIXBUNDLE_VARIABLE_ELEVATED, &llElevated);
    }
    ThemeControlElevates(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, (m_Bundle.fPerMachine && !llElevated));       

    BOOL fAccepted = !ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_CHECKBOX) || !ThemeControlEnabled(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_CHECKBOX) || ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_OPTIONS_CHECKBOX);
    ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAccepted);

    HRESULT hr = BalGetStringVariable(WIXSTDBA_VARIABLE_INSTALL_FOLDER, &sczUnformattedText);
    if (SUCCEEDED(hr))
    {
        // If the wix developer is showing a hidden variable in the UI, then obviously they don't care about keeping it safe
        // so don't go down the rabbit hole of making sure that this is securely freed.
        BalFormatString(sczUnformattedText, &sczText);
        ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_FOLDER_EDITBOX, sczText);
    }
}

对于此实现,我仍会更改一些内容,但我强烈建议您尝试了解引导程序应用程序的功能及其工作原理。

如果您想在安装过程中更改 UI 的行为,您需要熟悉此处的代码。您可以添加新页面、添加控件并设置变量以及其他一些内容。

如果这看起来工作量很大(我自己肯定会弄清楚这一切)请考虑您是否真的需要这种行为而不是其中一种行为的默认行为默认的 wixstdba 主题。