CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - pobranie listy lub tabeli KeyValue z klucza rejestru
Strona 1 z 1

pobranie listy lub tabeli KeyValue z klucza rejestru

Nowy postNapisane: niedziela, 13 lutego 2011, 00:22
przez Android
Witam,
Chciałbym uzyskać z rejestru spis przechowywanych wartości - ich nazwy.
Na przykład załóżmy, że aplikacja przechowuje w rejestrze informacje takie jak wymiar i położenie okna. Dane są zapisywane w HKEY_CURRENT_USER w kluczu Software\NazwProducenta\NazwaAplikacji\. Mają nazwy odpowiednio Height, Width, Top, Left.
Sytuacja jaka mnie interesuje ma miejsce wtedy gdy nie znamy nazw (Height, Width, Top, Left) ani ilosci wpisów. Chciałbym pobrać np. tablice z nazwami lub liste - w każdym bądź razie coś co pozwoli sprawdzić ile jest i jakie nazwy mają wpisy oraz dzięki temu później odwołać się do tych wpisów - najlepiej w pętli.
Z góry dziękuję za pomoc.

Re: pobranie listy lub tabeli KeyValue z klucza rejestru

Nowy postNapisane: niedziela, 13 lutego 2011, 10:45
przez polymorphism
Do dokumentacji nie łaska zajrzeć? -> TRegistry::GetValueNames.

Re: pobranie listy lub tabeli KeyValue z klucza rejestru

Nowy postNapisane: niedziela, 13 lutego 2011, 12:44
przez Cyfrowy Baron
Chodzi oczywiście o pobranie nazw wartości. Mając nazwy wartości w kluczu można już bez problemu pobrać przypisane im dane. Do pobrania nazw wartości z klucza służy oczywiście funkcja GetValueName. Pobranie wartości klucza zależy już w dużej mierze od jego typu. Proponuję taki kod:

KOD cpp:     UKRYJ  
#include <registry.hpp>
#include <memory>

void __fastcall ReadKeyValues(HKEY hKey, String subKey, TListView *ListView)
{
  TRegistry *Rejestr = new TRegistry();
  Rejestr->RootKey = hKey; /* otwieram drzewo */

  /* otwieram klucz, false - nie tworzę jeżeli klucz nie istnieje */
  if( !Rejestr->OpenKey(subKey, false) )
  {
   ShowMessage("Nieprawidłowy klucz!");
   delete Rejestr;
   return;
  }

  std::auto_ptr<TStrings> vList(new TStringList);

  Rejestr->GetValueNames(vList.get());

  ListView->Items->Clear();

  int x = -1;
  while(vList->Count - 1 > x++)
  {
   String ValueName = vList->Strings[x];

   TRegDataType rDT = Rejestr->GetDataType(ValueName);

   String DataType  = "";
   String DataValue = Rejestr->GetDataAsString(ValueName, false);

   switch(rDT)
   {
    case rdUnknown:
    {
     DataType = "REG_MULTI_SZ";
     TCHAR lpByte[8192];
     DWORD lpcbData = 8192;
     HKEY hqKey;
     if(RegOpenKeyEx( hKey, subKey.c_str(), 0,
                   KEY_QUERY_VALUE, &hqKey)  == ERROR_SUCCESS)
     {

      if( RegQueryValueEx( hqKey, ValueName.c_str(), NULL, NULL,
                         (LPBYTE)lpByte, &lpcbData) == ERROR_SUCCESS)
      {
       DataValue = lpByte;
      }

      RegCloseKey(hqKey);
     }
     break;
    }
    case rdString:       DataType = "REG_SZ"; break;
    case rdBinary:       DataType = "REG_BINARY"; break;
    case rdInteger:
    {
     DataType = "REG_DWORD";
     int iVal = DataValue.ToIntDef(0);
     DataValue = StringReplace(Rejestr->GetDataAsString(ValueName, true),
                 "dword:", "0x", TReplaceFlags() << rfReplaceAll)
                 + " (" + (String)iVal + ")";
     break;
    }
    case rdExpandString: DataType = "REG_EXPAND_SZ"; break;
   }

   TListItem * ElementListy = ListView->Items->Add();
   ElementListy->Caption = ValueName;
   ElementListy->SubItems->Add(DataType);
   ElementListy->SubItems->Add(DataValue);
  }

  delete Rejestr;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 ReadKeyValues( HKEY_LOCAL_MACHINE,
                "HARDWARE\\DESCRIPTION\\System",
                ListView1 );
}


Wynik zapisywany jest w obiekcie typu TListView, gdyż doskonale się do tego celu nadaje. Kod nie jest jednak w pełni funkcjonalny, gdyż wartości typu REG_MULTI_SZ i REG_EXPAND_SZ powinny być pobierane do jakiejś struktury, ale nie bardzo wiem do jakiej, a w pomocy nic konkretnego na ten temat nie ma. Poza tym rozróżnianie typów kluczy też pozostawia wiele do życzenia, gdyż w przykładzie TRegDataType będąca metodą klasy TRegistry nie rozróżnia typów REG_MULTI_SZ i REG_FULL_RESOURCE_DESCRIPTOR.

Re: pobranie listy lub tabeli KeyValue z klucza rejestru

Nowy postNapisane: niedziela, 13 lutego 2011, 20:26
przez Android
Bardzo dziękuję za pomoc :)

Re: pobranie listy lub tabeli KeyValue z klucza rejestru

Nowy postNapisane: poniedziałek, 14 lutego 2011, 10:03
przez Cyfrowy Baron
Po namyśle prezentuję poprawiony sposób odczytywania wartości typu REG_MULTI_SZ, tak by funkcja ReadKeyValues pobierała całą zawartość tego typu:

KOD cpp:     UKRYJ  
void __fastcall ReadKeyValues(HKEY hKey, String subKey, TListView *ListView)
{
  TRegistry *Rejestr = new TRegistry();
  Rejestr->RootKey = hKey;

  if( !Rejestr->OpenKey(subKey, false) )
  {
   ShowMessage("Nieprawidłowy klucz!");
   delete Rejestr;
   return;
  }

  std::auto_ptr<TStrings> vList(new TStringList);

  Rejestr->GetValueNames(vList.get());

  ListView->Items->Clear();

  int x = -1;
  while(vList->Count - 1 > x++)
  {
   String ValueName = vList->Strings[x];

   TRegDataType rDT = Rejestr->GetDataType(ValueName);

   String DataType  = "";
   String DataValue = Rejestr->GetDataAsString(ValueName, false);

   switch(rDT)
   {
    case rdUnknown:
    {
     DataType = "REG_MULTI_SZ";
     TCHAR lpByte[8192] = {'\0'};
     DWORD lpcbData = 8192;
     DWORD lpType;
     HKEY hqKey;
     if(RegOpenKeyEx( hKey, subKey.c_str(), 0,
                   KEY_QUERY_VALUE, &hqKey)  == ERROR_SUCCESS)
     {

      if( RegQueryValueEx( hqKey, ValueName.c_str(), NULL, &lpType,
                         (LPBYTE)lpByte, &lpcbData) == ERROR_SUCCESS)
      {
       if(lpType == REG_MULTI_SZ)
       {
        int y = 0;
        while(lpcbData > y++)
        {
         if(lpByte[y] == '\0') lpByte[y] = ' '; /* lpByte[y] = '\r' - dla zachowania układu listy */
        }
        DataValue = Trim((String)lpByte);
       }

       switch(lpType)
       {
        case 9:  DataType = "REG_QWORD"; break;
        case 10: DataType = "REG_QWORD_LITTLE_ENDIAN"; break;
       }
      }

      RegCloseKey(hqKey);
     }
     break;
    }
    case rdString:       DataType = "REG_SZ"; break;
    case rdBinary:       DataType = "REG_BINARY"; break;
    case rdInteger:
    {
     DataType = "REG_DWORD";
     int iVal = DataValue.ToIntDef(0);
     DataValue = StringReplace(Rejestr->GetDataAsString(ValueName, true),
                 "dword:", "0x", TReplaceFlags() << rfReplaceAll)
                 + " (" + (String)iVal + ")";
     break;
    }
    case rdExpandString: DataType = "REG_EXPAND_SZ"; break;
   }

   TListItem * ElementListy = ListView->Items->Add();
   ElementListy->Caption = ValueName;
   ElementListy->SubItems->Add(DataType);
   ElementListy->SubItems->Add(DataValue);
  }

  delete Rejestr;
}