Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jlib
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
jlib
Commits
c08333ef
Commit
c08333ef
authored
6 years ago
by
captainwong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update winreg
parent
73faa990
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1329 additions
and
5 deletions
+1329
-5
Registry.hpp
jlib/3rdparty/win32/Registry.hpp
+5
-5
WinReg.hpp
jlib/3rdparty/win32/WinReg.hpp
+1324
-0
No files found.
jlib/3rdparty/win32/Registry.hpp
View file @
c08333ef
...
@@ -437,7 +437,7 @@ inline std::wstring RegGetString(HKEY hKey, const std::wstring& subKey, const st
...
@@ -437,7 +437,7 @@ inline std::wstring RegGetString(HKEY hKey, const std::wstring& subKey, const st
}
}
//
//
// On return, RegGetValue() writes in dataSize the actual size of the string, in bytes.
// On return, RegGetValue
W
() writes in dataSize the actual size of the string, in bytes.
// We must resize the wstring object to the proper string size.
// We must resize the wstring object to the proper string size.
// Note that dataSize is expressed in bytes, and includes the terminating NUL; so we have to
// Note that dataSize is expressed in bytes, and includes the terminating NUL; so we have to
// subtract the NUL from the total string length, as wstring objects are already NUL-terminated.
// subtract the NUL from the total string length, as wstring objects are already NUL-terminated.
...
@@ -631,11 +631,11 @@ inline std::vector<std::pair<std::wstring, DWORD>> RegEnumValues(HKEY hKey)
...
@@ -631,11 +631,11 @@ inline std::vector<std::pair<std::wstring, DWORD>> RegEnumValues(HKEY hKey)
nullptr
// no data size
nullptr
// no data size
);
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegistryError
{
"Cannot enumerate values: RegEnumValue failed."
,
retCode
};
throw
RegistryError
{
"Cannot enumerate values: RegEnumValue
W
failed."
,
retCode
};
}
}
//
//
// On success, the RegEnumValue API writes the length of the
// On success, the RegEnumValue
W
API writes the length of the
// value name in the valueNameLen output parameter
// value name in the valueNameLen output parameter
// (not including the terminating NUL).
// (not including the terminating NUL).
// So we can build a wstring based on that length.
// So we can build a wstring based on that length.
...
@@ -714,11 +714,11 @@ inline std::vector<std::wstring> RegEnumSubKeys(HKEY hKey)
...
@@ -714,11 +714,11 @@ inline std::vector<std::wstring> RegEnumSubKeys(HKEY hKey)
nullptr
// no last write time
nullptr
// no last write time
);
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegistryError
{
"Cannot enumerate subkeys: RegEnumKeyEx failed."
,
retCode
};
throw
RegistryError
{
"Cannot enumerate subkeys: RegEnumKeyEx
W
failed."
,
retCode
};
}
}
//
//
// On success, the ::RegEnumKeyEx API writes the length of the
// On success, the ::RegEnumKeyEx
W
API writes the length of the
// subkey name in the subKeyNameLen output parameter
// subkey name in the subKeyNameLen output parameter
// (not including the terminating NUL).
// (not including the terminating NUL).
// So I can build a wstring based on that length.
// So I can build a wstring based on that length.
...
...
This diff is collapsed.
Click to expand it.
jlib/3rdparty/win32/WinReg.hpp
0 → 100644
View file @
c08333ef
#ifndef INCLUDE_GIOVANNI_DICANIO_WINREG_HPP
#define INCLUDE_GIOVANNI_DICANIO_WINREG_HPP
////////////////////////////////////////////////////////////////////////////////
//
// *** Modern C++ Wrappers Around Windows Registry C API ***
//
// Copyright (C) by Giovanni Dicanio
//
// First version: 2017, January 22nd
// Last update: 2017, August 9th
//
// E-mail: <giovanni.dicanio AT gmail.com>
//
// Registry key handles are safely and conveniently wrapped
// in the RegKey resource manager C++ class.
//
// Errors are signaled throwing exceptions of class RegException.
//
// Unicode UTF-16 strings are represented using the std::wstring class;
// ATL's CString is not used, to avoid dependencies from ATL or MFC.
//
// This is a header-only self-contained reusable module.
//
// Compiler: Visual Studio 2015
// Code compiles clean at /W4 on both 32-bit and 64-bit builds.
//
// ===========================================================================
//
// The MIT License(MIT)
//
// Copyright(c) 2017 Giovanni Dicanio
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h> // Windows Platform SDK
#include <crtdbg.h> // _ASSERTE
#include <memory> // std::unique_ptr
#include <stdexcept> // std::runtime_error
#include <string> // std::wstring
#include <utility> // std::swap, std::pair
#include <vector> // std::vector
namespace
winreg
{
//------------------------------------------------------------------------------
// Safe, efficient and convenient C++ wrapper around HKEY registry key handles.
//
// This class is movable but not copyable.
//
// This class is designed to be very *efficient* and low-overhead, for example:
// non-throwing operations are carefully marked as noexcept, so the C++ compiler
// can emit optimized code.
//
// Moreover, this class just wraps a raw HKEY handle, without any
// shared-ownership overhead like in std::shared_ptr; you can think of this
// class kind of like a std::unique_ptr for HKEYs.
//
// The class is also swappable (defines a custom non-member swap);
// relational operators are properly overloaded as well.
//------------------------------------------------------------------------------
class
RegKey
{
public
:
//
// Construction/Destruction
//
// Initialize as an empty key handle
RegKey
()
noexcept
=
default
;
// Take ownership of the input key handle
explicit
RegKey
(
HKEY
hKey
)
noexcept
;
// Open the given registry key if it exists, else create a new key.
// Uses default KEY_READ|KEY_WRITE access.
// For finer grained control, call the Create() method overloads.
// Throw RegException on failure.
RegKey
(
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
);
// Open the given registry key if it exists, else create a new key.
// Allow the caller to specify the desired access to the key (e.g. KEY_READ
// for read-only access).
// For finer grained control, call the Create() method overloads.
// Throw RegException on failure.
RegKey
(
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
REGSAM
desiredAccess
);
// Take ownership of the input key handle.
// The input key handle wrapper is reset to an empty state.
RegKey
(
RegKey
&&
other
)
noexcept
;
// Move-assign from the input key handle.
// Properly check against self-move-assign (which is safe and does nothing).
RegKey
&
operator
=
(
RegKey
&&
other
)
noexcept
;
// Ban copy
RegKey
(
const
RegKey
&
)
=
delete
;
RegKey
&
operator
=
(
const
RegKey
&
)
=
delete
;
// Safely close the wrapped key handle (if any)
~
RegKey
()
noexcept
;
//
// Properties
//
// Access the wrapped raw HKEY handle
HKEY
Get
()
const
noexcept
;
// Is the wrapped HKEY handle valid?
bool
IsValid
()
const
noexcept
;
// Same as IsValid(), but allow a short "if (regKey)" syntax
explicit
operator
bool
()
const
noexcept
;
// Is the wrapped handle a predefined handle (e.g.HKEY_CURRENT_USER) ?
bool
IsPredefined
()
const
noexcept
;
//
// Operations
//
// Close current HKEY handle.
// If there's no valid handle, do nothing.
// This method doesn't close predefined HKEY handles (e.g. HKEY_CURRENT_USER).
void
Close
()
noexcept
;
// Transfer ownership of current HKEY to the caller.
// Note that the caller is responsible for closing the key handle!
HKEY
Detach
()
noexcept
;
// Take ownership of the input HKEY handle.
// Safely close any previously open handle.
// Input key handle can be nullptr.
void
Attach
(
HKEY
hKey
)
noexcept
;
// Non-throwing swap;
// Note: There's also a non-member swap overload
void
SwapWith
(
RegKey
&
other
)
noexcept
;
//
// Wrappers around Windows Registry APIs.
// See the official MSDN documentation for these APIs for detailed explanations
// of the wrapper method parameters.
//
// Wrapper around RegCreateKeyEx, that allows you to specify desired access
void
Create
(
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
REGSAM
desiredAccess
=
KEY_READ
|
KEY_WRITE
);
// Wrapper around RegCreateKeyEx
void
Create
(
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
REGSAM
desiredAccess
,
DWORD
options
,
SECURITY_ATTRIBUTES
*
securityAttributes
,
DWORD
*
disposition
);
// Wrapper around RegOpenKeyExW
void
Open
(
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
REGSAM
desiredAccess
=
KEY_READ
|
KEY_WRITE
);
//
// Registry Value Setters
//
void
SetDwordValue
(
const
std
::
wstring
&
valueName
,
DWORD
data
);
void
SetQwordValue
(
const
std
::
wstring
&
valueName
,
const
ULONGLONG
&
data
);
void
SetStringValue
(
const
std
::
wstring
&
valueName
,
const
std
::
wstring
&
data
);
void
SetExpandStringValue
(
const
std
::
wstring
&
valueName
,
const
std
::
wstring
&
data
);
void
SetMultiStringValue
(
const
std
::
wstring
&
valueName
,
const
std
::
vector
<
std
::
wstring
>&
data
);
void
SetBinaryValue
(
const
std
::
wstring
&
valueName
,
const
std
::
vector
<
BYTE
>&
data
);
void
SetBinaryValue
(
const
std
::
wstring
&
valueName
,
const
void
*
data
,
DWORD
dataSize
);
//
// Registry Value Getters
//
DWORD
GetDwordValue
(
const
std
::
wstring
&
valueName
);
ULONGLONG
GetQwordValue
(
const
std
::
wstring
&
valueName
);
std
::
wstring
GetStringValue
(
const
std
::
wstring
&
valueName
);
enum
class
ExpandStringOption
{
DontExpand
,
Expand
};
std
::
wstring
GetExpandStringValue
(
const
std
::
wstring
&
valueName
,
ExpandStringOption
expandOption
=
ExpandStringOption
::
DontExpand
);
std
::
vector
<
std
::
wstring
>
GetMultiStringValue
(
const
std
::
wstring
&
valueName
);
std
::
vector
<
BYTE
>
GetBinaryValue
(
const
std
::
wstring
&
valueName
);
//
// Query Operations
//
void
QueryInfoKey
(
DWORD
&
subKeys
,
DWORD
&
values
,
FILETIME
&
lastWriteTime
);
// Return the DWORD type ID for the input registry value
DWORD
QueryValueType
(
const
std
::
wstring
&
valueName
);
// Enumerate the subkeys of the registry key, using RegEnumKeyExW
std
::
vector
<
std
::
wstring
>
EnumSubKeys
();
// Enumerate the values under the registry key, using RegEnumValueW.
// Returns a vector of pairs: In each pair, the wstring is the value name,
// the DWORD is the value type.
std
::
vector
<
std
::
pair
<
std
::
wstring
,
DWORD
>>
EnumValues
();
//
// Misc Registry API Wrappers
//
void
DeleteValue
(
const
std
::
wstring
&
valueName
);
void
DeleteKey
(
const
std
::
wstring
&
subKey
,
REGSAM
desiredAccess
);
void
FlushKey
();
void
LoadKey
(
const
std
::
wstring
&
subKey
,
const
std
::
wstring
&
filename
);
void
SaveKey
(
const
std
::
wstring
&
filename
,
SECURITY_ATTRIBUTES
*
securityAttributes
);
void
EnableReflectionKey
();
void
DisableReflectionKey
();
bool
QueryReflectionKey
();
void
ConnectRegistry
(
const
std
::
wstring
&
machineName
,
HKEY
hKeyPredefined
);
// Return a string representation of Windows registry types
static
std
::
wstring
RegTypeToString
(
DWORD
regType
);
//
// Relational comparison operators are overloaded as non-members
// ==, !=, <, <=, >, >=
//
private
:
// The wrapped registry key handle
HKEY
m_hKey
{
nullptr
};
};
//------------------------------------------------------------------------------
// An exception representing an error with the registry operations
//------------------------------------------------------------------------------
class
RegException
:
public
std
::
runtime_error
{
public
:
RegException
(
const
char
*
message
,
LONG
errorCode
)
:
std
::
runtime_error
{
message
}
,
m_errorCode
{
errorCode
}
{}
RegException
(
const
std
::
string
&
message
,
LONG
errorCode
)
:
std
::
runtime_error
{
message
}
,
m_errorCode
{
errorCode
}
{}
// Get the error code returned by Windows registry APIs
LONG
ErrorCode
()
const
noexcept
{
return
m_errorCode
;
}
private
:
// Error code, as returned by Windows registry APIs
LONG
m_errorCode
;
};
//------------------------------------------------------------------------------
// Overloads of relational comparison operators for RegKey
//------------------------------------------------------------------------------
inline
bool
operator
==
(
const
RegKey
&
a
,
const
RegKey
&
b
)
noexcept
{
return
a
.
Get
()
==
b
.
Get
();
}
inline
bool
operator
!=
(
const
RegKey
&
a
,
const
RegKey
&
b
)
noexcept
{
return
a
.
Get
()
!=
b
.
Get
();
}
inline
bool
operator
<
(
const
RegKey
&
a
,
const
RegKey
&
b
)
noexcept
{
return
a
.
Get
()
<
b
.
Get
();
}
inline
bool
operator
<=
(
const
RegKey
&
a
,
const
RegKey
&
b
)
noexcept
{
return
a
.
Get
()
<=
b
.
Get
();
}
inline
bool
operator
>
(
const
RegKey
&
a
,
const
RegKey
&
b
)
noexcept
{
return
a
.
Get
()
>
b
.
Get
();
}
inline
bool
operator
>=
(
const
RegKey
&
a
,
const
RegKey
&
b
)
noexcept
{
return
a
.
Get
()
>=
b
.
Get
();
}
//------------------------------------------------------------------------------
// RegKey Inline Methods
//------------------------------------------------------------------------------
inline
RegKey
::
RegKey
(
const
HKEY
hKey
)
noexcept
:
m_hKey
{
hKey
}
{}
inline
RegKey
::
RegKey
(
const
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
)
{
Create
(
hKeyParent
,
subKey
);
}
inline
RegKey
::
RegKey
(
const
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
REGSAM
desiredAccess
)
{
Create
(
hKeyParent
,
subKey
,
desiredAccess
);
}
inline
RegKey
::
RegKey
(
RegKey
&&
other
)
noexcept
:
m_hKey
{
other
.
m_hKey
}
{
// Other doesn't own the handle anymore
other
.
m_hKey
=
nullptr
;
}
inline
RegKey
&
RegKey
::
operator
=
(
RegKey
&&
other
)
noexcept
{
// Prevent self-move-assign
if
((
this
!=
&
other
)
&&
(
m_hKey
!=
other
.
m_hKey
))
{
// Close current
Close
();
// Move from other (i.e. take ownership of other's raw handle)
m_hKey
=
other
.
m_hKey
;
other
.
m_hKey
=
nullptr
;
}
return
*
this
;
}
inline
RegKey
::~
RegKey
()
noexcept
{
// Release the owned handle (if any)
Close
();
}
inline
HKEY
RegKey
::
Get
()
const
noexcept
{
return
m_hKey
;
}
inline
void
RegKey
::
Close
()
noexcept
{
if
(
IsValid
())
{
// Do not call RegCloseKey on predefined keys
if
(
!
IsPredefined
())
{
::
RegCloseKey
(
m_hKey
);
}
// Avoid dangling references
m_hKey
=
nullptr
;
}
}
inline
bool
RegKey
::
IsValid
()
const
noexcept
{
return
m_hKey
!=
nullptr
;
}
inline
RegKey
::
operator
bool
()
const
noexcept
{
return
IsValid
();
}
inline
bool
RegKey
::
IsPredefined
()
const
noexcept
{
// Predefined keys
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836(v=vs.85).aspx
if
((
m_hKey
==
HKEY_CURRENT_USER
)
||
(
m_hKey
==
HKEY_LOCAL_MACHINE
)
||
(
m_hKey
==
HKEY_CLASSES_ROOT
)
||
(
m_hKey
==
HKEY_CURRENT_CONFIG
)
||
(
m_hKey
==
HKEY_CURRENT_USER_LOCAL_SETTINGS
)
||
(
m_hKey
==
HKEY_PERFORMANCE_DATA
)
||
(
m_hKey
==
HKEY_PERFORMANCE_NLSTEXT
)
||
(
m_hKey
==
HKEY_PERFORMANCE_TEXT
)
||
(
m_hKey
==
HKEY_USERS
))
{
return
true
;
}
return
false
;
}
inline
HKEY
RegKey
::
Detach
()
noexcept
{
HKEY
hKey
{
m_hKey
};
// We don't own the HKEY handle anymore
m_hKey
=
nullptr
;
// Transfer ownership to the caller
return
hKey
;
}
inline
void
RegKey
::
Attach
(
const
HKEY
hKey
)
noexcept
{
// Prevent self-attach
if
(
m_hKey
!=
hKey
)
{
// Close any open registry handle
Close
();
// Take ownership of the input hKey
m_hKey
=
hKey
;
}
}
inline
void
RegKey
::
SwapWith
(
RegKey
&
other
)
noexcept
{
// Enable ADL (not necessary in this case, but good practice)
using
std
::
swap
;
// Swap the raw handle members
swap
(
m_hKey
,
other
.
m_hKey
);
}
inline
void
swap
(
RegKey
&
a
,
RegKey
&
b
)
noexcept
{
a
.
SwapWith
(
b
);
}
inline
void
RegKey
::
Create
(
const
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
const
REGSAM
desiredAccess
)
{
constexpr
DWORD
kDefaultOptions
=
REG_OPTION_NON_VOLATILE
;
Create
(
hKeyParent
,
subKey
,
desiredAccess
,
kDefaultOptions
,
nullptr
,
// no security attributes,
nullptr
// no disposition
);
}
inline
void
RegKey
::
Create
(
const
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
const
REGSAM
desiredAccess
,
const
DWORD
options
,
SECURITY_ATTRIBUTES
*
const
securityAttributes
,
DWORD
*
const
disposition
)
{
HKEY
hKey
{
nullptr
};
LONG
retCode
=
::
RegCreateKeyExW
(
hKeyParent
,
subKey
.
c_str
(),
0
,
// reserved
REG_NONE
,
// user-defined class type parameter not supported
options
,
desiredAccess
,
securityAttributes
,
&
hKey
,
disposition
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegCreateKeyEx failed."
,
retCode
};
}
// Safely close any previously opened key
Close
();
// Take ownership of the newly created key
m_hKey
=
hKey
;
}
inline
void
RegKey
::
Open
(
const
HKEY
hKeyParent
,
const
std
::
wstring
&
subKey
,
const
REGSAM
desiredAccess
)
{
HKEY
hKey
{
nullptr
};
LONG
retCode
=
::
RegOpenKeyExW
(
hKeyParent
,
subKey
.
c_str
(),
REG_NONE
,
// default options
desiredAccess
,
&
hKey
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegOpenKeyExW failed."
,
retCode
};
}
// Safely close any previously opened key
Close
();
// Take ownership of the newly created key
m_hKey
=
hKey
;
}
inline
void
RegKey
::
SetDwordValue
(
const
std
::
wstring
&
valueName
,
const
DWORD
data
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_DWORD
,
reinterpret_cast
<
const
BYTE
*>
(
&
data
),
sizeof
(
data
)
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write DWORD value: RegSetValueExW failed."
,
retCode
};
}
}
inline
void
RegKey
::
SetQwordValue
(
const
std
::
wstring
&
valueName
,
const
ULONGLONG
&
data
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_QWORD
,
reinterpret_cast
<
const
BYTE
*>
(
&
data
),
sizeof
(
data
)
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write QWORD value: RegSetValueExW failed."
,
retCode
};
}
}
inline
void
RegKey
::
SetStringValue
(
const
std
::
wstring
&
valueName
,
const
std
::
wstring
&
data
)
{
_ASSERTE
(
IsValid
());
// String size including the terminating NUL, in bytes
const
DWORD
dataSize
=
static_cast
<
DWORD
>
((
data
.
length
()
+
1
)
*
sizeof
(
wchar_t
));
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_SZ
,
reinterpret_cast
<
const
BYTE
*>
(
data
.
c_str
()),
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write string value: RegSetValueExW failed."
,
retCode
};
}
}
inline
void
RegKey
::
SetExpandStringValue
(
const
std
::
wstring
&
valueName
,
const
std
::
wstring
&
data
)
{
_ASSERTE
(
IsValid
());
// String size including the terminating NUL, in bytes
const
DWORD
dataSize
=
static_cast
<
DWORD
>
((
data
.
length
()
+
1
)
*
sizeof
(
wchar_t
));
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_EXPAND_SZ
,
reinterpret_cast
<
const
BYTE
*>
(
data
.
c_str
()),
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write expand string value: RegSetValueExW failed."
,
retCode
};
}
}
namespace
details
{
// Helper function to build a multi-string from a vector<wstring>
inline
std
::
vector
<
wchar_t
>
BuildMultiString
(
const
std
::
vector
<
std
::
wstring
>&
data
)
{
// Special case of the empty multi-string
if
(
data
.
empty
())
{
// Build a vector containing just two NULs
return
std
::
vector
<
wchar_t
>
(
2
,
L'\0'
);
}
// Get the total length in wchar_ts of the multi-string
size_t
totalLen
=
0
;
for
(
const
auto
&
s
:
data
)
{
// Add one to current string's length for the terminating NUL
totalLen
+=
(
s
.
length
()
+
1
);
}
// Add one for the last NUL terminator (making the whole structure double-NUL terminated)
totalLen
++
;
// Allocate a buffer to store the multi-string
std
::
vector
<
wchar_t
>
multiString
;
multiString
.
reserve
(
totalLen
);
// Copy the single strings into the multi-string
for
(
const
auto
&
s
:
data
)
{
multiString
.
insert
(
multiString
.
end
(),
s
.
begin
(),
s
.
end
());
// Don't forget to NUL-terminate the current string
multiString
.
push_back
(
L'\0'
);
}
// Add the last NUL-terminator
multiString
.
push_back
(
L'\0'
);
return
multiString
;
}
}
// namespace details
inline
void
RegKey
::
SetMultiStringValue
(
const
std
::
wstring
&
valueName
,
const
std
::
vector
<
std
::
wstring
>&
data
)
{
_ASSERTE
(
IsValid
());
// First, we have to build a double-NUL-terminated multi-string from the input data
const
std
::
vector
<
wchar_t
>
multiString
=
details
::
BuildMultiString
(
data
);
// Total size, in bytes, of the whole multi-string structure
const
DWORD
dataSize
=
static_cast
<
DWORD
>
(
multiString
.
size
()
*
sizeof
(
wchar_t
));
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_MULTI_SZ
,
reinterpret_cast
<
const
BYTE
*>
(
&
multiString
[
0
]),
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write multi-string value: RegSetValueExW failed."
,
retCode
};
}
}
inline
void
RegKey
::
SetBinaryValue
(
const
std
::
wstring
&
valueName
,
const
std
::
vector
<
BYTE
>&
data
)
{
_ASSERTE
(
IsValid
());
// Total data size, in bytes
const
DWORD
dataSize
=
static_cast
<
DWORD
>
(
data
.
size
());
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_BINARY
,
&
data
[
0
],
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write binary data value: RegSetValueExW failed."
,
retCode
};
}
}
inline
void
RegKey
::
SetBinaryValue
(
const
std
::
wstring
&
valueName
,
const
void
*
const
data
,
const
DWORD
dataSize
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegSetValueExW
(
m_hKey
,
valueName
.
c_str
(),
0
,
// reserved
REG_BINARY
,
static_cast
<
const
BYTE
*>
(
data
),
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot write binary data value: RegSetValueExW failed."
,
retCode
};
}
}
inline
DWORD
RegKey
::
GetDwordValue
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
DWORD
data
{};
// to be read from the registry
DWORD
dataSize
=
sizeof
(
data
);
// size of data, in bytes
const
DWORD
flags
=
RRF_RT_REG_DWORD
;
LONG
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
&
data
,
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get DWORD value: RegGetValueW failed."
,
retCode
};
}
return
data
;
}
inline
ULONGLONG
RegKey
::
GetQwordValue
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
ULONGLONG
data
{};
// to be read from the registry
DWORD
dataSize
=
sizeof
(
data
);
// size of data, in bytes
const
DWORD
flags
=
RRF_RT_REG_QWORD
;
LONG
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
&
data
,
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get QWORD value: RegGetValueW failed."
,
retCode
};
}
return
data
;
}
inline
std
::
wstring
RegKey
::
GetStringValue
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
// Get the size of the result string
DWORD
dataSize
=
0
;
// size of data, in bytes
const
DWORD
flags
=
RRF_RT_REG_SZ
;
LONG
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
nullptr
,
// output buffer not needed now
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get size of string value: RegGetValueW failed."
,
retCode
};
}
// Allocate a string of proper size.
// Note that dataSize is in bytes and includes the terminating NUL;
// we have to convert the size from bytes to wchar_ts for wstring::resize.
std
::
wstring
result
;
result
.
resize
(
dataSize
/
sizeof
(
wchar_t
));
// Call RegGetValueW for the second time to read the string's content
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
&
result
[
0
],
// output buffer
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get string value: RegGetValueW failed."
,
retCode
};
}
// Remove the NUL terminator scribbled by RegGetValueW from the wstring
result
.
resize
((
dataSize
/
sizeof
(
wchar_t
))
-
1
);
return
result
;
}
inline
std
::
wstring
RegKey
::
GetExpandStringValue
(
const
std
::
wstring
&
valueName
,
const
ExpandStringOption
expandOption
)
{
_ASSERTE
(
IsValid
());
DWORD
flags
=
RRF_RT_REG_EXPAND_SZ
;
// Adjust the flag for RegGetValueW considering the expand string option specified by the caller
if
(
expandOption
==
ExpandStringOption
::
DontExpand
)
{
flags
|=
RRF_NOEXPAND
;
}
// Get the size of the result string
DWORD
dataSize
=
0
;
// size of data, in bytes
LONG
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
nullptr
,
// output buffer not needed now
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get size of expand string value: RegGetValueW failed."
,
retCode
};
}
// Allocate a string of proper size.
// Note that dataSize is in bytes and includes the terminating NUL.
// We must convert from bytes to wchar_ts for wstring::resize.
std
::
wstring
result
;
result
.
resize
(
dataSize
/
sizeof
(
wchar_t
));
// Call RegGetValueW for the second time to read the string's content
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
&
result
[
0
],
// output buffer
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get expand string value: RegGetValueW failed."
,
retCode
};
}
// Remove the NUL terminator scribbled by RegGetValueW from the wstring
result
.
resize
((
dataSize
/
sizeof
(
wchar_t
))
-
1
);
return
result
;
}
inline
std
::
vector
<
std
::
wstring
>
RegKey
::
GetMultiStringValue
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
// Request the size of the multi-string, in bytes
DWORD
dataSize
=
0
;
const
DWORD
flags
=
RRF_RT_REG_MULTI_SZ
;
LONG
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
nullptr
,
// output buffer not needed now
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get size of multi-string value: RegGetValueW failed."
,
retCode
};
}
// Allocate room for the result multi-string.
// Note that dataSize is in bytes, but our vector<wchar_t>::resize method requires size
// to be expressed in wchar_ts.
std
::
vector
<
wchar_t
>
data
;
data
.
resize
(
dataSize
/
sizeof
(
wchar_t
));
// Read the multi-string from the registry into the vector object
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// no type required
&
data
[
0
],
// output buffer
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get multi-string value: RegGetValueW failed."
,
retCode
};
}
// Resize vector to the actual size returned by GetRegValue.
// Note that the vector is a vector of wchar_ts, instead the size returned by GetRegValue
// is in bytes, so we have to scale from bytes to wchar_t count.
data
.
resize
(
dataSize
/
sizeof
(
wchar_t
));
// Parse the double-NUL-terminated string into a vector<wstring>,
// which will be returned to the caller
std
::
vector
<
std
::
wstring
>
result
;
const
wchar_t
*
currStringPtr
=
&
data
[
0
];
while
(
*
currStringPtr
!=
L'\0'
)
{
// Current string is NUL-terminated, so get its length calling wcslen
const
size_t
currStringLength
=
wcslen
(
currStringPtr
);
// Add current string to the result vector
result
.
push_back
(
std
::
wstring
{
currStringPtr
,
currStringLength
});
// Move to the next string
currStringPtr
+=
currStringLength
+
1
;
}
return
result
;
}
inline
std
::
vector
<
BYTE
>
RegKey
::
GetBinaryValue
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
// Get the size of the binary data
DWORD
dataSize
=
0
;
// size of data, in bytes
const
DWORD
flags
=
RRF_RT_REG_BINARY
;
LONG
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
nullptr
,
// output buffer not needed now
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get size of binary data: RegGetValueW failed."
,
retCode
};
}
// Allocate a buffer of proper size to store the binary data
std
::
vector
<
BYTE
>
data
(
dataSize
);
// Call RegGetValueW for the second time to read the data content
retCode
=
::
RegGetValueW
(
m_hKey
,
nullptr
,
// no subkey
valueName
.
c_str
(),
flags
,
nullptr
,
// type not required
&
data
[
0
],
// output buffer
&
dataSize
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get binary data: RegGetValueW failed."
,
retCode
};
}
return
data
;
}
inline
DWORD
RegKey
::
QueryValueType
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
DWORD
typeId
{};
// will be returned by RegQueryValueExW
LONG
retCode
=
::
RegQueryValueExW
(
m_hKey
,
valueName
.
c_str
(),
nullptr
,
// reserved
&
typeId
,
nullptr
,
// not interested
nullptr
// not interested
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot get the value type: RegQueryValueExW failed."
,
retCode
};
}
return
typeId
;
}
inline
void
RegKey
::
QueryInfoKey
(
DWORD
&
subKeys
,
DWORD
&
values
,
FILETIME
&
lastWriteTime
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegQueryInfoKey
(
m_hKey
,
nullptr
,
nullptr
,
nullptr
,
&
subKeys
,
nullptr
,
nullptr
,
&
values
,
nullptr
,
nullptr
,
nullptr
,
&
lastWriteTime
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegQueryInfoKey failed."
,
retCode
};
}
}
inline
std
::
vector
<
std
::
wstring
>
RegKey
::
EnumSubKeys
()
{
_ASSERTE
(
IsValid
());
// Get some useful enumeration info, like the total number of subkeys
// and the maximum length of the subkey names
DWORD
subKeyCount
{};
DWORD
maxSubKeyNameLen
{};
LONG
retCode
=
::
RegQueryInfoKey
(
m_hKey
,
nullptr
,
// no user-defined class
nullptr
,
// no user-defined class size
nullptr
,
// reserved
&
subKeyCount
,
&
maxSubKeyNameLen
,
nullptr
,
// no subkey class length
nullptr
,
// no value count
nullptr
,
// no value name max length
nullptr
,
// no max value length
nullptr
,
// no security descriptor
nullptr
// no last write time
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegQueryInfoKey failed while preparing for subkey enumeration."
,
retCode
};
}
// NOTE: According to the MSDN documentation, the size returned for subkey name max length
// does *not* include the terminating NUL, so let's add +1 to take it into account
// when I allocate the buffer for reading subkey names.
maxSubKeyNameLen
++
;
// Preallocate a buffer for the subkey names
auto
nameBuffer
=
std
::
make_unique
<
wchar_t
[]
>
(
maxSubKeyNameLen
);
// The result subkey names will be stored here
std
::
vector
<
std
::
wstring
>
subkeyNames
;
// Enumerate all the subkeys
for
(
DWORD
index
=
0
;
index
<
subKeyCount
;
index
++
)
{
// Get the name of the current subkey
DWORD
subKeyNameLen
=
maxSubKeyNameLen
;
retCode
=
::
RegEnumKeyExW
(
m_hKey
,
index
,
nameBuffer
.
get
(),
&
subKeyNameLen
,
nullptr
,
// reserved
nullptr
,
// no class
nullptr
,
// no class
nullptr
// no last write time
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot enumerate subkeys: RegEnumKeyExW failed."
,
retCode
};
}
// On success, the ::RegEnumKeyExW API writes the length of the
// subkey name in the subKeyNameLen output parameter
// (not including the terminating NUL).
// So I can build a wstring based on that length.
subkeyNames
.
push_back
(
std
::
wstring
{
nameBuffer
.
get
(),
subKeyNameLen
});
}
return
subkeyNames
;
}
inline
std
::
vector
<
std
::
pair
<
std
::
wstring
,
DWORD
>>
RegKey
::
EnumValues
()
{
_ASSERTE
(
IsValid
());
// Get useful enumeration info, like the total number of values
// and the maximum length of the value names
DWORD
valueCount
{};
DWORD
maxValueNameLen
{};
LONG
retCode
=
::
RegQueryInfoKey
(
m_hKey
,
nullptr
,
// no user-defined class
nullptr
,
// no user-defined class size
nullptr
,
// reserved
nullptr
,
// no subkey count
nullptr
,
// no subkey max length
nullptr
,
// no subkey class length
&
valueCount
,
&
maxValueNameLen
,
nullptr
,
// no max value length
nullptr
,
// no security descriptor
nullptr
// no last write time
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegQueryInfoKey failed while preparing for value enumeration."
,
retCode
};
}
// NOTE: According to the MSDN documentation, the size returned for value name max length
// does *not* include the terminating NUL, so let's add +1 to take it into account
// when I allocate the buffer for reading value names.
maxValueNameLen
++
;
// Preallocate a buffer for the value names
auto
nameBuffer
=
std
::
make_unique
<
wchar_t
[]
>
(
maxValueNameLen
);
// The value names and types will be stored here
std
::
vector
<
std
::
pair
<
std
::
wstring
,
DWORD
>>
valueInfo
;
// Enumerate all the values
for
(
DWORD
index
=
0
;
index
<
valueCount
;
index
++
)
{
// Get the name and the type of the current value
DWORD
valueNameLen
=
maxValueNameLen
;
DWORD
valueType
{};
retCode
=
::
RegEnumValueW
(
m_hKey
,
index
,
nameBuffer
.
get
(),
&
valueNameLen
,
nullptr
,
// reserved
&
valueType
,
nullptr
,
// no data
nullptr
// no data size
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"Cannot enumerate values: RegEnumValueW failed."
,
retCode
};
}
// On success, the RegEnumValueW API writes the length of the
// value name in the valueNameLen output parameter
// (not including the terminating NUL).
// So we can build a wstring based on that.
valueInfo
.
push_back
(
std
::
make_pair
(
std
::
wstring
{
nameBuffer
.
get
(),
valueNameLen
},
valueType
)
);
}
return
valueInfo
;
}
inline
void
RegKey
::
DeleteValue
(
const
std
::
wstring
&
valueName
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegDeleteValueW
(
m_hKey
,
valueName
.
c_str
());
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegDeleteValueW failed."
,
retCode
};
}
}
inline
void
RegKey
::
DeleteKey
(
const
std
::
wstring
&
subKey
,
const
REGSAM
desiredAccess
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegDeleteKeyExW
(
m_hKey
,
subKey
.
c_str
(),
desiredAccess
,
0
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegDeleteKeyExW failed."
,
retCode
};
}
}
inline
void
RegKey
::
FlushKey
()
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegFlushKey
(
m_hKey
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegFlushKey failed."
,
retCode
};
}
}
inline
void
RegKey
::
LoadKey
(
const
std
::
wstring
&
subKey
,
const
std
::
wstring
&
filename
)
{
Close
();
LONG
retCode
=
::
RegLoadKeyW
(
m_hKey
,
subKey
.
c_str
(),
filename
.
c_str
());
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegLoadKeyW failed."
,
retCode
};
}
}
inline
void
RegKey
::
SaveKey
(
const
std
::
wstring
&
filename
,
SECURITY_ATTRIBUTES
*
const
securityAttributes
)
{
_ASSERTE
(
IsValid
());
LONG
retCode
=
::
RegSaveKeyW
(
m_hKey
,
filename
.
c_str
(),
securityAttributes
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegSaveKeyW failed."
,
retCode
};
}
}
inline
void
RegKey
::
EnableReflectionKey
()
{
LONG
retCode
=
::
RegEnableReflectionKey
(
m_hKey
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegEnableReflectionKey failed."
,
retCode
};
}
}
inline
void
RegKey
::
DisableReflectionKey
()
{
LONG
retCode
=
::
RegDisableReflectionKey
(
m_hKey
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegDisableReflectionKey failed."
,
retCode
};
}
}
inline
bool
RegKey
::
QueryReflectionKey
()
{
BOOL
isReflectionDisabled
=
FALSE
;
LONG
retCode
=
::
RegQueryReflectionKey
(
m_hKey
,
&
isReflectionDisabled
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegQueryReflectionKey failed."
,
retCode
};
}
return
(
isReflectionDisabled
?
true
:
false
);
}
inline
void
RegKey
::
ConnectRegistry
(
const
std
::
wstring
&
machineName
,
const
HKEY
hKeyPredefined
)
{
// Safely close any previously opened key
Close
();
HKEY
hKeyResult
{
nullptr
};
LONG
retCode
=
::
RegConnectRegistryW
(
machineName
.
c_str
(),
hKeyPredefined
,
&
hKeyResult
);
if
(
retCode
!=
ERROR_SUCCESS
)
{
throw
RegException
{
"RegConnectRegistryW failed."
,
retCode
};
}
// Take ownership of the result key
m_hKey
=
hKeyResult
;
}
inline
std
::
wstring
RegKey
::
RegTypeToString
(
const
DWORD
regType
)
{
switch
(
regType
)
{
case
REG_SZ
:
return
L"REG_SZ"
;
case
REG_EXPAND_SZ
:
return
L"REG_EXPAND_SZ"
;
case
REG_MULTI_SZ
:
return
L"REG_MULTI_SZ"
;
case
REG_DWORD
:
return
L"REG_DWORD"
;
case
REG_QWORD
:
return
L"REG_QWORD"
;
case
REG_BINARY
:
return
L"REG_BINARY"
;
default
:
return
L"Unknown/unsupported registry type"
;
}
}
}
// namespace winreg
#endif // INCLUDE_GIOVANNI_DICANIO_WINREG_HPP
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment