Visual Studio Smart Device CAB projects are extremely helpful in many ways for building a cab installer, even thought they have some pending issues, like a more natural MSBUILD integration, they allow us to have a cleaner and dynamic definition of our mobile app installation based on our source projects instead of relying just in binary and .inf files.
Sometimes we need to perform some custom actions before and after the installation or uninstallation. Typically we can need to check for pre requisites or show a Terms & Conditions/EULA before the installation and continue only if the user accepts it or, as another example, we can need to remove temporary files and registry entries after uninstallation.
In this post I want to show you a very simple way to implement a Setup.dll which shows a Terms & Conditions dialog which requires the explicit user acceptance to continue the installation.
What we need to start?
We'll use Visual Studio 2008 but this procedure also works with VS2005. You'll need Visual C++ and Smart Devices support installed.
I recommend you to take a look at this article in MSDN regarding Setup.dll files for better context.
Choose any of your mobile applications (or create a new empty one) and create a new Smart Device Cab project for it, as I describe in this post. Once you got it, we're ready to start.
I'll use a port of SplashScreenSample for VS2008. For instance, my solution explorer looks like this:
Creating a new Setup.dll
First thing to do is to create a new Visual C++ Smart Device DLL project. Right click on the solution and select "Add" - "New Project".
The "Add New Project" dialog will pop up. Please select Visual C++ / Smart Device in "Project types" and use the "Win32 Smart Device Project" template.
I'll call it "EULASetup". Once you've entered the name just press "OK".
Nice... and now it's wizard time. Let's follow the "Win32 Smart Device Project Wizard"
Select the platform corresponding to your project. In this particular sample I'm targeting Windows Mobile 6 Standard:
As we want to implement a very simple DLL, just select "DLL" as Application Type and don't check anything else ("Precompiled headers" cannot be modified so let them checked).
Once we press "Finish" the wizard will create a new native C++ project in our Solution. The new project should look like this:
Showing the EULA dialog at installation begin
If it's not already open, please open EULASetup.cpp by double clicking on it. This class currently contains the DLLMain entry point for the library. We actually don't need this function in our setup.dll so this function can be removed.
What we need is to implement a function to be called when the user tries to install the cab. This function is Install_Init. In this function we'll show the terms & conditions for our application installation and according with the user response we can continue the installation or cancel it.
Our code needs to include "ce_setup.h" to get the required knowledge of Install_Init signature types, in this sample codeINSTALL_INIT, an enumeration which gives us the two possible result values: codeINSTALL_INIT_CONTINUE or codeINSTALL_INIT_CANCEL.
For simplicity, we can put the text in a string directly hardcoded within the source. I'm calling it "Message". Install_Init will show the message using the MessageBox API, and handling a "Yes" response continuing with the installation or a negative response canceling it.
It's important to remark that Install_Init may be called more than once, with different values for the installation directory; for example when the current directory doesn't have enough room. So we need to handle the fFirstCall parameter value to only show the dialog the first time our function is called.
How looks our code? please replace the entire content of EULASetup.cpp with the following:
#include "stdafx.h"
#include "ce_setup.h"
// This is a variable containing the text to be displayed
// in the Terms & Conditions dialog
TCHAR Message[] = _T("TERMS & CONDITIONS\r\n ")
_T("Selecting YES you're accepting our terms & conditions.\r\n")
_T("This is just a sample application.\r\n")
_T("From http://www.mobilepractices.com\r\n")
_T("You can replace this text with your own.\r\n")
_T("We're using a setup.dll to show this dialog.\r\n")
_T("Extra line to force vertical scrollbar.\r\n")
_T("Extra line to force vertical scrollbar.\r\n")
_T("Extra line to force vertical scrollbar.\r\n")
_T("Extra line to force vertical scrollbar.\r\n")
_T("Extra line to force vertical scrollbar.\r\n")
_T("Extra line to force vertical scrollbar.\r\n")
_T("Last line.\r\n")
;
// This function will be called when the user
// tries to install the cab. According to its return
// value the installation continues or is cancelled.
// As this could be called more than once
// (i.e. if there is not enough space on the target)
// we should take care about fFirstCall parameter
// to show the dialog only once.
codeINSTALL_INIT Install_Init( HWND hwndParent,
BOOL fFirstCall,
BOOL fPreviouslyInstalled,
LPCTSTR pszInstallDir )
{
if (!fFirstCall
::MessageBoxW(0, Message,
_T("SplashScreenSample")
, MB_YESNO) == IDYES)
return codeINSTALL_INIT_CONTINUE;
else
return codeINSTALL_INIT_CANCEL;
}
Exporting Install_Init function using a .DEF file
As our Install_Init function should be visibly externally to allow WCELOAD.EXE to call it during the .cab file processing; it means that we need to export it, and in this sample we'll use a .def file for doing it.
Please, press right click on EULASetup (the project) and select Add - New Item...
Please select "Module-Definition File (.def)" and enter "EULASetup" as its name. Press "Add".
A new "EULASetup.dll" is included in your project. If it's not already open in the editor, please open it and replace the body with the following:
LIBRARY "EULASetup"
EXPORTS
Install_Init @1
In this .def file we're just exporting Install_Init. Save the changes and build it. No errors should be found.
Adding the Setup.dll to our Smart Device CAB Project
Finally, we need to add "EULASetup.dll" as the setup.dll for our Smart Device CAB Project. This is really straightforward. Right click on the Installer project and "Add - Project Output..."
What we're doing is adding the output of build EULASetup to the installer. In fact, we're adding EULASetup.dll into the cab installer. The way to do it is selecting EULASetup as the project and "Primary Output" as what we want to include. Press "OK".
Now we have in our installer project the Primary Output from EULASetup.
The final step is to select it as the Setup.dll for our installer. Just select the Installer project by clicking on it
In the Properties pane for "CE Setup DLL" select (Browse...)
The Primary Output of a project is placed by default into the "Application Folder" of the CAB File System. So, in the following dialog please select "Application Folder" and press "OK" to open that folder
In the Application Folder select "Primary Output from EULASetup (Active)" and press "OK" again.
And... that's it! We've included EULASetup as the Setup DLL for our installer.
We're ready to rebuild the project and generate the .CAB File. Now when we try to install SplashSampleInstaller.CAB, we'll first get the following dialog:
If the user selects "No", the installation will be aborted. It will only continue if the user selects "Yes". I know the text could be improved a lot, and you even can use a more elaborated dialog, but... that's your homework!
Hope you like this walkthrough, and most important, it helps you. If you want to see the source code, just download it from the following link: