UNPKG

gpii-windows

Version:

Components of the GPII personalization infrastructure for use on Microsoft's "Windows" ™

718 lines (638 loc) 27.2 kB
/* * Windows Registry Settings Handler * * Copyright 2012, 2014 Raising the Floor - International * Copyright 2012 Antranig Basman * Copyright 2012 Astea Solutions AD * * Licensed under the New BSD license. You may not use this file except in * compliance with this License. * * The research leading to these results has received funding from the European Union's * Seventh Framework Programme (FP7/2007-2013) * under grant agreement no. 289016. * * You may obtain a copy of the License at * https://github.com/GPII/universal/blob/master/LICENSE.txt */ "use strict"; var ffi = require("ffi-napi"), ref = require("ref"), Struct = require("ref-struct"), fluid = require("gpii-universal"); require("../../WindowsUtilities/WindowsUtilities.js"); var gpii = fluid.registerNamespace("gpii"); var windows = fluid.registerNamespace("gpii.windows"); fluid.registerNamespace("gpii.windows.registrySettingsHandler"); var NULL = ref.NULL; /** * Pointer to ACL struct. * * This type is just for making more human readable working with pointers to ACL * structs. */ var ACLRef = ref.refType("void"); // Guide to node_ffi types and conversions: // https://github.com/rbranson/node-ffi/wiki/Node-FFI-Tutorial var advapi32 = new ffi.Library("advapi32", { // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724897(v=vs.85).aspx // HKEY, LPCWSTR, DWORD, REGSAM, PHKEY // Note abuse of type of argument 1 - node_ffi doesn't allow us to forge pointers from integers directly, // as required by base keys RegOpenKeyExW: [ "int32", ["uint32", "pointer", "uint32", "uint32", "pointer"] ], // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724837(v=vs.85).aspx // HKEY RegCloseKey: [ "long", ["uint32"] ], // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724911(v=vs.85).aspx // HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD RegQueryValueExW: [ "int32", ["uint32", "pointer", "pointer", "pointer", "pointer", "pointer"] ], // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724844(v=vs.85).aspx // HKEY, LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD // Similar abuse to RegOpenKeyExW RegCreateKeyExW: [ "long", ["uint32", "pointer", "uint32", "pointer", "uint32", "uint32", "pointer", "pointer", "pointer"] ], // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx // HKEY, LPCWSTR, DWORD, DWORD, const BYTE*, DWORD RegSetValueExW: [ "long", ["uint32", "pointer", "uint32", "uint32", "pointer", "uint32"] ], // https://msdn.microsoft.com/library/ms724847 // HKEY, LPCWSTR // Similar abuse to RegOpenKeyExW - for convenience, only accepts base keys RegDeleteKeyExW: [ "long", ["uint32", "pointer", "uint32", "ulong"] ], // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724851(v=vs.85).aspx // HKEY, LPCWSTR RegDeleteValueW: [ "long", ["uint32", "pointer"] ], // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724865(v=vs.85).aspx // HKEY, DWORD, LPTSTR, LPDWORD, LPDWORD, LPDWORD, LPBYTE, LPDWORD // Similar abuse to RegOpenKeyExW - for convenience, only accepts base keys RegEnumValueW: [ "int32", ["uint32", "uint32", "pointer", "pointer", "pointer", "pointer", "pointer", "pointer"] ], // https://docs.microsoft.com/es-es/windows/desktop/api/winreg/nf-winreg-reggetkeysecurity // HKEY, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, LPDWORD RegGetKeySecurity : [ "long", ["uint32", "uint32", "pointer", "uint32*"] ], // https://docs.microsoft.com/es-es/windows/desktop/api/winreg/nf-winreg-regsetkeysecurity // HKEY, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR RegSetKeySecurity: [ "long", ["uint32", "uint32", "pointer"] ], // https://docs.microsoft.com/en-us/windows/desktop/api/aclapi/nf-aclapi-setentriesinaclw // ULONG, PEXPLICIT_ACCESS_W, PACL, PACL SetEntriesInAclW: [ "uint32", ["ulong", "pointer", "pointer", "pointer"] ], // https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-initializesecuritydescriptor // PSECURITY_DESCRIPTOR, DWORD InitializeSecurityDescriptor: [ "bool", ["pointer", "uint32"] ], // https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-getsecuritydescriptordacl // PSECURITY_DESCRIPTOR, LPBOOL, PACL, LPBOOL GetSecurityDescriptorDacl: [ "bool", ["pointer", "bool*", "pointer", "bool*"] ], // https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl // PSECURITY_DESCRIPTOR, LPBOOL, PACL, LPBOOL SetSecurityDescriptorDacl: [ "bool", ["pointer", "bool", "pointer", "bool"] ], // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724865(v=vs.85).aspx // HKEY, DWORD, LPWSTR, LPDWORD, LPDWORD, LPWSTR, LPDWORD, PFILETIME // Similar abuse to RegOpenKeyExW - for convenience, only accepts base keys RegEnumKeyExW: [ "int32", ["uint32", "uint32", "pointer", "pointer", "int", "int", "int", "int"] ] }); var t = windows.types; /** * Structure that holds information to identify to which entities the permissions specified in the * ExplicitAccess should be applied to. * * Doc: https://docs.microsoft.com/en-us/windows/desktop/api/accctrl/ns-accctrl-_trustee_a */ windows.Trustee = new Struct([ ["pointer", "pMultipleTrustee"], [t.DWORD, "MultipleTrusteeOperation"], [t.DWORD, "TrusteeForm"], [t.DWORD, "TrusteeType"], ["pointer", "ptstrName"] ]); /** * Structure that holds the access control information for a security descriptor. * * Doc: https://docs.microsoft.com/en-us/windows/desktop/api/accctrl/ns-accctrl-_explicit_access_a */ windows.ExplicitAccess = new Struct([ [t.DWORD, "grfAccessPermissions"], [t.DWORD, "grfAccessMode"], [t.DWORD, "grfInheritance"], [windows.Trustee, "Trustee"] ]); // SECURITY_DESCRIPTOR Constants windows.securityDescriptorRevision = 1; // sizeof(SECURITY_DESCRIPTOR) windows.securityDescriptorSize = 48; // Minimal permissions required for accessing and modifying keys security information. windows.securityAccess = windows.accessTypes.READ_CONTROL | windows.accessTypes.WRITE_DAC; var cr = windows.checkReturnCode; windows.registryTypes = {}; windows.registryTypes.REG_SZ = { code: 1, readConvert: function (pointer) { return windows.fromWideChar(pointer); }, writeConvert: function (value) { return windows.toWideChar(value); } }; windows.registryTypes.REG_MULTI_SZ = { code: 7, readConvert: function (pointer) { return windows.stringFromWideCharArray(pointer); }, writeConvert: function (value) { var buffer = windows.stringToWideCharArray(value); return { pointer: buffer, length: buffer.length }; } }; windows.registryTypes.REG_DWORD = { code: 4, readConvert: function (pointer) { return pointer.readUInt32LE(0); }, writeConvert: function (value) { var pointer = new Buffer(4); pointer.writeUInt32LE(Number(value), 0); return { pointer: pointer, length: 4 }; } }; windows.registryTypes.REG_BINARY = { code: 3, readConvert: function (pointer, count) { return gpii.pointerToHex(pointer, count); }, writeConvert: function (value) { return gpii.hexToPointer(value); } }; var c = windows.API_constants; windows.getBaseKey = function (baseKey) { var key = c[baseKey]; if (key === undefined) { fluid.fail("Unknown registry base key " + baseKey); } return key; }; /** * Parses a registry key path, allowing to specify if the 32 or 64-bit view should be used instead of the one correct * for the processes. The view is specified by prefixing the real path with "32:" or "64:" (eg, "64:Software\GPII"). * Currently, this is only used when retrieving the MachineGuid. * * The return object contains the real path, and a value (KEY_WOW64_64KEY, KEY_WOW64_32KEY, or 0) to bitwise "or" with * the samDesired parameter of RegCreateKeyEx, * RegOpenKeyEx, or RegDeleteKeyEx. * * @param {String} path The path * @return {Object} Object containing the real path, and access mask. */ windows.parseRegistryPath = function (path) { var togo = { desiredAccess: 0, realPath: path }; // To explicitly use either the 32 or 64bit view, prepend the path with "32:" or "64:". if (path[2] === ":") { var bits = path.substr(0, 2); if (bits === "64") { togo.desiredAccess |= c.KEY_WOW64_64KEY; } else if (bits === "32") { togo.desiredAccess |= c.KEY_WOW64_32KEY; } togo.realPath = path.substr(3); } return togo; }; /** * Opens the given registy key. * @param {String} baseKey The name of the base key. One of HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, * or HKEY_CURRENT_CONFIG * @param {String} path Path to the key. * @param {Buffer} keyHolder Buffer in which the key handle is received. * @param {Number} extraRights [optional] Any additional access rights required (see https://docs.microsoft.com/windows/desktop/SysInfo/registry-key-security-and-access-rights) * @return {Object} undefined on success, or { statusCode: 404 } */ windows.openRegistryKey = function (baseKey, path, keyHolder, extraRights) { var regPath = windows.parseRegistryPath(path); var pathW = windows.ensureAlignment(windows.toWideChar(regPath.realPath).pointer); var base = windows.getBaseKey(baseKey); var desiredAccess = regPath.desiredAccess | c.KEY_QUERY_VALUE; if (extraRights) { desiredAccess |= extraRights; } var code = advapi32.RegOpenKeyExW(base, pathW, 0, desiredAccess, keyHolder); if (code === windows.API_constants.returnCodes.FILE_NOT_FOUND) { return { statusCode: 404 }; } cr(code); }; windows.closeRegistryKey = function (keyHolder) { var code4 = advapi32.RegCloseKey(keyHolder.readUInt32LE(0)); cr(code4); }; windows.readRegistryKey = function (baseKey, path, subKey, type) { var converter = windows.registryTypes[type]; if (!converter) { fluid.fail("Unsupported registry type " + type); } var togo = { statusCode: 200 }; var keyHolder = new Buffer(4); var openError = windows.openRegistryKey(baseKey, path, keyHolder); if (openError) { return openError; } try { var subKeyW = windows.ensureAlignment(windows.toWideChar(subKey).pointer); var dataLength = new Buffer(4); var code2 = advapi32.RegQueryValueExW(keyHolder.readUInt32LE(0), subKeyW, NULL, NULL, NULL, dataLength); if (code2 === windows.API_constants.returnCodes.FILE_NOT_FOUND) { togo.statusCode = 404; return togo; } cr(code2); togo.bytes = dataLength.readInt32LE(0); // Add an extra 2 bytes to ensure the return is always null terminated (numeric values will ignore it). var valueHolder = new Buffer(togo.bytes + 2); valueHolder.fill(0); var code3 = advapi32.RegQueryValueExW(keyHolder.readUInt32LE(0), subKeyW, NULL, NULL, valueHolder, dataLength); cr(code3); togo.value = converter.readConvert(valueHolder, togo.bytes); } finally { windows.closeRegistryKey(keyHolder); } return togo; }; /** * Initializes a new empty security descriptor. * * @return {Object} A Buffer holding a new empty security descriptor. */ windows.initializeSecurityDescriptor = function () { var newSecDes = Buffer.alloc(windows.securityDescriptorSize); var resCode = advapi32.InitializeSecurityDescriptor(newSecDes, windows.securityDescriptorRevision); if (resCode === 0) { fluid.fail("Error: Failed to initialize security descriptor."); } else { return newSecDes; } }; /** * Retrieves a buffer holding a pointer to a security descriptor DACL. * * @param {Buffer} secBuffer The containing the security descriptor. * @param {Buffer} isPresent The buffer for holding a flag that determines if the DACL is especified in the * security descriptor. * @param {Buffer} isDefaulted A buffer for holding a flag to get the source of the DACL. * @return {Buffer} A buffer holding a reference to the current DACL that the security descriptor owns. */ windows.getSecurityDescriptorDacl = function (secBuffer, isPresent, isDefaulted) { var oldACL = ref.alloc(ACLRef); var desDACLCode = advapi32.GetSecurityDescriptorDacl(secBuffer, isPresent, oldACL, isDefaulted); if (desDACLCode === 0) { fluid.fail(windows.win32errorText("Getting security descriptor DACL ", 0, 0)); } else { return oldACL; } }; /** * Sets a new ACL to the supplied security descriptor. * * @param {Buffer} secBuffer The buffer containing the security descriptor. * @param {Number} daclPresent Flag to indicate the presence of a DACL in the security descriptor. * @param {Buffer} aclRef Reference to a ACL structrue that specifies the DACL for the security descriptor. * @param {Number} daclDefaulted Flag that indicates the source of the DACL. */ windows.setSecurityDescriptorDacl = function (secBuffer, daclPresent, aclRef, daclDefaulted) { var resCode = advapi32.SetSecurityDescriptorDacl(secBuffer, daclPresent, aclRef.deref(), daclDefaulted); if (resCode === 0) { fluid.fail(windows.win32errorText("Setting security descriptor DACL ", 0, 0)); } }; /** * Receives the number of entries in the EXPLICIT_ACCESS struct, and solve the * * @param {Number} nEntries Number of entries of the list of EXPLICIT_ACCESS structs passed as second * parameter. * @param {Object} eaSt EXPLICIT_ACCESS structure specifying the access control information. * @param {Object} aclRef Pointer to the existing ACL structure which want to be updated. * @return {Object} A pointer to a new ACL structure combining the information of the parameters * 'aclRef' and 'eaSt'. */ windows.setEntriesInAclW = function (nEntries, eaSt, aclRef) { var newACL = ref.alloc(ACLRef); var newEntriesCode = advapi32.SetEntriesInAclW(nEntries, eaSt.ref(), aclRef.deref(), newACL); cr(newEntriesCode); return newACL; }; /** * Gets a registry key security descriptor. * * @param {Buffer} keyHolder A uint32 size buffer with the pointer to the registry key. * @param {Number} information A uint32 with the information to be retrieved from the registryKey. Supported values * can be found in the windows.securityInformation object. * @return {Buffer} A buffer holding the security descriptor that wanted to be retrieved. */ windows.regGetKeySecurity = function (keyHolder, information) { var secSize = Buffer.alloc(4); var secBuffer = Buffer.alloc(4); advapi32.RegGetKeySecurity(keyHolder.readUInt32LE(0), information, secBuffer, secSize); var secSizeVal = secSize.readUInt32LE(0); secBuffer = Buffer.alloc(secSizeVal); var keySecCode = advapi32.RegGetKeySecurity(keyHolder.readUInt32LE(0), information, secBuffer, secSize); cr(keySecCode); return secBuffer; }; /** * Sets a registry key security descriptor. * * @param {Buffer} keyHolder A uint32 size buffer with the pointer to the registry key. * @param {Number} information A uint32 with the information to be retrieved from the registryKey. Supported values * can be found in the windows.securityInformation object. * @param {Buffer} secBuffer A buffer holding the security descriptor that is going to be set in the registry key. */ windows.regSetKeySecurity = function (keyHolder, information, secBuffer) { var resCode = advapi32.RegSetKeySecurity(keyHolder.readUInt32LE(0), information, secBuffer); cr(resCode); }; /** * Writes the necessary permissions to a registry key, so it can be accessed by UWP applications. * * @param {Buffer} keyHolder A uint32 size buffer with the pointer to the registry key. */ windows.writeUwpSecurity = function (keyHolder) { var information = windows.securityInformation.DACL_SECURITY_INFORMATION; var secBuffer = windows.regGetKeySecurity(keyHolder, information); var isPresent = Buffer.alloc(4); var isDefaulted = Buffer.alloc(4); var oldACL = windows.getSecurityDescriptorDacl(secBuffer, isPresent, isDefaulted); var appAppPackages = "ALL APPLICATION PACKAGES"; var ea = new windows.ExplicitAccess(); ea.grfAccessPermissions = windows.accessTypes.GENERIC_READ; ea.grfAccessMode = windows.accessMode.SET_ACCESS; ea.grfInheritance = windows.inheritanceFlags.SUB_CONTAINERS_AND_OBJECTS_INHERIT; ea.Trustee.TrusteeForm = windows.trusteeForm.TRUSTEE_IS_NAME; ea.Trustee.TrusteeType = windows.trusteeType.TRUSTEE_IS_WELL_KNOWN_GROUP; ea.Trustee.ptstrName = windows.toWideChar(appAppPackages).pointer; var newACL = windows.setEntriesInAclW(1, ea, oldACL); var isPresentVal = isPresent.readInt8(); var isDefaultedVal = isDefaulted.readInt8(); var newSecDes = windows.initializeSecurityDescriptor(); windows.setSecurityDescriptorDacl(newSecDes, isPresentVal, newACL, isDefaultedVal); windows.regSetKeySecurity(keyHolder, information, newSecDes); windows.kernel32.LocalFree(newACL.deref()); }; /** * Writes a registry key. * * @param {String} baseKey The base registry key of the full key path. * @param {String} path The registry key path without the base key. * @param {String} subKey The name of the subkey that is going to be written. * @param {Object} value The value to be set in the subKey. * @param {String} type The type of the value that is going to be set. * @param {Boolean} uwpKey A flag indicating if the registry key should be created with special read permissions, so * UWP application can access them. * @return {Object} An object holding a field 'statusCode' with the error code * resulting from the operation. */ windows.writeRegistryKey = function (baseKey, path, subKey, value, type, uwpKey) { var converter = windows.registryTypes[type]; if (!converter) { fluid.fail("Unsupported registry type " + type); } var togo = { statusCode: 200 }; var regPath = windows.parseRegistryPath(path); var pathW = windows.ensureAlignment(windows.toWideChar(regPath.realPath).pointer); var keyHolder = new Buffer(4); var base = windows.getBaseKey(baseKey); var code = 0; if (uwpKey) { code = advapi32.RegCreateKeyExW( base, pathW, 0, NULL, 0, regPath.desiredAccess | c.KEY_SET_VALUE | windows.securityAccess, NULL, keyHolder, NULL ); } else { code = advapi32.RegCreateKeyExW( base, pathW, 0, NULL, 0, regPath.desiredAccess | c.KEY_SET_VALUE, NULL, keyHolder, NULL ); } cr(code); try { var subKeyW = windows.ensureAlignment(windows.toWideChar(subKey).pointer); var code2; if (value === undefined) { code2 = advapi32.RegDeleteValueW(keyHolder.readUInt32LE(0), subKeyW); } else { var converted = converter.writeConvert(value); code2 = advapi32.RegSetValueExW(keyHolder.readUInt32LE(0), subKeyW, 0, converter.code, converted.pointer, converted.length); } if (value === undefined && code2 === windows.API_constants.returnCodes.FILE_NOT_FOUND) { // Do not fail if delete was requested for nonexistent key return togo; } // TODO: consider plausible errors which might result from this process cr(code2); if (uwpKey) { windows.writeUwpSecurity(keyHolder); } } finally { advapi32.RegCloseKey(keyHolder.readUInt32LE(0)); } return togo; }; // Note that this function cannot delete keys recursively. RegDeleteKeyExW is not available // as a result of requirement for Windows XP level API support. This functionality can be // implemented manually on top of this existing API if required. // NB: This utility is currently used only to clean up state from within test cases windows.deleteRegistryKey = function (baseKey, path) { var regPath = windows.parseRegistryPath(path); var pathW = windows.ensureAlignment(windows.toWideChar(regPath.realPath).pointer); var base = windows.getBaseKey(baseKey); var code = advapi32.RegDeleteKeyExW(base, pathW, regPath.desiredAccess, 0); // Do not fail if delete was requested for nonexistent key if (code !== windows.API_constants.returnCodes.FILE_NOT_FOUND) { cr(code); } }; /** * Enumerates the values in a key. * * @param {String} baseKey The registry base key. * @param {String} path The key path. * @return {*} An object containing the name, data, type, and size of each value. */ windows.enumRegistryValues = function (baseKey, path) { var togo = {}; var keyHolder = new Buffer(4); var openError = windows.openRegistryKey(baseKey, path, keyHolder); if (openError) { return openError; } try { var maxLength = 0xffff; var nameLength = new Buffer(4); var typeHolder = new Buffer(4); var nameHolder = new Buffer(maxLength); var dataSizeHolder = new Buffer(maxLength); for (var index = 0; ; index++) { // Get the name, type, and data length of the next value. nameLength.writeUInt32LE(Number(maxLength), 0); var code2 = advapi32.RegEnumValueW(keyHolder.readUInt32LE(0), index, nameHolder, nameLength, NULL, typeHolder, NULL, dataSizeHolder); if (code2 === windows.API_constants.returnCodes.FILE_NOT_FOUND) { return togo; } else if (code2 === windows.API_constants.returnCodes.ERROR_NO_MORE_ITEMS) { break; } else { cr(code2); } var value = { name: windows.fromWideChar(nameHolder), bytes: dataSizeHolder.readInt32LE(0), type: null, data: null }; togo[value.name] = value; // Add an extra 2 bytes to ensure the return is always null terminated (numeric values will ignore it). var dataHolder = new Buffer(value.bytes + 2); dataHolder.fill(0); var code3 = advapi32.RegQueryValueExW(keyHolder.readUInt32LE(0), nameHolder, NULL, typeHolder, dataHolder, dataSizeHolder); cr(code3); // Get the type converter var typeCode = typeHolder.readUInt32LE(0); if (typeCode === 2) { // Cater for REG_EXPAND_SZ (RegGetValue should really have been used if expansion is required) typeCode = windows.registryTypes.REG_SZ.code; } var converter = null; for (var regType in windows.registryTypes) { if (windows.registryTypes.hasOwnProperty(regType) && windows.registryTypes[regType].code === typeCode) { converter = windows.registryTypes[regType]; value.type = regType; break; } } if (converter) { value.data = converter.readConvert(dataHolder, dataSizeHolder.readUInt32LE(0)); } } } finally { windows.closeRegistryKey(keyHolder); } return togo; }; /** * Enumerates the sub-keys in a key. * * @param {String} baseKey The registry base key. * @param {String} path The key path. * @return {Array<String>} An array of the names of keys contained in the given key. */ windows.enumRegistryKeys = function (baseKey, path) { var togo = []; var keyHolder = new Buffer(4); var openError = windows.openRegistryKey(baseKey, path, keyHolder, c.KEY_ENUMERATE_SUB_KEYS); if (openError) { return openError; } try { // Max key name is 255 characters (+1 for null terminator, x2 for wide chars) var maxLength = 0x200; var nameHolder = new Buffer(maxLength); var nameLength = ref.alloc(gpii.windows.types.DWORD); var index = 0; var code; do { nameLength.writeUInt32LE(Number(maxLength), 0); code = advapi32.RegEnumKeyExW(keyHolder.readUInt32LE(0), index, nameHolder, nameLength, 0, 0, 0, 0); if (code === 0) { togo.push(gpii.windows.fromWideChar(nameHolder)); index++; } else if (code !== windows.API_constants.returnCodes.ERROR_NO_MORE_ITEMS) { cr(code); } } while (code === 0); } finally { windows.closeRegistryKey(keyHolder); } return togo; }; windows.registrySettingsHandler.setImpl = function (payload) { var baseKey = payload.options.hKey; var path = payload.options.path; var dataTypes = payload.options.dataTypes; var uwpKey = payload.options.uwp; var results = fluid.transform(payload.settings, function (value, key) { if (dataTypes[key] === undefined) { fluid.fail("No registry dataType defined in options block for the setting " + key); } var dataType = dataTypes[key]; var oldValue = windows.readRegistryKey(baseKey, path, key, dataType); var writeStatus = windows.writeRegistryKey(baseKey, path, key, value, dataType, uwpKey); var newValue = windows.readRegistryKey(baseKey, path, key, dataType); return { oldValue: oldValue.value, statusCode: writeStatus.statusCode, newValue: newValue.value }; }); fluid.log("Registry settings handler SET returning results ", results); return results; }; windows.registrySettingsHandler.getImpl = function (payload) { var baseKey = payload.options.hKey; var path = payload.options.path; var dataTypes = payload.options.dataTypes; if (dataTypes === undefined) { fluid.fail("No registry dataTypes block defined in options. Full payload: " + JSON.stringify(payload, null, 4)); } var results = fluid.transform(payload.settings, function (value, key) { if (dataTypes[key] === undefined) { fluid.fail("No registry dataType defined in options block for the setting " + key); } var currentValue = windows.readRegistryKey(baseKey, path, key, dataTypes[key]); return currentValue.value; }); fluid.log("Registry settings handler GET returning results ", results); return results; }; windows.registrySettingsHandler.get = function (payload) { return gpii.settingsHandlers.invokeSettingsHandler(windows.registrySettingsHandler.getImpl, payload); }; windows.registrySettingsHandler.set = function (payload) { return gpii.settingsHandlers.invokeSettingsHandler(windows.registrySettingsHandler.setImpl, payload); };