Bootstrapper Application UI - How To move between pages

我怕爱的太早我们不能终老 提交于 2019-12-10 09:54:00

问题


I am writing a Bootstrapper Application and want to create the UI for it using the WixStandardBootstrapperApplication. I want the UI such that on the first page(Install page), I see the standard EULA and a checkbox which says I accept and a button to proceed on the next page (Options page) which should get enabled only after I select the checkbox. On the next page, I list some text and want to have another checkbox, which kind of again says I accept and a button to Install which gets enabled only after I select the checkbox.

<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>

The second page(Options page) is working according to what I need - Checkbox and Install button disabled, and it gets enabled only after selecting the checkbox. But on the first page(Install page) I am not able to make it work. The button is enabled even if the checkbox is not checked. I tried different options for the Checkbox and Button Name but I am unable to make it work. What can I do to make it work? Also if you have any link for any documentation for the different options then please share. I found the help file with Thmutil schema but it doesn't list the various options for Checkboxes or Buttons.

Any suggestions welcome. Feel free to ask if anything is unclear. Thanks for your help in advance.


回答1:


To do this you'll need to delve into the code for your bootstrapperapplication (WixStdBootstrapperApplication.cpp).

Luckily you're basing this off of the WixStdBootstrapperApplication which I've spend quite some time getting to know.

First thing you need to do is put the EulaAcceptCheckbox back onto the page with the actual Eula on it. When you're going to control the UI elements being enabled/disabled you need to do this from within the bootstrapper application's code. The BA owns the UI.

Now we need to change the behaviour of that EulaAcceptCheckbox so that it enables/disables the OptionsButton.

In the WndProc is where we handle all the messages generated by the user when they click on a button or scroll or do anything. Under WM_COMMAND we have a switch based on LOWORD(wParam) which is the ID of the control that raised the message.

Locate "WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX" and see that it calls pBA->OnClickAcceptCheckbox();

Here is the method

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

Looks super simple right? Here you just have to change WIXSTDBA_CONTROL_INSTALL_BUTTON to the WIXSTDBA_CONTROL_OPTIONS_BUTTON

We also need to set the Options button to default disabled. To do this we go into "OnChangeState" and look for the if for WIXSTDBA_PAGE_INSTALL

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);
    }
}

We need to update this block to be

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);
    }
}

Here we removed the elevated stuff since that goes on the install button and instead enable/disable the options button depending on whether it is defined in the theme and if the accept checkbox is checked or not.

Next you'll need to add a way to locate your new OptionsPage checkbox.

You should have an enum in your cpp file

enum WIXSTDBA_CONTROL

It should be ordered into controls on pages. Here you'll need to add a new entry for your new Options checkbox control, maybe WIXSTDBA_CONTROL_OPTIONS_CHECKBOX

Below this enum you'll have a 2-d array

static THEME_ASSIGN_CONTROL_ID vrgInitControls[] = 

You'll need to add a new entry here that is inserted at the same place you inserted into your enum. The inserted array item should look like this

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

Now we need a way to handle messages from this Control. Head back to WndProc and add a new case to the switch under WM_COMMAND it should be

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

Now add a OnClickOptionsCheckbox method to your bootstrapper application just like the OnClickAcceptCheckbox()

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

Finally, we need to add the llElevated stuff we removed from the OnChangeState WIXSTDBA_PAGE_INSTALL case to WIXSTDBA_PAGE_OPTIONS and also set the default state of the Install button

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);
    }
}

Will get changed to

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);
    }
}

There are a few things I would still change around with this implementation but I would highly suggest trying to walk through what the bootstrapper application does and how it works.

If you want to change the behaviour of the UI during your install you'll need to get familiar with the code here. You can add new pages, add controls, and set variables along with some other stuff.

If this seems like a lot of work (figuring all this out myself definitely was) consider whether or not you really need this type of behaviour over the default behaviour of one of the default wixstdba themes.



来源:https://stackoverflow.com/questions/36879242/bootstrapper-application-ui-how-to-move-between-pages

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!