When I deploy the application to customers, I like to wrap all cabs in one as it would be much easier. For example, .NETCF and SQLCE. If the device is new, the .NETCF or SQLCE needs to be installed prior running my application. Thanks for CeSetupDriver and here. They helped me a lot to deploy the application with the way I want. However, I don't want to prompt user every time that the .NETCF or SQLCE has already installed. So I come up with a checking method to validate that the application has already installed and skip to next cab installation. All you need to do is passing you name of application and CSP (Configuration Service Provider) xml to validate. However, somehow I feel the code is a bit long. Can anyone shorten it? Ha... I am just lazy...

/** 
 * Query the installation files
 *
 * @param LPTSTR xmlDoc The xml document 
 * @param appName The application name
 * @return Returns true if installed
 */
BOOL Utils::QueryInstalledByCSP(LPTSTR xmlDoc, const TCHAR *appName)
{
  BOOL szResult = FALSE;
  
  if(xmlDoc == NULL)
   return FALSE;
   IXMLDOMDocument *pDOM = NULL;
    
    // Load the XML DOM
    if(SUCCEEDED(CoInitializeEx(NULL,COINIT_MULTITHREADED)))
 {    
  if(SUCCEEDED(CoCreateInstance(CLSID_DOMDocument, NULL, 
   CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, 
   IID_IXMLDOMDocument, (LPVOID *) &pDOM)))
  {
   // Tell the "doc" that we're not going to load asynchronously.
   if (SUCCEEDED(pDOM->put_async(VARIANT_FALSE)))
   {
    VARIANT_BOOL vBool;
    pDOM->loadXML(xmlDoc,&vBool);
    if (vBool == VARIANT_TRUE)
    {
     IXMLDOMNode *pNode;
     if (SUCCEEDED(pDOM->selectSingleNode(_T("wap-provisioningdoc"), &pNode)))
          {   
      IXMLDOMNodeList *pNodeList;
      IXMLDOMNode *pNodeChild;
      IXMLDOMNode *pNodeValue;
      IXMLDOMNamedNodeMap *pXMLNamedNodeMap;
      if (SUCCEEDED(pNode->selectSingleNode(_T("characteristic"), &pNode)))
      {   
       if(SUCCEEDED(pNode->selectNodes(_T("characteristic"), &pNodeList)))
       {
        long length = 0;
        pNodeList->get_length(&length);
        if(length > 0)
        {
         HRESULT hr = pNodeList->nextNode(&pNodeChild);
         while(hr == S_OK)
         {         
          if(SUCCEEDED(pNodeChild->get_attributes(&pXMLNamedNodeMap)))
          {
           if(SUCCEEDED(pXMLNamedNodeMap->getNamedItem(_T("type"), &pNodeValue)))
           {
            VARIANT varNodeValue;
            if(SUCCEEDED(pNodeValue->get_nodeValue(&varNodeValue)))
            {
             if(lstrcmpi(varNodeValue.bstrVal, appName) == 0)
             {
              szResult = TRUE;
              break;
             }
            }
            pNodeValue->Release();
           }
          }
          hr = pNodeList->nextNode(&pNodeChild);
         }
         pXMLNamedNodeMap->Release();
        }
        pNodeList->Release();
       }
      }
           }
     pNode->Release();
     pNode = NULL;
    }
   }
   pDOM->Release();
   // release COM
   CoUninitialize();
  }
 }
  return szResult;
}

So now what you have to do is add another method to check name of the cabs.
So far, it works all fine on all Motorola (Symbol) devices.

/** 
 * Check the installed application name with related cab file 
 */
BOOL Utils::CheckCabInstalled(LPTSTR xmlDoc, const TCHAR *cabName)
{
 if(lstrcmpi(cabName, _T("NETCFv35.wm.armv4i.cab")) == 0)
  return QueryInstalledByCSP(xmlDoc, _T("Microsoft .NET CF 3.5"));
 else if(lstrcmpi(cabName, _T("NETCFv35.Messages.EN.wm.cab")) == 0)
  return QueryInstalledByCSP(xmlDoc, _T("Microsoft .NET CF 3.5 EN-String Resource"));
 else if(lstrcmpi(cabName, _T("sqlce.ppc.wce5.armv4i.CAB")) == 0)
  return QueryInstalledByCSP(xmlDoc, _T("SQLServerCompact 3.5 Core"));
 else if(lstrcmpi(cabName, _T("sqlce.repl.ppc.wce5.armv4i.CAB")) == 0)
  return QueryInstalledByCSP(xmlDoc, _T("SQLServerCompact 3.5 Repl"));
 else if(lstrcmpi(cabName, _T("sqlce.dev.ENU.ppc.wce5.armv4i.CAB")) == 0)
  return QueryInstalledByCSP(xmlDoc, _T("SQLServerCompact 3.5 Tools EN"));
 else 
  return FALSE;
}