Subversion Repositories libraries.mycontrols

Rev

Rev 4 | Blame | Compare with Previous | Last modification | View Log

/*
Module : HKLM.CPP
Purpose: Implementation for a class to provide simple
         access to the HKEY_LOCAL_MACHINE\Software\Company\MyApp
                 registry key similiar to the functions MFC provides
                 to access the same settings in HKEY_CURRENT_USER
Created: PJN / 27-07-1998
History: PJN / 03-10-1999 Addition of GetProfileStringArray and WriteProfileStringArray methods
         PJN / 09-08-2001 1. Updated copyright message
                          2. Fixed an issue where the class fails to read any key that is readonly. 
                          This is a problem since Win2000 defaults access to HKLM for "normal" 
                          users to readonly. Thanks to Hans-Georg Ulrich for spotting this problem
                          3. Removed an unreferenced function for the hklm header file
                          4. Fixed a memory overwrite problem in CHKLM::SetStringArrayIntoRegistry.
                          Thanks to BoundsChecker on spotting this problem.
                          5. Fixed a problem in CHKLM::SetStringArrayIntoRegistry with the 
                          calculation of the size to be used in the call to RegSetValueEx
                          6. GetStringArrayFromRegistry now use RegQueryValueEx to get the size of 
                          the data it contains.
                          7. Sample app now uses CWinApp to make it easier for testing.
         PJN / 12-10-2001 1. Now allows application name to be overridden using new method namely, 
                          SetProductNameRegistryKey. Thanks to Rene M. Laviolette for this suggestion.
                             


Copyright (c) 1998 - 2001 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
when your product is released in binary form. You are allowed to modify the source code in any way you want 
except you cannot modify the copyright details at the top of each module. If you want to distribute source 
code with your application, then you are only allowed to distribute versions released by the author. This is 
to maintain a single distribution point for the source code. 

*/

///////////////////////////////// Includes //////////////////////////////////
#pragma warning( disable : 4996 )
#include "stdafx.h"
#include "hklm.h"
 
#pragma warning(disable : 4996)

//////////////// Macros //////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


//////////////// Implementation //////////////////////////////////////

void CHKLM::SetRegistryKey(char *lpszRegistryKey)
{
    m_sRegistryKey = lpszRegistryKey;
}

void CHKLM::SetProductNameRegistryKey(LPCTSTR lpszProductNameRegistryKey)
{
  m_sProductNameRegistryKey = lpszProductNameRegistryKey;
}

void CHKLM::SetProductNameRegistryKey(UINT nIDProductNameRegistryKey)
{
  CString sKey;
    VERIFY(sKey.LoadString(nIDProductNameRegistryKey));
    SetProductNameRegistryKey(sKey);
}

CString CHKLM::GetProductNameRegistryKey() const
{
  return m_sProductNameRegistryKey;
}

void CHKLM::SetRegistryKey(UINT nIDRegistryKey)
{
  CString sKey;
    VERIFY(sKey.LoadString(nIDRegistryKey));
  SetRegistryKey(sKey.GetBuffer());
}

// returns key for HKEY_LOCAL_MACHINE\"Software"\RegistryKey\ProfileName
// creating it if it doesn't exist
// responsibility of the caller to call RegCloseKey() on the returned HKEY
HKEY CHKLM::GetAppRegistryKey(BOOL bReadOnly)
{
    ASSERT(m_sRegistryKey.GetLength());

    HKEY hAppKey = NULL;
    HKEY hSoftKey = NULL;
    HKEY hCompanyKey = NULL;

  //Setup the access type
  REGSAM samDesired = KEY_WRITE | KEY_READ;
  if (bReadOnly)
    samDesired = KEY_READ;

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software"), 0, samDesired, &hSoftKey) == ERROR_SUCCESS)
    {
        DWORD dw;
        if (RegCreateKeyEx(hSoftKey, m_sRegistryKey, 0, REG_NONE,   REG_OPTION_NON_VOLATILE, 
                       samDesired, NULL, &hCompanyKey, &dw) == ERROR_SUCCESS)
        {
      if (m_sProductNameRegistryKey.GetLength())
      {
              RegCreateKeyEx(hCompanyKey, m_sProductNameRegistryKey, 0, REG_NONE,   REG_OPTION_NON_VOLATILE, 
                       samDesired, NULL, &hAppKey, &dw);
      }
      else
      {
        ASSERT(AfxGetApp());
              RegCreateKeyEx(hCompanyKey, AfxGetApp()->m_pszAppName, 0, REG_NONE,   REG_OPTION_NON_VOLATILE, 
                       samDesired, NULL, &hAppKey, &dw);
      }
        }
    }
    if (hSoftKey != NULL)
        RegCloseKey(hSoftKey);
    if (hCompanyKey != NULL)
        RegCloseKey(hCompanyKey);

    return hAppKey;
}

// returns key for:
//      HKEY_LOCAL_MACHINE\"Software"\RegistryKey\AppName\lpszSection
// creating it if it doesn't exist.
// responsibility of the caller to call RegCloseKey() on the returned HKEY
HKEY CHKLM::GetSectionKey(LPCTSTR lpszSection, BOOL bReadOnly)
{
    ASSERT(lpszSection != NULL);

    HKEY hSectionKey = NULL;
    HKEY hAppKey = GetAppRegistryKey(bReadOnly);
    if (hAppKey == NULL)
        return NULL;

  //Setup the access type
  REGSAM samDesired = KEY_WRITE | KEY_READ;
  if (bReadOnly)
    samDesired = KEY_READ;

    DWORD dw;
    RegCreateKeyEx(hAppKey, lpszSection, 0, REG_NONE, REG_OPTION_NON_VOLATILE, 
                 samDesired, NULL, &hSectionKey, &dw);
    RegCloseKey(hAppKey);
    return hSectionKey;
}

UINT CHKLM::GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry,   int nDefault)
{
    ASSERT(lpszSection != NULL);
    ASSERT(lpszEntry != NULL);

    HKEY hSecKey = GetSectionKey(lpszSection, TRUE);
    if (hSecKey == NULL)
        return nDefault;
    DWORD dwValue;
    DWORD dwType;
    DWORD dwCount = sizeof(DWORD);
    LONG lResult = RegQueryValueEx(hSecKey, (LPTSTR)lpszEntry, NULL, &dwType,
                                       (LPBYTE)&dwValue, &dwCount);
    RegCloseKey(hSecKey);
    if (lResult == ERROR_SUCCESS)
    {
        ASSERT(dwType == REG_DWORD);
        ASSERT(dwCount == sizeof(dwValue));
        return (UINT)dwValue;
    }
    return nDefault;
}

CString CHKLM::GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault)
{
    ASSERT(lpszSection != NULL);
    ASSERT(lpszEntry != NULL);

    HKEY hSecKey = GetSectionKey(lpszSection, TRUE);
    if (hSecKey == NULL)
        return lpszDefault;
    CString strValue;
    DWORD dwType, dwCount;
    LONG lResult = RegQueryValueEx(hSecKey, (LPTSTR)lpszEntry, NULL, &dwType,
                                     NULL, &dwCount);
    if (lResult == ERROR_SUCCESS)
    {
        ASSERT(dwType == REG_SZ);
        lResult = RegQueryValueEx(hSecKey, (LPTSTR)lpszEntry, NULL, &dwType,
                                      (LPBYTE)strValue.GetBuffer(dwCount/sizeof(TCHAR)), &dwCount);
        strValue.ReleaseBuffer();
    }
    RegCloseKey(hSecKey);
    if (lResult == ERROR_SUCCESS)
    {
        ASSERT(dwType == REG_SZ);
        return strValue;
    }
    return lpszDefault;
}

BOOL CHKLM::GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, BYTE** ppData, UINT* pBytes)
{
    ASSERT(lpszSection != NULL);
    ASSERT(lpszEntry != NULL);
    ASSERT(ppData != NULL);
    ASSERT(pBytes != NULL);
    *ppData = NULL;
    *pBytes = 0;

    HKEY hSecKey = GetSectionKey(lpszSection, TRUE);
    if (hSecKey == NULL)
        return FALSE;

    DWORD dwType, dwCount;
    LONG lResult = RegQueryValueEx(hSecKey, (LPTSTR)lpszEntry, NULL, &dwType, NULL, &dwCount);
    *pBytes = dwCount;
    if (lResult == ERROR_SUCCESS)
    {
        ASSERT(dwType == REG_BINARY);
        *ppData = new BYTE[*pBytes];
        lResult = RegQueryValueEx(hSecKey, (LPTSTR)lpszEntry, NULL, &dwType,
            *ppData, &dwCount);
    }
    RegCloseKey(hSecKey);
    if (lResult == ERROR_SUCCESS)
    {
        ASSERT(dwType == REG_BINARY);
        return TRUE;
    }
    else
    {
        delete [] *ppData;
        *ppData = NULL;
    }
    return FALSE;
}

BOOL CHKLM::GetProfileStringArray(LPCTSTR lpszSection, LPCTSTR lpszEntry, CStringArray& array)
{
    ASSERT(lpszSection != NULL);

  //Empty out the array before we go any further
  array.RemoveAll();

    HKEY hSecKey = GetSectionKey(lpszSection, TRUE);
    if (hSecKey == NULL)
        return FALSE;
    BOOL bSuccess = GetStringArrayFromRegistry(hSecKey, lpszEntry, array);
    RegCloseKey(hSecKey);
    return bSuccess;
}

BOOL CHKLM::WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue)
{
    ASSERT(lpszSection != NULL);
    ASSERT(lpszEntry != NULL);

    HKEY hSecKey = GetSectionKey(lpszSection);
    if (hSecKey == NULL)
        return FALSE;
    LONG lResult = RegSetValueEx(hSecKey, lpszEntry, NULL, REG_DWORD,
                                 (LPBYTE)&nValue, sizeof(nValue));
    RegCloseKey(hSecKey);
    return lResult == ERROR_SUCCESS;
}

BOOL CHKLM::WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue)
{
    ASSERT(lpszSection != NULL);

    LONG lResult;
    if (lpszEntry == NULL) //delete whole section
    {
        HKEY hAppKey = GetAppRegistryKey();
        if (hAppKey == NULL)
            return FALSE;
        lResult = ::RegDeleteKey(hAppKey, lpszSection);
        RegCloseKey(hAppKey);
    }
    else if (lpszValue == NULL)
    {
        HKEY hSecKey = GetSectionKey(lpszSection);
        if (hSecKey == NULL)
            return FALSE;
        // necessary to cast away const below
        lResult = ::RegDeleteValue(hSecKey, (LPTSTR)lpszEntry);
        RegCloseKey(hSecKey);
    }
    else
    {
        HKEY hSecKey = GetSectionKey(lpszSection);
        if (hSecKey == NULL)
            return FALSE;
        lResult = RegSetValueEx(hSecKey, lpszEntry, NULL, REG_SZ,
            (LPBYTE)lpszValue, (lstrlen(lpszValue)+1)*sizeof(TCHAR));
        RegCloseKey(hSecKey);
    }
    return lResult == ERROR_SUCCESS;
}

BOOL CHKLM::WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes)
{
    ASSERT(lpszSection != NULL);

    LONG lResult;
    HKEY hSecKey = GetSectionKey(lpszSection);
    if (hSecKey == NULL)
        return FALSE;
    lResult = RegSetValueEx(hSecKey, lpszEntry, NULL, REG_BINARY,
        pData, nBytes);
    RegCloseKey(hSecKey);
    return lResult == ERROR_SUCCESS;
}

BOOL CHKLM::WriteProfileStringArray(LPCTSTR lpszSection, LPCTSTR lpszEntry, const CStringArray& array)
{
    ASSERT(lpszSection != NULL);
    HKEY hSecKey = GetSectionKey(lpszSection);
    if (hSecKey == NULL)
        return FALSE;
    BOOL bSuccess = SetStringArrayIntoRegistry(hSecKey, lpszEntry, array);
    RegCloseKey(hSecKey);
    return bSuccess;
}

BOOL CHKLM::GetStringArrayFromRegistry(HKEY hKey, LPCTSTR lpszEntry, CStringArray& array)
{
    ASSERT(hKey != NULL);
    ASSERT(lpszEntry != NULL);

  //Assume the worst
  BOOL bSuccess = FALSE;

  //Empty the array before we go any further
  array.RemoveAll();

    DWORD dwType, dwCount;
    LONG lResult = RegQueryValueEx(hKey, (LPTSTR)lpszEntry, NULL, &dwType, NULL, &dwCount);
    if (lResult == ERROR_SUCCESS)
    {
        ASSERT(dwType == REG_MULTI_SZ);
        LPBYTE lpBuffer = new BYTE[dwCount];
        lResult = RegQueryValueEx(hKey, (LPTSTR)lpszEntry, NULL, &dwType, lpBuffer, &dwCount);
    if (lResult == ERROR_SUCCESS)
    {
      LPTSTR lpszStrings = (LPTSTR) lpBuffer;
      while (lpszStrings[0] != 0)
      {
        array.Add((LPCTSTR) lpszStrings);
        lpszStrings += (_tcslen(lpszStrings ) + 1);
      }

      bSuccess = TRUE;
    }

    //Tidy up the heap memory we have used
    delete [] lpBuffer;
    }

  return bSuccess;
}

BOOL CHKLM::SetStringArrayIntoRegistry(HKEY hKey, LPCTSTR lpszEntry, const CStringArray& array)
{
  int i;
  //Validate our input parameters
  ASSERT(hKey);
  ASSERT(lpszEntry != NULL);

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

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

  //Convert from BYTE size to character size
  dwSize *= sizeof(TCHAR);

  //Allocate the memory we want
  BYTE* lpBuffer = new BYTE[dwSize];
  ::ZeroMemory(lpBuffer, dwSize);

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

  //Finally write it into the registry
    BOOL bSuccess = (::RegSetValueEx(hKey, lpszEntry, NULL, REG_MULTI_SZ, lpBuffer, dwSize) == ERROR_SUCCESS);

  //free up the memory we used
  delete [] lpBuffer;

  return bSuccess;
}