Installing Multiple CABS on Windows Mobile 5.0

Updated to fix a few of the html special characters!
"Starting with Windows Mobile 5.0, only one instance of the installer (wceload.exe)
can be running at a time on Pocket PC devices.
This restriction has always been in place on Smartphone.
As a result, CAB files that start other CAB files from a
custom setup DLL may not work on Windows Mobile 5.0.
The workaround for this is to have a small executable in the
CAB that a custom setup.dll starts in its Install_Exit entry point."
I have provided a coded solution.

Click ' Read more...' to get the code.

Here is the coded solution:
Your setup DLL should have a function which looks like this:

codeINSTALL_EXIT Install_Exit(HWND hwndparent,
LPCTSTR pszInstallDir,
WORD cfaileddirs,
WORD cfailedfiles,
WORD cfailedregkeys,
WORD cfailedregvals,
WORD cfailedshortcuts)
{	
 PROCESS_INFORMATION pi = {0};

 //your multi cab installer program
 LPCTSTR lpExe = _T("\\Program Files\\myprogram\\Installer.exe");
 //the directory where your multiple CABS live
 LPCTSTR lpCmdLine = _T("\"\\Program Files\\myprogram\\\"");

 CreateProcess(lpExe, lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi); 

 if (pi.hProcess)
  CloseHandle (pi.hProcess);
 if (pi.hThread)
  CloseHandle (pi.hThread); 

 //return value
 return codeINSTALL_EXIT_DONE;
}

You will need to make a new smart device application, I called mine Installer.
Make sure you link toolhelp.lib

// Installer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <Tlhelp32.h>
#include <windows.h>
#include <commctrl.h>
void installCab(LPTSTR cabFile);
void installCabs(LPCTSTR directory);
bool checkIfWCELOADIsRunning();

int _tmain(int argc, _TCHAR* argv[])
{
 do
 {
  Sleep(1000);
 }
  while(checkIfWCELOADIsRunning());
 MessageBox(0, _T("Additional programs will be installed.\n 
\nIf Prompted to restart press cancel. Press OK to continue."),argv[1], 0);
 installCabs(argv[1]);
	
 return 0;
}

//install a cab file
void installCab(LPTSTR cabFile)
{
 // Specify an action for the application to perform, flags and other parameters 
 SHELLEXECUTEINFO info; 
 info.cbSize = sizeof(info); 
 //info.fMask = SEE_MASK_FLAG_NO_UI; 
 info.fMask = SEE_MASK_NOCLOSEPROCESS;
 info.hwnd = NULL; 
 info.lpVerb = _T("open"); 
 info.lpFile = cabFile;//_T("file"); 
 info.lpParameters = _T(""); 
 info.lpDirectory = _T(""); 
 info.nShow = SW_SHOW;
 //info.hInstApp = AfxGetInstanceHandle();
 // Call to perform an action 
 ShellExecuteEx(&info);	

 WaitForSingleObject(info.hProcess,INFINITE);

}

//install all cabs in a directory, calls installCab(LPTSTR cabFile)
void installCabs(LPCTSTR directory)
{
  //to save space i have excluded this
  //i have a function which finds all CABS in the directory
  //you can also hard code your CAB files
}

bool checkIfWCELOADIsRunning()
{
 PROCESSENTRY32 pe32;
 HANDLE hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

 if( hProcessSnap == INVALID_HANDLE_VALUE )
 {
  MessageBox(0, _T("invalid handle"), _T("proc"), 0);
  return false;
 }

 // Retrieve information about the first process,
 // and exit if unsuccessful
 if( !Process32First( hProcessSnap, &pe32 ) )
 {		
  MessageBox(0, _T("couldnt get info"), _T("proc"), 0);
  CloseHandle( hProcessSnap );     // Must clean up the snapshot object!
  return false;
 }

 do
 {
  if(wcscmp(pe32.szExeFile, _T("wceload.exe")) == 0)
  {
   CloseHandle( hProcessSnap );
   return true;
  }
 }
 while( Process32Next( hProcessSnap, &pe32 ) );
 CloseHandle( hProcessSnap );
 return false;
}

NOTE: this was put together very quickly, a few times I haven't been able to retrieve information about the first process.