native-reg
Version:
Native in-process low-level windows registry access.
649 lines (481 loc) • 18.7 kB
Markdown
# `native-reg`
In-process native node module for Windows registry access. It includes prebuilt
binaries for Windows for x86 64-bit and 32-bit, and also ARM 64-bit (tested against
unofficial Node.js builds, [as it is not currently supported](https://github.com/nodejs/node/issues/25998)).
There are no fallbacks for other (future?) Windows targets, though requests are
welcome.
If not running on Windows, the module will not fail to load in order to simplify
cross-platform bundling, but it will assert if any of the functions are called.
## Example
```js
const reg = require('native-reg');
const key = reg.openKey(
reg.HKCU,
'Software\\MyCompany\\MySoftware',
reg.Access.ALL_ACCESS);
const version = reg.getValue(key, 'Install', 'Version');
if (isOldVersion(version)) {
reg.deleteTree(key, 'Install');
const installKey = reg.createKey(key, 'Install', reg.Access.ALL_ACCESS);
reg.setValueSZ(installKey, 'Version', newVersion);
// ...
reg.closeKey(installKey);
}
reg.closeKey(key);
```
## API
Read each API's linked Windows documentation for details on functionality and usage.
Contents:
- [Errors](#errors)
- [Constants](#constants):
- [`HKEY` enum](#hkey-enum)
- [Shorthands](#shorthands)
- [`isHKEY`](#ishkey)
- [`Access` enum](#access-enum)
- [`ValueType` enum](#valuetype-enum)
- [Raw APIs](#raw-apis):
- [`Value` type](#value-type)
- [`createKey`](#createkey)
- [`openKey`](#openkey)
- [`loadAppKey`](#loadappkey)
- [`openCurrentUser`](#opencurrentuser)
- [`enumKeyNames`](#enumkeynames)
- [`enumValueNames`](#enumvaluenames)
- [`queryValueRaw`](#queryvalueraw)
- [`getValueRaw`](#getvalueraw)
- [`setValueRaw`](#setvalueraw)
- [`renameKey`](#renamekey)
- [`copyTree`](#copytree)
- [`deleteKey`](#deletekey)
- [`deleteTree`](#deletetree)
- [`deleteKeyValue`](#deletekeyvalue)
- [`deleteValue`](#deletevalue)
- [`closeKey`](#closekey)
- [Format Helpers](#format-helpers)
- [`parseValue`](#parsevalue)
- [`parseString`](#parsestring)
- [`parseMultiString`](#parsemultistring)
- [`formatDWORD`](#formatdword)
- [`formatQWORD`](#formatqword)
- [Formatted value APIs](#formatted-value-apis)
- [`setValue{Type}`](#setvaluetype)
- [`getValue`](#getvalue)
- [`queryValue`](#queryvalue)
### Errors
The API initially validates the arguments with the standard node `assert` library:
```js
try {
// Should not be 'HKLM', but reg.HKLM or reg.HKEY.LOCAL_MACHINE
reg.openKey('HKLM', 'SOFTWARE\\Microsoft\\Windows', reg.Access.READ);
assert.fail();
} catch (e) {
assert(e instanceof require('assert').AssertionError);
}
```
If the wrapped Windows API returns an error, with a couple of exceptions for
commonly non-failure errors (e.g. key does not exist), are thrown as JS `Error`s
with the generic error message, e.g.: `Access is denied.`, but additional
standard `errno` and `syscall` properties, for example, a common error is trying
to use `Access.ALL_ACCESS` on `reg.HKLM`, which you need UAC elevation for:
```js
try {
// Assuming you are not running as administrator!
reg.openKey(reg.HKLM, 'SOFTWARE\\Microsoft\\Windows', reg.Access.ALL_ACCESS);
assert.fail();
} catch (e) {
assert.strictEqual(e.message, 'Access is denied.');
assert.strictEqual(e.errno, 5);
assert.strictEqual(e.syscall, 'RegOpenKeyExW');
}
```
### Constants
This library uses Typescript `enum`s for constants, this generates a
two way name <-> value mapping.
For example: `Access.SET_VALUE` is `0x0002`, and `Access[2]` is `"SET_VALUE"`.
#### `HKEY` enum
Exports the set of [predefined `HKEY`s](https://docs.microsoft.com/en-us/windows/win32/sysinfo/predefined-keys).
[`createKey`](#createkey), [`openKey`](#openkey), [`loadAppKey`](#loadappkey) and
[`openCurrentUser`](#opencurrentuser) will return other values for `HKEY`s,
which at the moment are objects with a single property `native` with the native
HKEY handle as a V8 `External` value, for use in other native packages, or `null`
after it is closed.
For these values you can call [`closeKey`](#closekey) once you are done to clean up
early, but they will be closed by the garbage collector if you chose not to.
```ts
export enum HKEY {
CLASSES_ROOT = 0x80000000,
CURRENT_USER = 0x80000001,
LOCAL_MACHINE = 0x80000002,
USERS = 0x80000003,
PERFORMANCE_DATA = 0x80000004,
PERFORMANCE_TEXT = 0x80000050,
PERFORMANCE_NLSTEXT = 0x80000060,
CURRENT_CONFIG = 0x80000005,
DYN_DATA = 0x80000006,
CURRENT_USER_LOCAL_SETTINGS = 0x80000007,
}
```
##### Shorthands
Also exports the standard shorthand HKEY names:
```ts
export const HKCR = HKEY.CLASSES_ROOT;
export const HKCU = HKEY.CURRENT_USER;
export const HKLM = HKEY.LOCAL_MACHINE;
export const HKU = HKEY.USERS;
```
##### `isHKEY`
Helper returns if the argument is a valid-looking `HKEY`. Most APIs will throw
an assertion error if `hkey` that does not return true for this is used.
Valid HKEY values are,
* The values of the [`HKEY` enum](#hkey-enum)
* Objects returned from [`createKey`](#createkey), [`openKey`](#openkey),
[`loadAppKey`](#loadappkey) and [`openCurrentUser`](#opencurrentuser)
* `External` values that represent HKEYs (for example, from another node
addon)
* Non-`0` 32-bit values that represent the pointer value of HKEYs
(for example, from another node addon) - not that this is unreliable on
64-bit applications, and should be avoided.
```ts
export function isHKEY(hkey: any): boolean;
```
#### `Access` enum
Specifies access checks for opened or created keys. Not always enforced for
opened keys:
> Certain registry operations perform access checks against the security descriptor of the key, not the access mask specified when the handle to the key was obtained. For example, even if a key is opened with a samDesired of KEY_READ, it can be used to create registry keys if the key's security descriptor permits. In contrast, the RegSetValueEx function specifically requires that the key be opened with the KEY_SET_VALUE access right.
```ts
// from https://docs.microsoft.com/en-nz/windows/desktop/SysInfo/registry-key-security-and-access-rights
export enum Access {
// Specific rights
QUERY_VALUE = 0x0001,
SET_VALUE = 0x0002,
CREATE_SUB_KEY = 0x0004,
ENUMERATE_SUB_KEYS = 0x0008,
NOTIFY = 0x0010,
CREATE_LINK = 0x0020,
// WOW64. See https://docs.microsoft.com/en-nz/windows/desktop/WinProg64/accessing-an-alternate-registry-view
WOW64_64KEY = 0x0100,
WOW64_32KEY = 0x0200,
// Generic rights.
READ = 0x2_0019,
WRITE = 0x2_0006,
EXECUTE = READ,
ALL_ACCESS = 0xF_003F,
}
```
#### `ValueType` enum
Types for registry values. See [documentation](https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types).
```ts
export enum ValueType {
NONE = 0, // No value type
SZ = 1, // Unicode nul terminated string
EXPAND_SZ = 2, // Unicode nul terminated string
// (with environment variable references)
BINARY = 3, // Free form binary
DWORD = 4, // 32-bit number
DWORD_LITTLE_ENDIAN = 4, // 32-bit number (same as REG_DWORD)
DWORD_BIG_ENDIAN = 5, // 32-bit number
LINK = 6, // Symbolic Link (unicode)
MULTI_SZ = 7, // Multiple Unicode strings
RESOURCE_LIST = 8, // Resource list in the resource map
FULL_RESOURCE_DESCRIPTOR = 9, // Resource list in the hardware description
RESOURCE_REQUIREMENTS_LIST = 10,
QWORD = 11, // 64-bit number
QWORD_LITTLE_ENDIAN = 11, // 64-bit number (same as REG_QWORD)
}
```
### Raw APIs
These APIs fairly directly wrap the Windows API linked, only abstracting some of
the allocation and general usage style.
The exception is [`enumKeyNames`](#enumkeynames) and [`enumValueNames`](#enumvaluenames)
which iterate to build a list and only return the names, and not other properties.
#### `Value` type
Raw registry values returned from [`queryValueRaw`](#queryvalueraw) and [`getValueRaw`](#getvalueraw)
are simply Node `Buffer`s with an additional `type` property from `ValueType`:
```ts
export type Value = Buffer & { type: ValueType };
```
#### `createKey`
Wraps [`RegCreateKeyExW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regcreatekeyexw)
> Creates the specified registry key. If the key already exists, the function opens it. Note that key names are not case sensitive.
You must call [`closeKey`](#closekey) on the result to clean up.
```ts
export function createKey(
hkey: HKEY,
subKey: string,
access: Access,
options: CreateKeyOptions = 0,
): HKEY;
export enum CreateKeyOptions {
NON_VOLATILE = 0,
VOLATILE = 1,
CREATE_LINK = 2,
BACKUP_RESTORE = 4,
}
```
#### `openKey`
Wraps [`RegOpenKeyExW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regopenkeyexw)
> Opens the specified registry key. Note that key names are not case sensitive.
Returns `null` if `subKey` does not exist under `hkey`.
You must call [`closeKey`](#closekey) on the result to clean up.
```ts
export function openKey(
hkey: HKEY,
subKey: string,
access: Access,
options: OpenKeyOptions = 0,
): HKEY | null;
export enum OpenKeyOptions {
OPEN_LINK = 8,
}
```
#### `loadAppKey`
Wraps [`RegLoadAppKeyW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regloadappkeyw)
> Loads the specified registry hive as an application hive.
You must call [`closeKey`](#closekey) on the result to clean up.
```ts
export function loadAppKey(
file: string,
access: Access,
): HKEY;
```
#### `openCurrentUser`
Wraps [`RegOpenCurrentUser`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regopencurrentuser)
> Retrieves a handle to the `HKEY_CURRENT_USER` key for the user the current thread is impersonating.
Only makes sense to use if you have access to Windows user impersonation. Maybe take a look at my
currently WIP [Windows user account package](https://github.com/simonbuchan/native-users-node).
You must call [`closeKey`](#closekey) on the result to clean up.
```ts
export function openCurrentUser(access: Access): HKEY;
```
#### `enumKeyNames`
Wraps [`RegEnumKeyExW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regenumkeyexw)
iterated to get the sub key names for a key.
> Enumerates the subkeys of the specified open registry key.
```ts
export function enumKeyNames(hkey: HKEY): string[];
```
#### `enumValueNames`
Wraps [`RegEnumValueW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regenumvaluew)
iterated to get the value names for a key.
> Enumerates the values for the specified open registry key.
```ts
export function enumValueNames(hkey: HKEY): string[];
```
#### `queryValueRaw`
Wraps [`RegQueryValueExW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regqueryvalueexw)
without additional parsing.
> Retrieves the type and data for the specified value name associated with an open registry key.
You may want to use [`queryValue`](#queryvalue) instead.
Returns `null` if `valueName` does not exist under `hkey`.
```ts
export function queryValueRaw(
hkey: HKEY,
valueName: string | null,
): Value | null;
```
#### `getValueRaw`
Wraps [`RegGetValueW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-reggetvaluew)
without additional parsing.
> Retrieves the type and data for the specified registry value.
You may want to use [`getValue`](#getvalue) instead.
Returns `null` if `subKey` or `valueName` does not exist under `hkey`.
```ts
export function getValueRaw(
hkey: HKEY,
subKey: string | null,
valueName: string | null,
flags: GetValueFlags = 0,
): Value | null;
export enum GetValueFlags {
RT_ANY = 0xffff,
RT_REG_NONE = 0x0001,
RT_REG_SZ = 0x0002,
RT_REG_EXPAND_SZ = 0x0004,
RT_REG_BINARY = 0x0008,
RT_REG_DWORD = 0x0010,
RT_REG_MULTI_SZ = 0x0020,
RT_REG_QWORD = 0x0040,
RT_DWORD = RT_REG_DWORD | RT_REG_BINARY,
RT_QWORD = RT_REG_QWORD | RT_REG_BINARY,
NO_EXPAND = 0x10000000,
// ZEROONFAILURE = 0x20000000, // doesn't make sense here
SUBKEY_WOW6464KEY = 0x00010000,
SUBKEY_WOW6432KEY = 0x00020000,
}
```
#### `setValueRaw`
Wraps [`RegSetValueExW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regsetvalueexw)
> Sets the data and type of a specified value under a registry key.
```ts
export function setValueRaw(
hkey: HKEY,
valueName: string | null,
valueType: ValueType,
data: Buffer,
): void;
```
#### `renameKey`
Wraps [`RegRenameKey`](https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regrenamekey)
> Changes the name of the specified registry key.
```ts
export function renameKey(
hkey: HKEY,
subKey: string | null,
newSubKey: string,
): void;
```
#### `copyTree`
Wraps [`RegCopyTreeW`](https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regcopytreew)
> Copies the specified registry key, along with its values and subkeys, to the specified destination key.
```ts
export function copyTree(
hkeySrc: HKEY,
subKey: string | null,
hkeyDest: HKEY,
): void;
```
#### `deleteKey`
Wraps [`RegDeleteKeyW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regdeletekeyw)
> Deletes a subkey and its values. Note that key names are not case sensitive.
Returns true if the key existed before it was deleted.
```ts
export function deleteKey(
hkey: HKEY,
subKey: string,
): boolean;
```
#### `deleteTree`
Wraps [`RegDeleteTreeW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regdeletetreew)
> Deletes the subkeys and values of the specified key recursively.
Returns true if the key existed before it was deleted.
```ts
export function deleteTree(
hkey: HKEY,
subKey: string | null,
): boolean;
```
#### `deleteKeyValue`
Wraps [`RegDeleteKeyValueW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regdeletekeyvaluew)
> Removes the specified value from the specified registry key and subkey.
Returns true if the value existed before it was deleted.
```ts
export function deleteKeyValue(
hkey: HKEY,
subKey: string,
valueName: string,
): boolean;
```
#### `deleteValue`
Wraps [`RegDeleteValueW`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regdeletevaluew)
> Removes a named value from the specified registry key. Note that value names are not case sensitive.
Returns true if the value existed before it was deleted.
```ts
export function deleteValue(
hkey: HKEY,
valueName: string | null,
): boolean;
```
#### `closeKey`
Wraps [`RegCloseKey`](https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regclosekey)
> Closes a handle to the specified registry key.
For convenience, `null` or `undefined` values are allowed and ignored.
```ts
export function closeKey(hkey: HKEY | null | undefined): void;
```
### Format helpers
#### `parseValue`
Returns the JS-native value for common `Value` types:
- `SZ`, `EXPAND_SZ` -> `string`
- `BINARY` -> `Buffer`
- `DWORD` / `DWORD_LITTLE_ENDIAN` -> `number`
- `DWORD_BIG_ENDIAN` -> `number`
- `MULTI_SZ` -> `string[]`
- `QWORD` / `QWORD_LITTLE_ENDIAN` -> `bigint`
Throws an assertion error if the type is not one of the above!
For convenience, passes through `null` so missing values don't have
to be specially treated.
```ts
export type ParsedValue = number | bigint | string | string[] | Buffer;
export function parseValue(value: Value | null): ParsedValue | null;
```
#### `parseString`
Parses `SZ` and `EXPAND_SZ` (etc.) registry values.
```ts
export function parseString(value: Buffer): string;
```
#### `parseMultiString`
Parses `MULTI_SZ` registry values.
```ts
export function parseMultiString(value: Buffer): string[];
```
#### `formatString`
Formats a string to `SZ`, `EXPAND_SZ` (etc.) format.
```ts
export function formatString(value: string): Buffer;
```
#### `formatMultiString`
Formats an array of `string`s to `MULTI_SZ` format.
```ts
export function formatMultiString(values: string[]): Buffer;
```
#### `formatDWORD`
Formats a `number` to `DWORD` / `DWORD_LITTLE_ENDIAN` format.
```ts
export function formatDWORD(value: number): Buffer;
```
#### `formatQWORD`
Formats a `number` or `bigint` to `QWORD` format.
```ts
export function formatQWORD(value: number | bigint): Buffer;
```
### Formatted value APIs
These APIs wrap the raw value APIs with the formatting helpers.
#### `setValue{Type}`
A set of wrappers that sets the registry value using [`setValueRaw`](#setvalueraw)
with the appropriate [`ValueType`](#valuetype-enum) and [format helper](#format-helpers).
For example, `setValueSZ` is `setValueRaw(hkey, valueName, ValueType.SZ, formatString(value))`.
```ts
export function setValueSZ(
hkey: HKEY,
valueName: string | null,
value: string,
): void;
export function setValueEXPAND_SZ(
hkey: HKEY,
valueName: string | null,
value: string,
): void;
export function setValueMULTI_SZ(
hkey: HKEY,
valueName: string | null,
value: string[],
): void;
export function setValueDWORD(
hkey: HKEY,
valueName: string | null,
value: number,
): void;
export function setValueQWORD(
hkey: HKEY,
valueName: string | null,
value: number | bigint,
): void;
```
#### `getValue`
Wraps [`getValueRaw`](#getvalueraw) in [`parseValue`](#parsevalue).
```ts
export function getValue(
hkey: HKEY,
subKey: string | null,
valueName: string | null,
flags: GetValueFlags = 0,
): ParsedValue | null;
```
#### `queryValue`
Wraps [`queryValueRaw`](#queryvalueraw) in [`parseValue`](#parsevalue).
```ts
export function queryValue(
hkey: HKEY,
valueName: string | null,
): ParsedValue | null;
```