This blog is used as a memory dump of random thoughts and interesting facts about different things in the world of IT. If anyone finds it useful, the author will be just happy! :-)

Thursday, February 24, 2011

Moving to dotNetInstaller: the odd Basic UI

In the previous post, I’ve outlined how to emulate the launch conditions behavior in dotNetInstaller. In that article I have also emphasized the importance of turning the UI into the Basic mode. It is necessary in order to avoid extra dialogs which require user interaction. If you followed the scenario I described, you might notice a strange behavior of the BasicUI mode: the message boxes disappear without any user participation. I thought it’s be a kind of a bug, but it was done on purpose. Take a look at this code (taken from dotNetInstaller sources):

int DniMessageBox::Show(const std::wstring& p_lpszText, UINT p_nType /*=MB_OK*/, UINT p_nDefaultResult /*=MB_OK*/, UINT p_nIDHelp /*=0*/)
{
int result = p_nDefaultResult;
switch(InstallUILevelSetting::Instance->GetUILevel())
{
// basic UI, dialogs appear and disappea
case InstallUILevelBasic:
{
g_hHook = SetWindowsHookEx(WH_CBT, CBTProc, NULL, GetCurrentThreadId());
CHECK_WIN32_BOOL(NULL != g_hHook, L"Error setting CBT hook");
result = AfxMessageBox(p_lpszText.c_str(), p_nType, p_nIDHelp);
CHECK_BOOL(0 != result, L"Not enough memory to display the message box.");
if (result == 0xFFFFFF) result = p_nDefaultResult;
}
break;

// silent, no UI
case InstallUILevelSilent:
result = p_nDefaultResult;
break;

// full UI
case InstallUILevelFull:
default:
result = AfxMessageBox(p_lpszText.c_str(), p_nType, p_nIDHelp);
break;
}

return result;
}

So, as you can see, in Basic mode is shows the message box, and after some time (if you didn’t catch the moment to press any button), it automatically emulates the pressing of default choice button. I was quite surprised when I understood it was designed to work like this – that’s because I’ve never seen such a UI behavior…

But, anyway, I suspect that a user would like to know why the installation terminated - a certain prerequisite is not installed. As long as the mentioned behavior is hard-coded, the only option is to create a custom build of dotNetInstaller. It’s obvious that the fix is trivial here – make the case for InstallUILevelBasic go the same branch as InstallUILevelFull, that is, just show the message box. Next step is to build the solution – see “Contributing to Source Code” chapter of dotNetInstaller.chm for instructions how to build.

Finally, install the custom build instead of the official one and make sure your setup project picks the changes up. That’s it!

As usual, I would appreciate any comments and notes!


4 comments:

  1. Thank you for the great articles on this bootstrapper. It comes in handy with the somewhat limited documentation on their site!

    Something I haven't been able to find information on is how to change the file attributes properly. For example, adding a Company attribute inserts a second company attribute on top of the one that is absorbed from the "dotNetInstaller.exe" template file.

    Do you have any tips how to do this task? (short of using a second utility to edit the file attributes after the setup file is produced)

    ReplyDelete
  2. Thanks for your comment, Anonymous!

    I haven't tried what you're asking about (it was just not required to), but I can see there's a topic in User Guide help file called "Attributes & Versions". It describes how to change the attribute values and add custom attributes.

    BTW, what do you add another Company attribute instead of changing the one which is already there?

    ReplyDelete
  3. Hi Yan, thanks for your reply.

    I apologize for the delay, I'm just getting back to working with the dotNetInstaller again (have a million things to do lately), so I looked into your feedback.

    The fileattributes collection within my configuration.xml file did not have any entries to begin with, so there was no Company attribute to edit - I had to add a new one. The configuration file was taken from the StandaloneSetup sample, and the dotNetInstaller.exe file that I'm pointing the installerLinker at is from this sample too.

    When I use the installerLinker, this is the format I use to run in cmd:

    installerLinker /Output:setup.exe /Icon:Icon.ico /Template:dotNetInstaller.exe /Splash:Splash.bmp /Configuration:configuration.xml /Banner:banner.bmp /Embed+ /Verbose+

    Maybe it's just me, but I'm not wholly understanding why the template reference points to dotNetInstaller.exe

    From the manual under the "Setup Executable" topic:
    "dotNetInstaller.exe is a bootstrapper, a lightweight driver for your setup process."

    I'm pretty sure it is this executable that the installerLinker gets the file attributes from and then combines them with what I've defined in the Installer Editor program.

    My solution for now is to use another piece of software to change the fileattributes after my setup.exe is built.

    Was hoping there exists another less-clunky method that I'm missing.

    Cheers,
    Greg

    ReplyDelete
  4. Hi Greg,

    To be honest, I've not looked under the hood that much to explain the technique behind the /template attribute, but your assumption sounds rather logical. I've not faced with the behavior you describe (with file attributes), probably because I'm using version 2.0? I know it is still in beta, but it works fine for me. Try to check this out - it might be the case that it was fixed in the later versions than the one you use.

    Good luck!

    ReplyDelete