text: //+---------------------------------------------------------------------------
  //
  //  Microsoft Windows
  //  Copyright (C) Microsoft Corporation, 1997.
  //
  //  File:       K K U T I L S . C P P
  //
  //  Contents:   Misc. helper functions
  //
  //  Notes:
  //
  //  Author:     kumarp   14 Jan 1997
  //
  //----------------------------------------------------------------------------
  
  #include "pch.h"
  #pragma hdrstop
  #include "kkutils.h"
  #include "ncreg.h"
  
  extern const WCHAR c_szRegKeyServices[];
  
  // ----------------------------------------------------------------------
  //
  // Function:  AddOnlyOnceToStringList
  //
  // Purpose:   Add the specified string to the list if it is not present
  //            in that list
  //
  // Arguments:
  //    psl       [in]  list of strings
  //    pszString [in]  string to add
  //
  // Returns:   None
  //
  // Author:    kumarp 23-December-97
  //
  // Notes:
  //
  void AddOnlyOnceToStringList(IN TStringList* psl, IN PCWSTR pszString)
  {
      AssertValidReadPtr(psl);
      AssertValidReadPtr(pszString);
  
      if (!FIsInStringList(*psl, pszString))
      {
          AddAtEndOfStringList(*psl, pszString);
      }
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  ConvertDelimitedListToStringList
  //
  // Purpose:   Convert a delimited list to a TStringList
  //
  // Arguments:
  //    strDelimitedList [in]  delimited list
  //    chDelimiter      [in]  delimiter
  //    slList           [out] list of string items
  //
  // Returns:   None
  //
  // Author:    kumarp 23-December-97
  //
  // Notes:
  //
  void ConvertDelimitedListToStringList(IN const tstring& strDelimitedList,
                                        IN WCHAR chDelimiter,
                                        OUT TStringList &slList)
  {
      PCWSTR pszDelimitedList = strDelimitedList.c_str();
      DWORD i=0, dwStart;
  
      // should this be EraseAndDeleteAll() ??
      //EraseAll(&slList);
  	EraseAndDeleteAll(&slList);
      tstring strTemp;
      DWORD dwNumChars;
  
      // the two spaces are intentional
      static WCHAR szCharsToSkip[] = L"  \t";
      szCharsToSkip[0] = chDelimiter;
  
      while (pszDelimitedList[i])
      {
          dwStart = i;
          while (pszDelimitedList[i] &&
                 !wcschr(szCharsToSkip, pszDelimitedList[i]))
          {
              ++i;
          }
  
          // if each item is enclosed in quotes. strip the quotes
          dwNumChars = i - dwStart;
          if (pszDelimitedList[dwStart] == '"')
          {
              dwStart++;
              dwNumChars -= 2;
          }
  
          strTemp = strDelimitedList.substr(dwStart, dwNumChars);
          slList.insert(slList.end(), new tstring(strTemp));
  
          // skip spaces and delimiter
          //
          while (pszDelimitedList[i] &&
                 wcschr(szCharsToSkip, pszDelimitedList[i]))
          {
              ++i;
          }
      }
  }
  
  
  // ----------------------------------------------------------------------
  //
  // Function:  ConvertCommaDelimitedListToStringList
  //
  // Purpose:   Convert a comma delimited list to a TStringList
  //
  // Arguments:
  //    strDelimitedList [in]  comma delimited list
  //    slList           [out] list of string items
  //
  // Returns:   None
  //
  // Author:    kumarp 23-December-97
  //
  // Notes:
  //
  void ConvertCommaDelimitedListToStringList(IN const tstring& strDelimitedList, OUT TStringList &slList)
  {
      ConvertDelimitedListToStringList(strDelimitedList, (WCHAR) ',', slList);
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  ConvertSpaceDelimitedListToStringList
  //
  // Purpose:   Convert a space delimited list to a TStringList
  //
  // Arguments:
  //    strDelimitedList [in]  Space delimited list
  //    slList           [out] list of string items
  //
  // Returns:   None
  //
  // Author:    kumarp 23-December-97
  //
  // Notes:
  //
  void ConvertSpaceDelimitedListToStringList(IN const tstring& strDelimitedList,
                                             OUT TStringList &slList)
  {
      ConvertDelimitedListToStringList(strDelimitedList, ' ', slList);
  }
  
  void ConvertStringListToCommaList(IN const TStringList &slList, OUT tstring &strList)
  {
      ConvertStringListToDelimitedList(slList, strList, ',');
  }
  
  void ConvertStringListToDelimitedList(IN const TStringList &slList,
                        OUT tstring &strList, IN WCHAR chDelimiter)
  {
      TStringListIter pos = slList.begin();
      tstring strTemp;
      WORD i=0;
      static const WCHAR szSpecialChars[] = L" %=";
  
      while (pos != slList.end())
      {
          strTemp = **pos++;
  
          //
          //  put quotes around any strings that have chars that setupapi doesn't like.
          //
          if (strTemp.empty() ||
              (L'\"' != *(strTemp.c_str()) &&
               wcscspn(strTemp.c_str(), szSpecialChars) < strTemp.size()))
          {
              strTemp = L'"' + strTemp + L'"';
          }
  
          if (i)
          {
              strList = strList + chDelimiter + strTemp;
          }
          else
          {
              strList = strTemp;
          }
          ++i;
      }
  }
  
  
  // ----------------------------------------------------------------------
  //
  // Function:  IsBoolString
  //
  // Purpose:   Parse a string to decide if it represents a boolean value
  //
  // Arguments:
  //    pszStr  [in]  string
  //    pbValue [out] pointer to BOOL value parsed
  //
  // Returns:   TRUE on success, FALSE otherwise
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  BOOL IsBoolString(IN PCWSTR pszStr, OUT BOOL *pbValue)
  {
      if ((!_wcsicmp(pszStr, L"yes")) ||
      (!_wcsicmp(pszStr, L"true")) ||
      (!_wcsicmp(pszStr, L"1")))
      {
          *pbValue = TRUE;
          return TRUE;
      }
      else if ((!_wcsicmp(pszStr, L"no")) ||
           (!_wcsicmp(pszStr, L"false")) ||
           (!_wcsicmp(pszStr, L"0")))
      {
          *pbValue = FALSE;
          return TRUE;
      }
      else
      {
          return FALSE;
      }
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  FIsInStringArray
  //
  // Purpose:   Find out if a string exists in an array
  //
  // Arguments:
  //    ppszStrings     [in]  array of strings
  //    cNumStrings     [in]  num strings in array
  //    pszStringToFind [in]  string to find
  //
  // Returns:   TRUE on success, FALSE otherwise
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  BOOL FIsInStringArray(
      IN const PCWSTR* ppszStrings,
      IN DWORD cNumStrings,
      IN PCWSTR pszStringToFind,
      OUT UINT* puIndex)
  {
      for (DWORD isz = 0; isz < cNumStrings; isz++)
      {
          if (!lstrcmpiW(ppszStrings[isz], pszStringToFind))
          {
              if (puIndex)
              {
                  *puIndex = isz;
              }
  
              return TRUE;
          }
      }
      return FALSE;
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  HrRegOpenServiceKey
  //
  // Purpose:   Open reg key for the given service
  //
  // Arguments:
  //    szServiceName [in]  name of service
  //    samDesired    [in]  SAM required
  //    phKey         [out] pointer to handle of reg key
  //
  // Returns:   S_OK on success, otherwise an error code
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  HRESULT HrRegOpenServiceKey(
      IN PCWSTR pszServiceName,
      IN REGSAM samDesired,
      OUT HKEY* phKey)
  {
      DefineFunctionName("HrRegOpenServiceKey");
  
      AssertValidReadPtr(pszServiceName);
      AssertValidWritePtr(phKey);
  
      *phKey = NULL;
  
      HRESULT hr;
      tstring strService;
  
      strService = c_szRegKeyServices;
      strService += L"\\";
      strService += pszServiceName;
  
      hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, strService.c_str(),
                          samDesired, phKey);
  
      TraceErrorOptional(__FUNCNAME__, hr,
                         (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr));
  
      return hr;
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  HrRegOpenServiceSubKey
  //
  // Purpose:   Open sub key of a service key
  //
  // Arguments:
  //    pszServiceName [in]  name of service
  //    pszSubKey      [in]  name of sub key
  //    samDesired    [in]  SAM required
  //    phKey         [out] pointer to handle of key opened
  //
  // Returns:   S_OK on success, otherwise an error code
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  HRESULT HrRegOpenServiceSubKey(
      IN PCWSTR pszServiceName,
      IN PCWSTR pszSubKey,
      IN REGSAM samDesired,
      OUT HKEY* phKey)
  {
      AssertValidReadPtr(pszServiceName);
      AssertValidReadPtr(pszSubKey);
      AssertValidWritePtr(phKey);
  
      DefineFunctionName("HrRegOpenServiceSubKey");
  
      HRESULT hr = S_OK;
  
      tstring strKey;
      strKey = pszServiceName;
      strKey += L"\\";
      strKey += pszSubKey;
  
      hr = HrRegOpenServiceKey(strKey.c_str(), samDesired, phKey);
  
      TraceError(__FUNCNAME__, hr);
  
      return hr;
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  FIsServiceKeyPresent
  //
  // Purpose:   Check if a service reg key is present
  //
  // Arguments:
  //    pszServiceName [in]  name of service
  //
  // Returns:   TRUE on success, FALSE otherwise
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  BOOL FIsServiceKeyPresent(IN PCWSTR pszServiceName)
  {
      BOOL fResult = FALSE;
  
      HKEY hkeyService;
      HRESULT hr;
  
      hr = HrRegOpenServiceKey(pszServiceName, KEY_READ, &hkeyService);
      if (S_OK == hr)
      {
          // we just wanted to see if service is installed
          RegCloseKey(hkeyService);
          fResult = TRUE;
      }
  
      return fResult;
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  EraseAndDeleteAll
  //
  // Purpose:   Erase each element and then delete string array
  //
  // Arguments:
  //    sa [in]  pointer to array of strings
  //
  // Returns:   None
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  void EraseAndDeleteAll(IN TStringArray* sa)
  {
      for (size_t i=0; i < sa->size(); i++)
      {
          delete (*sa)[i];
      }
      sa->erase(sa->begin(), sa->end());
  }
  
  
  // ----------------------------------------------------------------------
  //
  // Function:  AppendToPath
  //
  // Purpose:   Append a subpath/filename to a path
  //
  // Arguments:
  //    pstrPath [in]  path
  //    szItem   [in]  item to append
  //
  // Returns:   None
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  void AppendToPath(IN OUT tstring* pstrPath, IN PCWSTR szItem)
  {
      if (pstrPath->c_str()[pstrPath->size()-1] != L'\\')
      {
          *pstrPath += L'\\';
      }
  
      *pstrPath += szItem;
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  ConvertDelimitedListToStringArray
  //
  // Purpose:   Convert a delimited list to an array
  //
  // Arguments:
  //    strDelimitedList [in]  delimited list (e.g. "a,b,c")
  //    chDelimiter      [in]  delimiter char
  //    saStrings        [out] array of strings
  //
  // Returns:   None
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  void ConvertDelimitedListToStringArray(
      IN const tstring& strDelimitedList,
      IN WCHAR chDelimiter,
      OUT TStringArray &saStrings)
  {
      PCWSTR pszDelimitedList = strDelimitedList.c_str();
      DWORD i=0, dwStart;
  
      EraseAndDeleteAll(&saStrings);
  
      tstring strTemp;
      DWORD dwNumChars;
      while (pszDelimitedList[i])
      {
          dwStart = i;
          while (pszDelimitedList[i] && (pszDelimitedList[i] != chDelimiter))
          {
              ++i;
          }
  
          // if each item is enclosed in quotes. strip the quotes
          dwNumChars = i - dwStart;
          if (pszDelimitedList[dwStart] == L'"')
          {
              dwStart++;
              dwNumChars -= 2;
          }
  
          strTemp = strDelimitedList.substr(dwStart, dwNumChars);
          saStrings.push_back(new tstring(strTemp));
          if (pszDelimitedList[i])
          {
              ++i;
          }
      }
  }
  
  // ----------------------------------------------------------------------
  //
  // Function:  ConvertCommaDelimitedListToStringList
  //
  // Purpose:   Convert a comma delimited list to an array
  //
  // Arguments:
  //    strDelimitedList [in]  delimited list (e.g. "a,b,c")
  //    saStrings        [out] array of strings
  //
  // Returns:   None
  //
  // Author:    kumarp 12-February-98
  //
  // Notes:
  //
  void ConvertCommaDelimitedListToStringArray(
      IN const tstring& strDelimitedList,
      OUT TStringArray &saStrings)
  {
      ConvertDelimitedListToStringArray(strDelimitedList, L',', saStrings);
  }
  
  