Silently install multiple CABs on Windows Mobile

- How to modify MulticabInstall SDK Sample

- Notes about Security

Recently I've been involved in an issue about silently installing mutiple CABs, so I think it may be worth mentioning its results here.

The OS component invoked when installing CABs is WCELOAD.EXE: it's the same if the CAB is created for XML Provisioning (through makecab.exe) or for installing an application (thruogh CabWiz.exe). It's for example responsible to check for certificates when the Security Policies dictate that unsigned CAB are not allowed to run. The version for Windows Mobile (5.0\6) is a bit different from the one for Windows CE 5.0, maily regarding available command-line parameters, check out:

Starting with Windows Mobile 5.0, only one running instance of WCELOAD.EXE is possible, therefore the nested CABs used with Windows Mobile 2003 are no longer possible. A solution to this is the MulticabInstall SDK sample: it basically allows the installation-chaining of CABs packaged into an UberCAB by looking at some registry keys. The sample contains a whitepaper that explains everything needed, I won't double it here.

However, what if I want all those inner CABs to be SILENTLY installed? For a single CAB, the solution is programmatically launch WCELOAD.EXE with /silent option (on Windows Mobile). So I simply looked for the function in the MulticabInstall SDK sample responsible for executing the CAB and found:

 BOOL HostExec(LPCTSTR lpszFilePath, HANDLE *phProcess)
{
    BOOL bRet;
    SHELLEXECUTEINFO sei = {0};

    sei.cbSize = sizeof(sei);
    sei.nShow = SW_SHOWNORMAL;
    sei.lpFile = lpszFilePath;
    //sei.lpParameters = TEXT("/silent");  //WRONG APPROACH!!

    bRet = ShellExecuteEx(&sei);

    if (bRet)
    {
        *phProcess = sei.hProcess;
    }

    return bRet;
}

It uses the ShellExecuteEx() API to launch the application on the OS associated to files with .cab extension. I tried to set the parameter lpParameters of the SHELLEXECUTEINFO structure to "/silent", however this didn't work... So I looked at documentation for the SHELLEXECUTEINFO structure and found: "[...] If the lpFile member specifies a document file, this member should be NULL. ". At this point I remembered what that sentence means: lpParameters was basically ignored since my lpFile was NOT an .EXE! Embarrassed

In order to continue using ShellExecuteEx (and not CreateProcess, for exampple), the code I came up with was simply:

 BOOL HostExec(LPCTSTR lpszFilePath, HANDLE *phProcess)
{
    BOOL bRet;
    SHELLEXECUTEINFO sei = {0};

    sei.cbSize = sizeof(sei);
    sei.nShow = SW_SHOWNORMAL; 
    sei.lpFile = TEXT("\\Windows\\WCELOAD.EXE");

    TCHAR   szLaunchParms[MAX_PATH];
    StringCchPrintf(szLaunchParms,ARRAYSIZE(szLaunchParms), 
            TEXT("/silent \"%s\""), 
            lpszFilePath);
    sei.lpParameters = szLaunchParms;

    bRet = ShellExecuteEx(&sei);

    if (bRet)
    {
        *phProcess = sei.hProcess;
    }

    return bRet;
}

 

As a final note, consider that on WM5 there could be additional prompt regarding CAB installations, if the CAB is not signed with a certificate stored on the SPC store of the device.When using /noui (or /silent) then by default prompts are answered with 'Yes'. However, if the .cab file is unsigned (or signed with a certificate not stored on the device), any security-related prompts will default to 'No' for security reasons, and the installation might SILENTLY fail.

 

Cheers,

~raffaele