mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
260 lines
5.2 KiB
C++
260 lines
5.2 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Nestopia - NES/Famicom emulator written in C++
|
|
//
|
|
// Copyright (C) 2003-2008 Martin Freij
|
|
//
|
|
// This file is part of Nestopia.
|
|
//
|
|
// Nestopia is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Nestopia is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Nestopia; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "NstCollectionVector.hpp"
|
|
#include "NstSystemRegistry.hpp"
|
|
#include <Shlwapi.h>
|
|
#include <ShlObj.h>
|
|
|
|
#if NST_MSVC
|
|
#pragma comment(lib,"shlwapi")
|
|
#endif
|
|
|
|
namespace Nestopia
|
|
{
|
|
namespace System
|
|
{
|
|
struct Registry::Key::AutoKey
|
|
{
|
|
HKEY handle;
|
|
|
|
AutoKey()
|
|
: handle(NULL) {}
|
|
|
|
~AutoKey()
|
|
{
|
|
if (handle)
|
|
::RegCloseKey( handle );
|
|
}
|
|
};
|
|
|
|
void Registry::UpdateAssociations()
|
|
{
|
|
::SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL );
|
|
}
|
|
|
|
bool Registry::Key::operator << (const GenericString dataName) const
|
|
{
|
|
NST_ASSERT( dataName.NullTerminated() );
|
|
|
|
{
|
|
HeapString tmp;
|
|
|
|
if ((*this >> tmp) && tmp == dataName)
|
|
return false;
|
|
}
|
|
|
|
long result;
|
|
|
|
AutoKey keys[MAX_STACK+1];
|
|
keys[0].handle = HKEY_CLASSES_ROOT;
|
|
|
|
for (uint i=0; i < count; ++i)
|
|
{
|
|
result = ::RegCreateKeyEx
|
|
(
|
|
keys[i].handle,
|
|
stack[i],
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
i+1 == count ? KEY_SET_VALUE : KEY_WRITE,
|
|
NULL,
|
|
&keys[i+1].handle,
|
|
NULL
|
|
);
|
|
|
|
if (result != ERROR_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
result = ::RegSetValueEx
|
|
(
|
|
keys[count].handle,
|
|
NULL,
|
|
0,
|
|
REG_SZ,
|
|
reinterpret_cast<const BYTE*>(dataName.Ptr()),
|
|
(dataName.Length() + 1) * sizeof(wchar_t)
|
|
);
|
|
|
|
if (result != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Registry::Key::operator >> (HeapString& string) const
|
|
{
|
|
string.Clear();
|
|
|
|
AutoKey keys[MAX_STACK+1];
|
|
keys[0].handle = HKEY_CLASSES_ROOT;
|
|
|
|
for (uint i=0; i < count; ++i)
|
|
{
|
|
const long result = ::RegOpenKeyEx
|
|
(
|
|
keys[i].handle,
|
|
stack[i],
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&keys[i+1].handle
|
|
);
|
|
|
|
if (result != ERROR_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
DWORD type = 0, size = 0;
|
|
|
|
if (::RegQueryValueEx( keys[count].handle, NULL, NULL, &type, NULL, &size ) != ERROR_SUCCESS || type != REG_SZ)
|
|
return false;
|
|
|
|
if (size <= 1)
|
|
return false;
|
|
|
|
string.Resize( (size-1) / sizeof(wchar_t) );
|
|
|
|
if (::RegQueryValueEx( keys[count].handle, NULL, NULL, NULL, reinterpret_cast<BYTE*>(string.Ptr()), &size ) != ERROR_SUCCESS)
|
|
{
|
|
string.Clear();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Registry::Key::Delete() const
|
|
{
|
|
long result;
|
|
|
|
AutoKey keys[MAX_STACK+1];
|
|
keys[0].handle = HKEY_CLASSES_ROOT;
|
|
|
|
const uint last = count - 1;
|
|
|
|
for (uint i=0; i < last; ++i)
|
|
{
|
|
result = ::RegOpenKeyEx
|
|
(
|
|
keys[i].handle,
|
|
stack[i],
|
|
0,
|
|
KEY_WRITE,
|
|
&keys[i+1].handle
|
|
);
|
|
|
|
if (result != ERROR_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
{
|
|
HeapString tmp;
|
|
|
|
if (!(*this >> tmp))
|
|
return false;
|
|
}
|
|
|
|
::SHDeleteKey( keys[last].handle, stack[last] );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Registry::Key::Delete(const GenericString dataName) const
|
|
{
|
|
NST_ASSERT( dataName.NullTerminated() );
|
|
|
|
long result;
|
|
|
|
AutoKey keys[MAX_STACK+1];
|
|
keys[0].handle = HKEY_CLASSES_ROOT;
|
|
|
|
for (uint i=0; i < count; ++i)
|
|
{
|
|
result = ::RegOpenKeyEx
|
|
(
|
|
keys[i].handle,
|
|
stack[i],
|
|
0,
|
|
KEY_WRITE|KEY_QUERY_VALUE,
|
|
&keys[i+1].handle
|
|
);
|
|
|
|
if (result != ERROR_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
enum {PAD_TO_CHECK_REAL_LENGTH = 1};
|
|
|
|
Collection::Vector<wchar_t> storedData( dataName.Length() + 1 + PAD_TO_CHECK_REAL_LENGTH );
|
|
|
|
for (uint i=0; ; ++i)
|
|
{
|
|
DWORD storedType;
|
|
wchar_t storedValue[NST_MAX(MAX_PATH+1,512)];
|
|
DWORD storedValueSize = sizeof(storedValue);
|
|
DWORD storedDataSize = storedData.Size() * sizeof(wchar_t);
|
|
|
|
result = ::RegEnumValue
|
|
(
|
|
keys[count].handle,
|
|
i,
|
|
storedValue,
|
|
&storedValueSize,
|
|
NULL,
|
|
&storedType,
|
|
reinterpret_cast<BYTE*>( storedData.Begin() ),
|
|
&storedDataSize
|
|
);
|
|
|
|
if (result != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if
|
|
(
|
|
storedType == REG_SZ &&
|
|
storedDataSize == (storedData.Size() - PAD_TO_CHECK_REAL_LENGTH) * sizeof(wchar_t) &&
|
|
std::memcmp( storedData.Ptr(), dataName.Ptr(), storedDataSize ) == 0
|
|
)
|
|
{
|
|
if (storedValueSize)
|
|
{
|
|
// not default, delete value only
|
|
::RegDeleteValue( keys[count].handle, storedValue );
|
|
}
|
|
else
|
|
{
|
|
// selected as default, delete whole key
|
|
::SHDeleteKey( keys[count-1].handle, stack[count-1] );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|