SETUP.DLL for Windows Mobile cab files

Question: I have a Windows Mobile 6 professional app with a targeted framework as .NET CF 3.5. I created its SmartDeviceCab file. When I install it on device not having CF 3.5 it fails to run. I know that I must have NET CF 3.5 on the device where I want to run my app. How can I add a “smart” setup code to my cab setup? In my Visual Studio C#, VB.NET, C++ and Smart Devices support is installed. We often need to perform some custom actions before and after the installation or uninstallation on mobile phones, for example we need to check the OS we run our app on, or remove temporary files and registry entries after uninstallation. The best option is to create our own SETUP.DLL installation modul by using Visual C++. I assume that you are familiar with Microsoft Visual Studio and know how to create a smart device CAB Project. The CAB file is the common setup format for Windows Mobile devices. These files are processed by wceloader.exe. One side-effect is often unknown. It can only install one .cab file at a time. That means we cannot have nested .cab files, so we must “embed” the setup.dll modul, ergo you must add a SETUP project to your solution. The one and only CAB file must include the compiled SETUP.DLL as well. Search the net and look for good tutorials about how to add a SETUP.DLL module to CAB file. At the Microsoft’s MSDN site you’ll find a well written guide: optional Setup.dll file for nstallation How to add a NETCF version check has been discussed here: Windows Mobile .NET version detection at installation Now you can write your code. Skeleton example is here:
// Setup.h
#ifdef SETUP_EXPORTS
#define SETUP_API __declspec(dllexport)
#else
#define SETUP_API __declspec(dllimport)
#endif

// This class is exported from the Setup.dll
class SETUP_API CSetup {
public:
    CSetup(void);
    // TODO: add your methods here.
};

bool IsMyMethod(HWND  hwndParent);
Setup.cpp file:
// Setup.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "ce_setup.h"
#include "Setup.h"

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
// ----------------------------------------------------------
// Variables, constants...

TCHAR ErrorMessageTitle[] = _T("Setup Notice");

TCHAR ErrorMessageNet[] =  _T("My error message.\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.
//// To continue installation, return codeINSTALL_INIT_CONTINUE
// If you want to cancel installation,
// return codeINSTALL_INIT_CANCEL
codeINSTALL_INIT Install_Init(HWND hwndParent, BOOL  fFirstCall, BOOL fPreviouslyInstalled, LPCTSTR pszInstallDir )
{
    if( fFirstCall && ::IsMyMethod(hwndParent) == false ){
            ::MessageBox(hwndParent, ErrorMessageNet, ErrorMessageTitle, MB_OK);
            return codeINSTALL_INIT_CANCEL;
    }

    return codeINSTALL_INIT_CONTINUE;
}

// ----------------------------------------------------------
// To exit the installation DLL normally,
// return codeINSTALL_EXIT_DONE
// To unistall the application after the function exits,
// return codeINSTALL_EXIT_UNINSTALL
codeINSTALL_EXIT Install_Exit(
                                HWND    hwndParent,
                                LPCTSTR pszInstallDir,
                                WORD    cFailedDirs,
                                WORD    cFailedFiles,
                                WORD    cFailedRegKeys,
                                WORD    cFailedRegVals,
                                WORD    cFailedShortcuts
                            )
{
    return codeINSTALL_EXIT_DONE;
}

// ----------------------------------------------------------
// To continue uninstallation, return codeUNINSTALL_INIT_CONTINUE
// If you want to cancel installation,
// return codeUNINSTALL_INIT_CANCEL
codeUNINSTALL_INIT Uninstall_Init(HWND hwndParent, LPCTSTR pszInstallDir)
{
    return codeUNINSTALL_INIT_CONTINUE;
}

// ----------------------------------------------------------
codeUNINSTALL_EXIT Uninstall_Exit(HWND    hwndParent)
{
    return codeUNINSTALL_EXIT_DONE;
}

// ----------------------------------------------------------
// This is the constructor of a class that has been exported.
// see Setup.h for the class definition
CSetup::CSetup()
{
    return;
}

// ----------------------------------------------------------
// Your own system checking or settings...
bool IsMyMethod(HWND  hwndParent)
{
    // Do system check here
    // return true or false
    return true;
}
Note that at Windows Marketplace you don’t need to take care of the required .NET CF versions. Microsoft did a great job there! We have great experience with them.