UNPKG

native-reg

Version:

Native in-process low-level windows registry access.

649 lines (481 loc) 18.7 kB
# `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; ```