BOOL CNTScmService::ChangeDescription(const CNTServiceString& sDescription)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangeDescription, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows 2000 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  SERVICE_DESCRIPTION sd;
  CNTServiceString sTemp(sDescription);
#ifdef CNTSERVICE_MFC_EXTENSIONS
  sd.lpDescription = sTemp.GetBuffer(sTemp.GetLength());
#else
  sd.lpDescription = &(sTemp[0]);
#endif
  BOOL bSuccess = m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_DESCRIPTION, &sd);
#ifdef CNTSERVICE_MFC_EXTENSIONS
  sTemp.ReleaseBuffer();
#endif
  return bSuccess;
}
BOOL CNTScmService::ChangeRequiredPrivileges(const CStringArray& privileges)
{
  //Validate our parameters
  ASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    TRACE(_T("CNTScmService::ChangeRequiredPrivileges, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows Vista / Windows 2008 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Work out the size of the buffer we will need
  DWORD dwSize = 0;
  INT_PTR nStrings = privileges.GetSize();
  for (INT_PTR i=0; i<nStrings; i++)
    dwSize += privileges.GetAt(i).GetLength() + 1; //1 extra for each NULL terminator

  //Need one second NULL for the double NULL at the end
  dwSize++;

  //Allocate some memory for the API
  ATL::CHeapPtr<TCHAR> lpBuffer;
  if (!lpBuffer.Allocate(dwSize))
  {
    SetLastError(ERROR_OUTOFMEMORY);
    return FALSE;
  }

  //Now copy the strings into the buffer
  int nCurOffset = 0;
  LPTSTR lpszString = lpBuffer.m_pData;
  for (INT_PTR i=0; i<nStrings; i++)
  {
    CString sText = privileges.GetAt(i);
    int nCurrentStringLength = sText.GetLength();
    _tcscpy_s(&lpszString[nCurOffset], nCurrentStringLength+1, sText);
    nCurOffset += (nCurrentStringLength + 1);
  }
  //Don't forgot to doubly NULL terminate
  lpszString[nCurOffset] = _T('\0');

  //Call through the function pointer
  SERVICE_REQUIRED_PRIVILEGES_INFO srpi;
  srpi.pmszRequiredPrivileges = lpBuffer.m_pData;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &srpi);
}
BOOL CNTScmService::ChangeTrigger(PSERVICE_TRIGGER_INFO pTriggerInfo)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangeTrigger, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows 7 / Windows 2008 R2 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_TRIGGER_INFO, pTriggerInfo);
}
BOOL CNTScmService::ChangeFailureActions(LPSERVICE_FAILURE_ACTIONS pFailureActions)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangeFailureActions, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows 2000 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_FAILURE_ACTIONS, pFailureActions);
}
BOOL CNTScmService::ChangeLaunchProtected(DWORD dwLaunchProtected)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangeLaunchProtected, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows 8.1 / Windows 2012 R2 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  _SERVICE_LAUNCH_PROTECTED_INFO slpi;
  slpi.dwLaunchProtected = dwLaunchProtected;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_LAUNCH_PROTECTED, &slpi);
}
BOOL CNTScmService::ChangePreShutdown(DWORD dwPreshutdownTimeout)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangePreShutdown, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows Vista / Windows 2008 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  SERVICE_PRESHUTDOWN_INFO spsi;
  spsi.dwPreshutdownTimeout = dwPreshutdownTimeout;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_PRESHUTDOWN_INFO, &spsi);
}
BOOL CNTScmService::ChangeFailureActionsFlag(BOOL bFailureActionsOnNonCrashFailures)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangeFailureActionsFlag, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows Vista / Windows 2008 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  SERVICE_FAILURE_ACTIONS_FLAG sfaf;
  sfaf.fFailureActionsOnNonCrashFailures = bFailureActionsOnNonCrashFailures;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, &sfaf);
}
BOOL CNTScmService::ChangeDelayAutoStart(BOOL bDelayedAutoStart)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangeDelayAutoStart, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows Vista / Windows 2008 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  SERVICE_DELAYED_AUTO_START_INFO sdasi;
  sdasi.fDelayedAutostart = bDelayedAutoStart;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &sdasi);
}
BOOL CNTScmService::ChangeSidInfo(DWORD dwServiceSidType)
{
  //Validate our parameters
  ASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    TRACE(_T("CNTScmService::ChangeSidInfo, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows Vista / Windows 2008 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  SERVICE_SID_INFO ssi;
  ssi.dwServiceSidType = dwServiceSidType;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_SERVICE_SID_INFO, &ssi);
}
BOOL CNTScmService::ChangePreferredNode(USHORT usPreferredNode, BOOL bDelete)
{
  //Validate our parameters
  ATLASSERT(m_hService != NULL);

  //Check to see if the function pointer is available
  if (m_lpfnChangeServiceConfig2 == NULL)
  {
    ATLTRACE(_T("CNTScmService::ChangePreferredNode, ChangeServiceConfig2 function is not supported on this OS. You need to be running at least Windows 7 / Windows 2008 R2 to use this function\n"));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
  }

  //Call through the function pointer
  SERVICE_PREFERRED_NODE_INFO spni;
  spni.usPreferredNode = usPreferredNode;
  spni.fDelete = bDelete ? 1 : 0;
  return m_lpfnChangeServiceConfig2(m_hService, SERVICE_CONFIG_PREFERRED_NODE, &spni);
}