1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "nsWindowsRegKey.h"
13 #include "mozilla/Attributes.h"
15 //-----------------------------------------------------------------------------
17 // According to MSDN, the following limits apply (in characters excluding room
18 // for terminating null character):
19 #define MAX_KEY_NAME_LEN 255
20 #define MAX_VALUE_NAME_LEN 16383
22 class nsWindowsRegKey final
: public nsIWindowsRegKey
{
25 NS_DECL_NSIWINDOWSREGKEY
27 nsWindowsRegKey() : mKey(nullptr) {}
30 ~nsWindowsRegKey() { Close(); }
35 NS_IMPL_ISUPPORTS(nsWindowsRegKey
, nsIWindowsRegKey
)
38 nsWindowsRegKey::GetKey(HKEY
* aKey
) {
44 nsWindowsRegKey::SetKey(HKEY aKey
) {
50 nsWindowsRegKey::Close() {
59 nsWindowsRegKey::Open(uint32_t aRootKey
, const nsAString
& aPath
,
64 RegOpenKeyExW((HKEY
)(intptr_t)aRootKey
, PromiseFlatString(aPath
).get(), 0,
65 (REGSAM
)aMode
, &mKey
);
66 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
70 nsWindowsRegKey::Create(uint32_t aRootKey
, const nsAString
& aPath
,
75 LONG rv
= RegCreateKeyExW(
76 (HKEY
)(intptr_t)aRootKey
, PromiseFlatString(aPath
).get(), 0, nullptr,
77 REG_OPTION_NON_VOLATILE
, (REGSAM
)aMode
, nullptr, &mKey
, &disposition
);
78 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
82 nsWindowsRegKey::OpenChild(const nsAString
& aPath
, uint32_t aMode
,
83 nsIWindowsRegKey
** aResult
) {
84 if (NS_WARN_IF(!mKey
)) {
85 return NS_ERROR_NOT_INITIALIZED
;
88 nsCOMPtr
<nsIWindowsRegKey
> child
= new nsWindowsRegKey();
90 nsresult rv
= child
->Open((uintptr_t)mKey
, aPath
, aMode
);
100 nsWindowsRegKey::CreateChild(const nsAString
& aPath
, uint32_t aMode
,
101 nsIWindowsRegKey
** aResult
) {
102 if (NS_WARN_IF(!mKey
)) {
103 return NS_ERROR_NOT_INITIALIZED
;
106 nsCOMPtr
<nsIWindowsRegKey
> child
= new nsWindowsRegKey();
108 nsresult rv
= child
->Create((uintptr_t)mKey
, aPath
, aMode
);
113 child
.swap(*aResult
);
118 nsWindowsRegKey::GetChildCount(uint32_t* aResult
) {
119 if (NS_WARN_IF(!mKey
)) {
120 return NS_ERROR_NOT_INITIALIZED
;
125 RegQueryInfoKeyW(mKey
, nullptr, nullptr, nullptr, &numSubKeys
, nullptr,
126 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
127 if (rv
!= ERROR_SUCCESS
) {
128 return NS_ERROR_FAILURE
;
131 *aResult
= numSubKeys
;
136 nsWindowsRegKey::GetChildName(uint32_t aIndex
, nsAString
& aResult
) {
137 if (NS_WARN_IF(!mKey
)) {
138 return NS_ERROR_NOT_INITIALIZED
;
141 FILETIME lastWritten
;
143 wchar_t nameBuf
[MAX_KEY_NAME_LEN
+ 1];
144 DWORD nameLen
= sizeof(nameBuf
) / sizeof(nameBuf
[0]);
146 LONG rv
= RegEnumKeyExW(mKey
, aIndex
, nameBuf
, &nameLen
, nullptr, nullptr,
147 nullptr, &lastWritten
);
148 if (rv
!= ERROR_SUCCESS
) {
149 return NS_ERROR_NOT_AVAILABLE
; // XXX what's the best error code here?
152 aResult
.Assign(nameBuf
, nameLen
);
158 nsWindowsRegKey::HasChild(const nsAString
& aName
, bool* aResult
) {
159 if (NS_WARN_IF(!mKey
)) {
160 return NS_ERROR_NOT_INITIALIZED
;
163 // Check for the existence of a child key by opening the key with minimal
164 // rights. Perhaps there is a more efficient way to do this?
167 LONG rv
= RegOpenKeyExW(mKey
, PromiseFlatString(aName
).get(), 0,
168 STANDARD_RIGHTS_READ
, &key
);
170 if ((*aResult
= (rv
== ERROR_SUCCESS
&& key
))) {
178 nsWindowsRegKey::GetValueCount(uint32_t* aResult
) {
179 if (NS_WARN_IF(!mKey
)) {
180 return NS_ERROR_NOT_INITIALIZED
;
185 RegQueryInfoKeyW(mKey
, nullptr, nullptr, nullptr, nullptr, nullptr,
186 nullptr, &numValues
, nullptr, nullptr, nullptr, nullptr);
187 if (rv
!= ERROR_SUCCESS
) {
188 return NS_ERROR_FAILURE
;
191 *aResult
= numValues
;
196 nsWindowsRegKey::GetValueName(uint32_t aIndex
, nsAString
& aResult
) {
197 if (NS_WARN_IF(!mKey
)) {
198 return NS_ERROR_NOT_INITIALIZED
;
201 wchar_t nameBuf
[MAX_VALUE_NAME_LEN
];
202 DWORD nameLen
= sizeof(nameBuf
) / sizeof(nameBuf
[0]);
204 LONG rv
= RegEnumValueW(mKey
, aIndex
, nameBuf
, &nameLen
, nullptr, nullptr,
206 if (rv
!= ERROR_SUCCESS
) {
207 return NS_ERROR_NOT_AVAILABLE
; // XXX what's the best error code here?
210 aResult
.Assign(nameBuf
, nameLen
);
216 nsWindowsRegKey::HasValue(const nsAString
& aName
, bool* aResult
) {
217 if (NS_WARN_IF(!mKey
)) {
218 return NS_ERROR_NOT_INITIALIZED
;
221 LONG rv
= RegQueryValueExW(mKey
, PromiseFlatString(aName
).get(), 0, nullptr,
224 *aResult
= (rv
== ERROR_SUCCESS
);
229 nsWindowsRegKey::RemoveChild(const nsAString
& aName
) {
230 if (NS_WARN_IF(!mKey
)) {
231 return NS_ERROR_NOT_INITIALIZED
;
234 LONG rv
= RegDeleteKeyW(mKey
, PromiseFlatString(aName
).get());
236 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
240 nsWindowsRegKey::RemoveValue(const nsAString
& aName
) {
241 if (NS_WARN_IF(!mKey
)) {
242 return NS_ERROR_NOT_INITIALIZED
;
245 LONG rv
= RegDeleteValueW(mKey
, PromiseFlatString(aName
).get());
247 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
251 nsWindowsRegKey::GetValueType(const nsAString
& aName
, uint32_t* aResult
) {
252 if (NS_WARN_IF(!mKey
)) {
253 return NS_ERROR_NOT_INITIALIZED
;
256 LONG rv
= RegQueryValueExW(mKey
, PromiseFlatString(aName
).get(), 0,
257 (LPDWORD
)aResult
, nullptr, nullptr);
258 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
262 nsWindowsRegKey::ReadStringValue(const nsAString
& aName
, nsAString
& aResult
) {
263 if (NS_WARN_IF(!mKey
)) {
264 return NS_ERROR_NOT_INITIALIZED
;
269 const nsString
& flatName
= PromiseFlatString(aName
);
271 LONG rv
= RegQueryValueExW(mKey
, flatName
.get(), 0, &type
, nullptr, &size
);
272 if (rv
!= ERROR_SUCCESS
) {
273 return NS_ERROR_FAILURE
;
276 // This must be a string type in order to fetch the value as a string.
277 // We're being a bit forgiving here by allowing types other than REG_SZ.
278 if (type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
&& type
!= REG_MULTI_SZ
) {
279 return NS_ERROR_FAILURE
;
282 // The buffer size must be a multiple of 2.
284 return NS_ERROR_UNEXPECTED
;
292 // |size| may or may not include the terminating null character.
293 DWORD resultLen
= size
/ 2;
295 if (!aResult
.SetLength(resultLen
, mozilla::fallible
)) {
296 return NS_ERROR_OUT_OF_MEMORY
;
299 auto* begin
= aResult
.BeginWriting();
301 rv
= RegQueryValueExW(mKey
, flatName
.get(), 0, &type
, (LPBYTE
)begin
, &size
);
303 if (!aResult
.CharAt(resultLen
- 1)) {
304 // The string passed to us had a null terminator in the final position.
305 aResult
.Truncate(resultLen
- 1);
308 // Expand the environment variables if needed
309 if (type
== REG_EXPAND_SZ
) {
310 const nsString
& flatSource
= PromiseFlatString(aResult
);
311 resultLen
= ExpandEnvironmentStringsW(flatSource
.get(), nullptr, 0);
313 nsAutoString expandedResult
;
314 // |resultLen| includes the terminating null character
316 if (!expandedResult
.SetLength(resultLen
, mozilla::fallible
)) {
317 return NS_ERROR_OUT_OF_MEMORY
;
320 resultLen
= ExpandEnvironmentStringsW(
321 flatSource
.get(), expandedResult
.get(), resultLen
+ 1);
322 if (resultLen
<= 0) {
323 rv
= ERROR_UNKNOWN_FEATURE
;
327 aResult
= expandedResult
;
329 } else if (resultLen
== 1) {
330 // It apparently expands to nothing (just a null terminator).
335 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
339 nsWindowsRegKey::ReadIntValue(const nsAString
& aName
, uint32_t* aResult
) {
340 if (NS_WARN_IF(!mKey
)) {
341 return NS_ERROR_NOT_INITIALIZED
;
344 DWORD size
= sizeof(*aResult
);
345 LONG rv
= RegQueryValueExW(mKey
, PromiseFlatString(aName
).get(), 0, nullptr,
346 (LPBYTE
)aResult
, &size
);
347 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
351 nsWindowsRegKey::ReadInt64Value(const nsAString
& aName
, uint64_t* aResult
) {
352 if (NS_WARN_IF(!mKey
)) {
353 return NS_ERROR_NOT_INITIALIZED
;
356 DWORD size
= sizeof(*aResult
);
357 LONG rv
= RegQueryValueExW(mKey
, PromiseFlatString(aName
).get(), 0, nullptr,
358 (LPBYTE
)aResult
, &size
);
359 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
363 nsWindowsRegKey::ReadBinaryValue(const nsAString
& aName
, nsACString
& aResult
) {
364 if (NS_WARN_IF(!mKey
)) {
365 return NS_ERROR_NOT_INITIALIZED
;
369 LONG rv
= RegQueryValueExW(mKey
, PromiseFlatString(aName
).get(), 0, nullptr,
372 if (rv
!= ERROR_SUCCESS
) {
373 return NS_ERROR_FAILURE
;
381 if (!aResult
.SetLength(size
, mozilla::fallible
)) {
382 return NS_ERROR_OUT_OF_MEMORY
;
385 auto* begin
= aResult
.BeginWriting();
387 rv
= RegQueryValueExW(mKey
, PromiseFlatString(aName
).get(), 0, nullptr,
388 (LPBYTE
)begin
, &size
);
389 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
393 nsWindowsRegKey::WriteStringValue(const nsAString
& aName
,
394 const nsAString
& aValue
) {
395 if (NS_WARN_IF(!mKey
)) {
396 return NS_ERROR_NOT_INITIALIZED
;
399 // Need to indicate complete size of buffer including null terminator.
400 const nsString
& flatValue
= PromiseFlatString(aValue
);
402 LONG rv
= RegSetValueExW(mKey
, PromiseFlatString(aName
).get(), 0, REG_SZ
,
403 (const BYTE
*)flatValue
.get(),
404 (flatValue
.Length() + 1) * sizeof(char16_t
));
405 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
409 nsWindowsRegKey::WriteIntValue(const nsAString
& aName
, uint32_t aValue
) {
410 if (NS_WARN_IF(!mKey
)) {
411 return NS_ERROR_NOT_INITIALIZED
;
414 LONG rv
= RegSetValueExW(mKey
, PromiseFlatString(aName
).get(), 0, REG_DWORD
,
415 (const BYTE
*)&aValue
, sizeof(aValue
));
416 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
420 nsWindowsRegKey::WriteInt64Value(const nsAString
& aName
, uint64_t aValue
) {
421 if (NS_WARN_IF(!mKey
)) {
422 return NS_ERROR_NOT_INITIALIZED
;
425 LONG rv
= RegSetValueExW(mKey
, PromiseFlatString(aName
).get(), 0, REG_QWORD
,
426 (const BYTE
*)&aValue
, sizeof(aValue
));
427 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
431 nsWindowsRegKey::WriteBinaryValue(const nsAString
& aName
,
432 const nsACString
& aValue
) {
433 if (NS_WARN_IF(!mKey
)) {
434 return NS_ERROR_NOT_INITIALIZED
;
437 const nsCString
& flatValue
= PromiseFlatCString(aValue
);
438 LONG rv
= RegSetValueExW(mKey
, PromiseFlatString(aName
).get(), 0, REG_BINARY
,
439 (const BYTE
*)flatValue
.get(), flatValue
.Length());
440 return (rv
== ERROR_SUCCESS
) ? NS_OK
: NS_ERROR_FAILURE
;
443 //-----------------------------------------------------------------------------
445 void NS_NewWindowsRegKey(nsIWindowsRegKey
** aResult
) {
446 RefPtr
<nsWindowsRegKey
> key
= new nsWindowsRegKey();
450 //-----------------------------------------------------------------------------
452 nsresult
nsWindowsRegKeyConstructor(const nsIID
& aIID
, void** aResult
) {
453 nsCOMPtr
<nsIWindowsRegKey
> key
;
454 NS_NewWindowsRegKey(getter_AddRefs(key
));
455 return key
->QueryInterface(aIID
, aResult
);