registry.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,421 行 · 第 1/3 页

CPP
1,421
字号
            if ( m_dwLastError == ERROR_SUCCESS )
            {
                // check that it was the right type
                wxASSERT_MSG( !IsNumericValue(szValue),
                              wxT("Type mismatch in wxRegKey::QueryValue().") );

              return true;
            }
        }
    }

    wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
                  GetFullName(this, szValue));
    return false;
}

bool wxRegKey::SetValue(const wxChar *szValue, const wxString& strValue)
{
  if ( CONST_CAST Open() ) {
      m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_SZ,
                                    (RegString)strValue.c_str(),
                                    (strValue.Len() + 1)*sizeof(wxChar));
      if ( m_dwLastError == ERROR_SUCCESS )
        return true;
  }

  wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
                GetFullName(this, szValue));
  return false;
}

wxString wxRegKey::QueryDefaultValue() const
{
  wxString str;
  QueryValue(NULL, str);
  return str;
}

// ----------------------------------------------------------------------------
// enumeration
// NB: all these functions require an index variable which allows to have
//     several concurrently running indexations on the same key
// ----------------------------------------------------------------------------

bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
{
  if ( !Open(Read) )
    return false;

  lIndex = 0;
  return GetNextValue(strValueName, lIndex);
}

bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
{
  wxASSERT( IsOpened() );

  // are we already at the end of enumeration?
  if ( lIndex == -1 )
    return false;

    wxChar  szValueName[1024];                  // @@ use RegQueryInfoKey...
    DWORD dwValueLen = WXSIZEOF(szValueName);

    m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
                                 szValueName, &dwValueLen,
                                 RESERVED,
                                 NULL,            // [out] type
                                 NULL,            // [out] buffer for value
                                 NULL);           // [i/o]  it's length

    if ( m_dwLastError != ERROR_SUCCESS ) {
      if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
        m_dwLastError = ERROR_SUCCESS;
        lIndex = -1;
      }
      else {
        wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
                      GetName().c_str());
      }

      return false;
    }

    strValueName = szValueName;

  return true;
}

bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
{
  if ( !Open(Read) )
    return false;

  lIndex = 0;
  return GetNextKey(strKeyName, lIndex);
}

bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
{
  wxASSERT( IsOpened() );

  // are we already at the end of enumeration?
  if ( lIndex == -1 )
    return false;

  wxChar szKeyName[_MAX_PATH + 1];

#ifdef __WXWINCE__
  DWORD sizeName = WXSIZEOF(szKeyName);
  m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName,
      0, NULL, NULL, NULL);
#else
  m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
#endif

  if ( m_dwLastError != ERROR_SUCCESS ) {
    if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
      m_dwLastError = ERROR_SUCCESS;
      lIndex = -1;
    }
    else {
      wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
                    GetName().c_str());
    }

    return false;
  }

  strKeyName = szKeyName;
  return true;
}

// returns true if the value contains a number (else it's some string)
bool wxRegKey::IsNumericValue(const wxChar *szValue) const
{
    ValueType type = GetValueType(szValue);
    switch ( type ) {
        case Type_Dword:
        /* case Type_Dword_little_endian: == Type_Dword */
        case Type_Dword_big_endian:
            return true;

        default:
            return false;
    }
}

// ----------------------------------------------------------------------------
// exporting registry keys to file
// ----------------------------------------------------------------------------

#if wxUSE_STREAMS

// helper functions for writing ASCII strings (even in Unicode build)
static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch)
{
    ostr.PutC(ch);
    return ostr.IsOk();
}

static inline bool WriteAsciiEOL(wxOutputStream& ostr)
{
    // as we open the file in text mode, it is enough to write LF without CR
    return WriteAsciiChar(ostr, '\n');
}

static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p)
{
    return ostr.Write(p, strlen(p)).IsOk();
}

static inline bool WriteAsciiString(wxOutputStream& ostr, const wxString& s)
{
#if wxUSE_UNICODE
    wxCharBuffer name(s.mb_str());
    ostr.Write(name, strlen(name));
#else
    ostr.Write(s, s.length());
#endif

    return ostr.IsOk();
}

#endif // wxUSE_STREAMS

bool wxRegKey::Export(const wxString& filename) const
{
#if wxUSE_FFILE && wxUSE_STREAMS
    if ( wxFile::Exists(filename) )
    {
        wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."),
                   filename.c_str());
        return false;
    }

    wxFFileOutputStream ostr(filename, _T("w"));

    return ostr.Ok() && Export(ostr);
#else
    wxUnusedVar(filename);
    return false;
#endif
}

#if wxUSE_STREAMS
bool wxRegKey::Export(wxOutputStream& ostr) const
{
    // write out the header
    if ( !WriteAsciiString(ostr, "REGEDIT4\n\n") )
        return false;

    return DoExport(ostr);
}
#endif // wxUSE_STREAMS

static
wxString
FormatAsHex(const void *data,
            size_t size,
            wxRegKey::ValueType type = wxRegKey::Type_Binary)
{
    wxString value(_T("hex"));

    // binary values use just "hex:" prefix while the other ones must indicate
    // the real type
    if ( type != wxRegKey::Type_Binary )
        value << _T('(') << type << _T(')');
    value << _T(':');

    // write all the rest as comma-separated bytes
    value.reserve(3*size + 10);
    const char * const p = wx_static_cast(const char *, data);
    for ( size_t n = 0; n < size; n++ )
    {
        // TODO: line wrapping: although not required by regedit, this makes
        //       the generated files easier to read and compare with the files
        //       produced by regedit
        if ( n )
            value << _T(',');

        value << wxString::Format(_T("%02x"), (unsigned char)p[n]);
    }

    return value;
}

static inline
wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type)
{
    return FormatAsHex(value.c_str(), value.length() + 1, type);
}

wxString wxRegKey::FormatValue(const wxString& name) const
{
    wxString rhs;
    const ValueType type = GetValueType(name);
    switch ( type )
    {
        case Type_String:
            {
                wxString value;
                if ( !QueryValue(name, value) )
                    break;

                // quotes and backslashes must be quoted, linefeeds are not
                // allowed in string values
                rhs.reserve(value.length() + 2);
                rhs = _T('"');

                // there can be no NULs here
                bool useHex = false;
                for ( const wxChar *p = value.c_str(); *p && !useHex; p++ )
                {
                    switch ( *p )
                    {
                        case _T('\n'):
                            // we can only represent this string in hex
                            useHex = true;
                            break;

                        case _T('"'):
                        case _T('\\'):
                            // escape special symbol
                            rhs += _T('\\');
                            // fall through

                        default:
                            rhs += *p;
                    }
                }

                if ( useHex )
                    rhs = FormatAsHex(value, Type_String);
                else
                    rhs += _T('"');
            }
            break;

        case Type_Dword:
        /* case Type_Dword_little_endian: == Type_Dword */
            {
                long value;
                if ( !QueryValue(name, &value) )
                    break;

                rhs.Printf(_T("dword:%08x"), (unsigned int)value);
            }
            break;

        case Type_Expand_String:
        case Type_Multi_String:
            {
                wxString value;
                if ( !QueryRawValue(name, value) )
                    break;

                rhs = FormatAsHex(value, type);
            }
            break;

        case Type_Binary:
            {
                wxMemoryBuffer buf;
                if ( !QueryValue(name, buf) )
                    break;

                rhs = FormatAsHex(buf.GetData(), buf.GetDataLen());
            }
            break;

        // no idea how those appear in REGEDIT4 files
        case Type_None:
        case Type_Dword_big_endian:
        case Type_Link:
        case Type_Resource_list:
        case Type_Full_resource_descriptor:
        case Type_Resource_requirements_list:
        default:
            wxLogWarning(_("Can't export value of unsupported type %d."), type);
    }

    return rhs;
}

#if wxUSE_STREAMS

bool wxRegKey::DoExportValue(wxOutputStream& ostr, const wxString& name) const
{
    // first examine the value type: if it's unsupported, simply skip it
    // instead of aborting the entire export process because we failed to
    // export a single value
    wxString value = FormatValue(name);
    if ( value.empty() )
    {
        wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."),
                     name.c_str(), GetName().c_str());
        return true;
    }

    // we do have the text representation of the value, now write everything
    // out

    // special case: unnamed/default value is represented as just "@"
    if ( name.empty() )
    {
        if ( !WriteAsciiChar(ostr, '@') )
            return false;
    }
    else // normal, named, value
    {
        if ( !WriteAsciiChar(ostr, '"') ||
                !WriteAsciiString(ostr, name) ||
                    !WriteAsciiChar(ostr, '"') )
            return false;
    }

    if ( !WriteAsciiChar(ostr, '=') )
        return false;

    return WriteAsciiString(ostr, value) && WriteAsciiEOL(ostr);
}

bool wxRegKey::DoExport(wxOutputStream& ostr) const
{
    // write out this key name
    if ( !WriteAsciiChar(ostr, '[') )
        return false;

    if ( !WriteAsciiString(ostr, GetName(false /* no short prefix */)) )
        return false;

    if ( !WriteAsciiChar(ostr, ']') || !WriteAsciiEOL(ostr) )
        return false;

    // dump all our values
    long dummy;
    wxString name;
    wxRegKey& self = wx_const_cast(wxRegKey&, *this);
    bool cont = self.GetFirstValue(name, dummy);
    while ( cont )
    {
        if ( !DoExportValue(ostr, name) )
            return false;

        cont = GetNextValue(name, dummy);
    }

    // always terminate values by blank line, even if there were no values
    if ( !WriteAsciiEOL(ostr) )
        return false;

    // recurse to subkeys
    cont = self.GetFirstKey(name, dummy);
    while ( cont )
    {
        wxRegKey subkey(*this, name);
        if ( !subkey.DoExport(ostr) )
            return false;

        cont = GetNextKey(name, dummy);
    }

    return true;
}

#endif // wxUSE_STREAMS

// ============================================================================
// implementation of global private functions
// ============================================================================

bool KeyExists(WXHKEY hRootKey, const wxChar *szKey)
{
    // don't close this key itself for the case of empty szKey!
    if ( wxIsEmpty(szKey) )
        return true;

    HKEY hkeyDummy;
    if ( ::RegOpenKeyEx
         (
            (HKEY)hRootKey,
            szKey,
            RESERVED,
            KEY_READ,        // we might not have enough rights for rw access
            &hkeyDummy
         ) == ERROR_SUCCESS )
    {
        ::RegCloseKey(hkeyDummy);

        return true;
    }

    return false;
}

const wxChar *GetFullName(const wxRegKey *pKey, const wxChar *szValue)
{
  static wxString s_str;
  s_str = pKey->GetName();
  if ( !wxIsEmpty(szValue) )
    s_str << wxT("\\") << szValue;

  return s_str.c_str();
}

void RemoveTrailingSeparator(wxString& str)
{
  if ( !str.empty() && str.Last() == REG_SEPARATOR )
    str.Truncate(str.Len() - 1);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?