{"id":2158,"date":"2015-11-09T15:34:28","date_gmt":"2015-11-09T15:34:28","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2015\/11\/09\/reading-and-writing-to-the-windows-registry-in-process-from-node-js\/"},"modified":"2020-03-18T15:28:03","modified_gmt":"2020-03-18T22:28:03","slug":"reading-and-writing-to-the-windows-registry-in-process-from-node-js","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/reading-and-writing-to-the-windows-registry-in-process-from-node-js\/","title":{"rendered":"Reading and Writing to the Windows Registry in-process from Node.js"},"content":{"rendered":"<p>A single npm module that enables Node developers to update the Windows Registry, create file associations, and much more!<\/p>\n<p>As cross-platform application developers, we often need the ability to update the Windows Registry when installing our applications on Windows. Common features requested by app developers include reading and writing keys to Windows registry, creating file associations to make Windows assign default programs to a file extension, elevating processes to run as an administrator, and last but not least doing all this within the same process as our application. This code story describes the development of a single npm module that enables Node developers to perform these commonly-requested operations when installing Node.js applications on Windows.<\/p>\n<h2 id=\"the-problem\">The Problem<\/h2>\n<p><a href=\"http:\/\/electron.atom.io\/\">Electron<\/a> is a framework that enables developers to build cross platform desktop apps with web technologies. Electron is behind Microsoft\u2019s Visual Studio Code, Slack\u2019s Apps, GitHub\u2019s Atom, Facebook\u2019s Nucleide, Docker\u2019s Kinematic, and <a href=\"https:\/\/github.com\/sindresorhus\/awesome-electron#example-apps\">a few others<\/a>. Prior to our hackathon with GitHub and Visual Studio Code, developers had limited number of resources to work with in order to interact with the Windows Registry. More importantly, there was <a href=\"https:\/\/github.com\/atom\/electron\/issues\/1530\">no library<\/a> that allowed developers to update the Windows Registry without running a separate shell script. In order to provide a great app install experience for users on Windows, it was obvious that we needed to create an NPM module that can address all these issues. Since this is an NPM module, all Node.js applications can take advantage of this library.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-11-09-NodeJS-Windows-Registry-npm.jpg\" alt=\"npm module for windows registry\" \/><\/p>\n<h2 id=\"overview-of-the-solution\">Overview of the Solution<\/h2>\n<p>We partnered with GitHub, the maintainer of Electron, and Visual Studio Code, to enable registry operations and file associations for Node application on Windows. As a result of our hackathon, there is now a <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\">NPM module for Windows Registry<\/a> you can include in your application to do just that.<\/p>\n<h3 id=\"interact-with-windows-apis\">Interact with Windows APIs<\/h3>\n<p>This library interacts with native Windows APIs. We leveraged the following node modules to enable Node.js application to communicate with Windows interfaces:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/ffi\">node-ffi<\/a> &#8211; A Node.js addon for loading and calling dynamic libraries using pure Javascript. It can be used to create bindings to native libraries without writing any C++ code. We used this module to load a list of Windows DLLs to call native Windows APIs.<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/ref\">ref<\/a> &#8211; A NPM module that turns buffer instances into pointers. We used this module to define our own data types to map to the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa383751(v=vs.85).aspx\">Windows data types<\/a>. It also conveniently allowed us to reference and dereference buffers.<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/ref-struct\">ref-struct<\/a> &#8211; This module allows us to define and implement structures. In order to communicate with Windows APIs, we needed to implement structs that mirror the inputs and outputs of Windows interfaces.<\/li>\n<\/ul>\n<p>We leveraged the following Windows DLLs to communicate with Windows APIs.<\/p>\n<ul>\n<li><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms724875(v=vs.85).aspx\">Advapi32.dll<\/a> &#8211; A Windows library that supports numerous APIs including many security and registry calls. We used this library to perform CRUD operations in Windows Registry.<\/li>\n<li><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/bb762154(v=vs.85).aspx\">Shell32.dll<\/a> &#8211; A Windows library that contains Windows Shell APIs, which are used to open processes on Windows. We used this library to elevate privilege of a process, similar to the experience of running an application as an administrator.<\/li>\n<\/ul>\n<p>Let\u2019s dive into the code!<\/p>\n<h3 id=\"creating-node-wrappers-for-windows-apis\">Creating Node Wrappers for Windows APIs<\/h3>\n<p>We created a Node wrapper <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\/blob\/master\/lib\/native\/adv_api.js\">adv_api.js<\/a> for <code class=\"highlighter-rouge\">Advapi32.dll<\/code> to support basic registry manipulation. Using the <code class=\"highlighter-rouge\">ffi<\/code> node module, we can load <code class=\"highlighter-rouge\">Advapi32.dll<\/code>. Then for each Windows API we wanted to call, we created a Javascript API with the expected inputs and outputs.<\/p>\n<p>In C++, the follow example illustrates the use of <code class=\"highlighter-rouge\">RegOpenCurrentUser<\/code>, which is used to retrieve a handle to the HKEY_CURRENT_USER key for the user that the current thread is impersonating.<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>HKEY keyCurrentUser;\r\nlResult = RegOpenCurrentUser(KEY_READ, &amp;keyCurrentUser);\r\n<\/code><\/pre>\n<\/div>\n<p>In our Node.js wrapper, we used the <code class=\"highlighter-rouge\">ffi<\/code> node module to load <code class=\"highlighter-rouge\">Advapi32.dll<\/code>. Then we defined the <code class=\"highlighter-rouge\">RegOpenCurrentUser<\/code> API and other Registry related APIs with their expected inputs and outputs.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">ffi<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'ffi'<\/span><span class=\"p\">);<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">advApi<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">ffi<\/span><span class=\"p\">.<\/span><span class=\"nx\">Library<\/span><span class=\"p\">(<\/span><span class=\"s1\">'Advapi32'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"na\">RegOpenCurrentUser<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">'uint64'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">REGSAM<\/span><span class=\"p\">,<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">PHKEY<\/span><span class=\"p\">]],<\/span>\r\n    <span class=\"na\">RegQueryValueExA<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">'uint64'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'string'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'pointer'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">LPDWORD<\/span><span class=\"p\">,<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">LPBYTE<\/span><span class=\"p\">,<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">LPDWORD<\/span><span class=\"p\">]],<\/span>\r\n    <span class=\"p\">...<\/span>\r\n\r\n<span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Similarly, we created a Node wrapper <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\/blob\/master\/lib\/native\/shell32.js\">shell32.js<\/a> for <code class=\"highlighter-rouge\">Shell32.dll<\/code>, which is used to launch a process on Windows.<\/p>\n<p>In C++, the following example illustrates the use of <code class=\"highlighter-rouge\">ShellExecuteEx<\/code> to launch an application:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>BOOL result = ShellExecuteExA(&amp;ShExecInfo);\r\n<\/code><\/pre>\n<\/div>\n<p>In our Node.js wrapper, we used the <code class=\"highlighter-rouge\">ffi<\/code> node module to load <code class=\"highlighter-rouge\">Shell32.dll<\/code>, then we defined the <code class=\"highlighter-rouge\">ShellExecuteExA<\/code> API with its expected input and output.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">ffi<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'ffi'<\/span><span class=\"p\">);<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">shell32<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">ffi<\/span><span class=\"p\">.<\/span><span class=\"nx\">Library<\/span><span class=\"p\">(<\/span><span class=\"s1\">'Shell32'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\r\n\r\n    <span class=\"na\">ShellExecuteExA<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">'bool'<\/span><span class=\"p\">,<\/span>  <span class=\"p\">[<\/span><span class=\"nx\">SHELLEXECUTEINFOPtr<\/span><span class=\"p\">]]<\/span>\r\n<span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h3 id=\"create-windows-data-types-in-javascript\">Create Windows Data Types in JavaScript<\/h3>\n<p>As you can see, in order to replicate the exact Windows API call in JavaScript, we needed to create the same function with the exact inputs and outputs of the same data type as the Windows native data types.<\/p>\n<p>For example, let\u2019s look at how we defined the data types for the <code class=\"highlighter-rouge\">ShellExecuteExA<\/code> function.<\/p>\n<p>In C++, here is the definition of the <code class=\"highlighter-rouge\">ShellExecuteEx<\/code> function:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>BOOL ShellExecuteExA(\r\n  _Inout_ SHELLEXECUTEINFO *pExecInfo\r\n);\r\n<\/code><\/pre>\n<\/div>\n<p>With the above definition, <code class=\"highlighter-rouge\">ShellExecuteEx<\/code> expects a parameter of the type <code class=\"highlighter-rouge\">SHELLEXECUTEINFO*<\/code>, which is a pointer to a <code class=\"highlighter-rouge\">SHELLEXECUTEINFO<\/code> structure that contains and receives information about the application being executed. It also has a return value of type <code class=\"highlighter-rouge\">BOOL<\/code>, which represents the result of executing this call.<\/p>\n<p>In C++, this is the definition of the <code class=\"highlighter-rouge\">SHELLEXECUTEINFO<\/code> structure.<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>typedef struct _SHELLEXECUTEINFO {\r\n  DWORD     cbSize;\r\n  ULONG     fMask;\r\n  HWND      hwnd;\r\n  LPCTSTR   lpVerb;\r\n  LPCTSTR   lpFile;\r\n  LPCTSTR   lpParameters;\r\n  LPCTSTR   lpDirectory;\r\n  int       nShow;\r\n  HINSTANCE hInstApp;\r\n  LPVOID    lpIDList;\r\n  LPCTSTR   lpClass;\r\n  HKEY      hkeyClass;\r\n  DWORD     dwHotKey;\r\n  union {\r\n    HANDLE hIcon;\r\n    HANDLE hMonitor;\r\n  } DUMMYUNIONNAME;\r\n  HANDLE    hProcess;\r\n} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;\r\n<\/code><\/pre>\n<\/div>\n<p>In our Node.js wrapper <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\/blob\/master\/lib\/windef.js\">windef.js<\/a>, we needed to create the same <code class=\"highlighter-rouge\">SHELLEXECUTEINFO<\/code> struct. Luckily, we had <code class=\"highlighter-rouge\">ref<\/code>, <code class=\"highlighter-rouge\">ref struct<\/code>, and <code class=\"highlighter-rouge\">ref union<\/code> node modules to help us create the same struct in Javascript.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"nx\">SHELLEXECUTEINFO<\/span><span class=\"err\">:<\/span> <span class=\"nx\">struct<\/span><span class=\"p\">({<\/span>\r\n        <span class=\"na\">cbSize<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">DWORD<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">fMask<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">ULONG<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">hwnd<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">HWND<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">lpVerb<\/span><span class=\"p\">:<\/span>  <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">STRING<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">lpFile<\/span><span class=\"p\">:<\/span>  <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">STRING<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">lpParameters<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">STRING<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">lpDirectory<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">STRING<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">nShow<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">INT<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">hInstApp<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">HINSTANCE<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">lpIDList<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">LPVOID<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">lpClass<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">STRING<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">hkeyClass<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">dwHotKey<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">DWORD<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">DUMMYUNIONNAME<\/span><span class=\"p\">:<\/span> <span class=\"nx\">DUMMYUNIONNAME<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">hProcess<\/span><span class=\"p\">:<\/span> <span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">HANDLE<\/span>\r\n    <span class=\"p\">})<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>For each struct member, we looked up its data type and its size from the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa383751(v=vs.85).aspx\">Windows Data Types reference<\/a>, then created the same data type with the same properties in <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\/blob\/master\/lib\/types.js\">types.js<\/a>. We leveraged the <code class=\"highlighter-rouge\">ref<\/code> node module to create types.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">ref<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'ref'<\/span><span class=\"p\">);<\/span>\r\n\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">types<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"na\">REGSAM<\/span><span class=\"p\">:<\/span> <span class=\"nx\">ref<\/span><span class=\"p\">.<\/span><span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">uint64<\/span><span class=\"p\">,<\/span>\r\n    <span class=\"na\">DWORD<\/span><span class=\"p\">:<\/span> <span class=\"nx\">ref<\/span><span class=\"p\">.<\/span><span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">uint32<\/span><span class=\"p\">,<\/span>\r\n    <span class=\"na\">ULONG<\/span><span class=\"p\">:<\/span> <span class=\"nx\">ref<\/span><span class=\"p\">.<\/span><span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">uint32<\/span><span class=\"p\">,<\/span>\r\n <span class=\"p\">...<\/span>\r\n\r\n<span class=\"p\">};<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Now that we have the <code class=\"highlighter-rouge\">SHELLEXECUTEINFO<\/code> struct in Javascript, we can create an instance of it in <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\/blob\/master\/lib\/utils.js\">utils.js<\/a> with the <code class=\"highlighter-rouge\">runas<\/code> ShellExecuteEx verb for the <code class=\"highlighter-rouge\">lpVerb<\/code> member and a file path to the process we want to launch for the <code class=\"highlighter-rouge\">lpFile<\/code> member. Let\u2019s call it <code class=\"highlighter-rouge\">shellexecuteinfoval<\/code>. This instance can then be used as a parameter of <code class=\"highlighter-rouge\">ShellExecuteExA<\/code> so that we can launch a process with elevated privilege.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">shellexecuteinfoval<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">SHELLEXECUTEINFO<\/span><span class=\"p\">({<\/span>\r\n            <span class=\"na\">cbSize<\/span><span class=\"p\">:<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">SHELLEXECUTEINFO<\/span><span class=\"p\">.<\/span><span class=\"nx\">size<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">fMask<\/span><span class=\"p\">:<\/span> <span class=\"mh\">0x00000000<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">hwnd<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">lpVerb<\/span><span class=\"p\">:<\/span> <span class=\"nx\">lpVerb<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">lpFile<\/span><span class=\"p\">:<\/span> <span class=\"nx\">filepath<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">lpParameters<\/span><span class=\"p\">:<\/span> <span class=\"nx\">parameters<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">lpDirectory<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">nShow<\/span><span class=\"p\">:<\/span> <span class=\"nx\">SW_SHOWNORMAL<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">hInstApp<\/span><span class=\"p\">:<\/span> <span class=\"nx\">hInstApp<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">lpIDList<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">lpCLass<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">hkeyClass<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">dwHotKey<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n            <span class=\"na\">DUMMYUNIONNAME<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\r\n                <span class=\"na\">hIcon<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\r\n                <span class=\"na\">hMonitor<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span>\r\n            <span class=\"p\">},<\/span>\r\n            <span class=\"na\">hProcess<\/span><span class=\"p\">:<\/span> <span class=\"nx\">ref<\/span><span class=\"p\">.<\/span><span class=\"nx\">alloc<\/span><span class=\"p\">(<\/span><span class=\"nx\">types<\/span><span class=\"p\">.<\/span><span class=\"nx\">HANDLE<\/span><span class=\"p\">)<\/span>\r\n        <span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Let\u2019s call <code class=\"highlighter-rouge\">ShellExecuteExA<\/code> with a reference of our new parameter. We implemented this as an asynchronous call so that when the UAC (User Account Control) prompt is launched, the current process can continue to run without waiting on the user to respond.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"nx\">shell32<\/span><span class=\"p\">.<\/span><span class=\"nx\">ShellExecuteExA<\/span><span class=\"p\">.<\/span><span class=\"nx\">async<\/span><span class=\"p\">(<\/span><span class=\"nx\">shellexecuteinfoval<\/span><span class=\"p\">.<\/span><span class=\"nx\">ref<\/span><span class=\"p\">(),<\/span> <span class=\"nx\">callback<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>To wrap everything together, we created an API <code class=\"highlighter-rouge\">elevate<\/code> in our module that takes in a <code class=\"highlighter-rouge\">filepath<\/code> of the process you want to launch, its <code class=\"highlighter-rouge\">parameters<\/code> if any, and a callback to get the user\u2019s response to the UAC prompt.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"na\">elevate<\/span><span class=\"p\">:<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">filepath<\/span><span class=\"p\">,<\/span> <span class=\"nx\">parameters<\/span><span class=\"p\">,<\/span> <span class=\"nx\">callback<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"p\">...<\/span>\r\n    <span class=\"nx\">shell32<\/span><span class=\"p\">.<\/span><span class=\"nx\">ShellExecuteExA<\/span><span class=\"p\">.<\/span><span class=\"nx\">async<\/span><span class=\"p\">(<\/span><span class=\"nx\">shellexecuteinfoval<\/span><span class=\"p\">.<\/span><span class=\"nx\">ref<\/span><span class=\"p\">(),<\/span> <span class=\"nx\">callback<\/span><span class=\"p\">);<\/span>\r\n<span class=\"p\">}};<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>The process you want to launch with admin access will only be launched after the callback is called and only if the user clicks Yes in the UAC prompt. Otherwise, the process will not be launched. If the user is already running as an admin, the UAC prompt will not be triggered and the process you provided will be launched as an administrator automatically.<\/p>\n<p>Here is an example of this running:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"nx\">utils<\/span><span class=\"p\">.<\/span><span class=\"nx\">elevate<\/span><span class=\"p\">(<\/span><span class=\"s1\">'C:\\Program Files\\nodejs\\node.exe'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'index.js'<\/span><span class=\"p\">,<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">,<\/span> <span class=\"nx\">result<\/span><span class=\"p\">){<\/span><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"s1\">'callback'<\/span><span class=\"p\">);});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-11-09-NodeJS-Windows-Registry-elevate.gif\" alt=\"Elevate\" \/><\/p>\n<h2 id=\"enable-your-application\">Enable Your Application<\/h2>\n<p>To add the <a href=\"https:\/\/www.npmjs.com\/package\/windows-registry\">NPM module for Windows Registry<\/a> to your Node application, install the package:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>npm install windows-registry\r\n<\/code><\/pre>\n<\/div>\n<h3 id=\"installation\">Installation<\/h3>\n<p>To install node modules that require compilation on Windows, make sure you have installed the <a href=\"https:\/\/github.com\/nodejs\/node-gyp#installation\">necessary build tools<\/a>. Specifically, you need <code class=\"highlighter-rouge\">npm install -g node-gyp<\/code>, a cross-platform cli written in Node.js for native addon modules for Node.js.<\/p>\n<p>To install <code class=\"highlighter-rouge\">node-gyp<\/code>, you need to have the following prerequisites installed and configured in your development environment.<\/p>\n<ul>\n<li>Install <a href=\"http:\/\/www.python.org\/download\/releases\/2.7.3#download\">python v2.7.3<\/a>, and add it to your <code class=\"highlighter-rouge\">PATH<\/code>, <code class=\"highlighter-rouge\">npm config set python python2.7<\/code><\/li>\n<li>Install <a href=\"http:\/\/landinghub.visualstudio.com\/visual-cpp-build-tools\">VC++ Build Tools Technical Preview<\/a>. You do not need to install the full Visual Studio, only the build tools are required.\n<ul>\n<li>[Windows 7 only] requires <a href=\"http:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=40773\">.NET Framework 4.5.1<\/a><\/li>\n<\/ul>\n<\/li>\n<li>Launch cmd, <code class=\"highlighter-rouge\">npm config set msvs_version 2015 --global<\/code> (this is instead of <code class=\"highlighter-rouge\">npm install [package name] --msvs_version=2015<\/code> every time.)<\/li>\n<\/ul>\n<p>Once the prerequisites are installed, you should be able to do <code class=\"highlighter-rouge\">npm install -g node-gyp<\/code>.<\/p>\n<h3 id=\"reading-and-writing-to-the-windows-registry\">Reading and Writing to the Windows Registry<\/h3>\n<p>This library implements only a few of the basic registry commands, which allow you to do basic CRUD operations for keys in the registry.<\/p>\n<h4 id=\"opening-a-registry-key\">Opening a Registry Key<\/h4>\n<p>Registry keys can be opened by either opening a predefined registry key defined in the windef module:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">Key<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">Key<\/span><span class=\"p\">;<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">key<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Key<\/span><span class=\"p\">(<\/span><span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY_CLASSES_ROOT<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'.txt'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ACCESS<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ALL_ACCESS<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Or you can open a sub key from an already opened key:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">Key<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">Key<\/span><span class=\"p\">;<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">key<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Key<\/span><span class=\"p\">(<\/span><span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY_CLASSES_ROOT<\/span><span class=\"p\">,<\/span> <span class=\"s1\">''<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ACCESS<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ALL_ACCESS<\/span><span class=\"p\">);<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">key2<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">key<\/span><span class=\"p\">.<\/span><span class=\"nx\">openSubKey<\/span><span class=\"p\">(<\/span><span class=\"s1\">'.txt'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ACCESS<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ALL_ACCESS<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>And don\u2019t forget to close your key when you\u2019re done. Otherwise, you will leak native resources:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"nx\">key<\/span><span class=\"p\">.<\/span><span class=\"nx\">close<\/span><span class=\"p\">();<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h4 id=\"creating-a-key\">Creating a Key<\/h4>\n<p>Creating a key just requires that you have a Key object by either using the <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\/blob\/master\/lib\/windef.js#L27\">predefined keys<\/a> within the <code class=\"highlighter-rouge\">windef.HKEY<\/code> or opening a subkey from an existing key.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">Key<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">Key<\/span><span class=\"p\">;<\/span>\r\n<span class=\"c1\">\/\/ predefined key<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">key<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Key<\/span><span class=\"p\">(<\/span><span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY_CLASSES_ROOT<\/span><span class=\"p\">,<\/span> <span class=\"s1\">''<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ACCESS<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ALL_ACCESS<\/span><span class=\"p\">);<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">createdKey<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">key<\/span><span class=\"p\">.<\/span><span class=\"nx\">createSubKey<\/span><span class=\"p\">(<\/span><span class=\"s1\">'test_key_name'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ACCESS<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ALL_ACCESS<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h4 id=\"deleting-a-key\">Deleting a Key<\/h4>\n<p>To delete a key just call the <code class=\"highlighter-rouge\">Key.deleteKey()<\/code> function.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"nx\">createdKey<\/span><span class=\"p\">.<\/span><span class=\"nx\">deleteKey<\/span><span class=\"p\">();<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h4 id=\"writing-a-value-to-a-key\">Writing a Value to a Key<\/h4>\n<p>To write a value, you will again need a Key object and just need to call the <code class=\"highlighter-rouge\">Key.setValue<\/code> function:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">Key<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">Key<\/span><span class=\"p\">,<\/span>\r\n    <span class=\"nx\">windef<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">windef<\/span><span class=\"p\">;<\/span>\r\n\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">key<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Key<\/span><span class=\"p\">(<\/span><span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY<\/span><span class=\"p\">.<\/span><span class=\"nx\">HKEY_CLASSES_ROOT<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'.txt'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ACCESS<\/span><span class=\"p\">.<\/span><span class=\"nx\">KEY_ALL_ACCESS<\/span><span class=\"p\">);<\/span>\r\n<span class=\"nx\">key<\/span><span class=\"p\">.<\/span><span class=\"nx\">setValue<\/span><span class=\"p\">(<\/span><span class=\"s1\">'test_value_name'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">windef<\/span><span class=\"p\">.<\/span><span class=\"nx\">REG_VALUE_TYPE<\/span><span class=\"p\">.<\/span><span class=\"nx\">REG_SZ<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'test_value'<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h4 id=\"getting-a-value-from-a-key\">Getting a Value From a Key<\/h4>\n<p>To get a value from a key, just call <code class=\"highlighter-rouge\">Key.getValue<\/code>:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">value<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">key<\/span><span class=\"p\">.<\/span><span class=\"nx\">getValue<\/span><span class=\"p\">(<\/span><span class=\"s1\">'test_value_name'<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>The return value depends on the type of the key (REG_SZ for example will give you a string).<\/p>\n<h3 id=\"creating-file-associations\">Creating File Associations<\/h3>\n<p>To create a file association, you can call the <code class=\"highlighter-rouge\">fileAssociation.associateExeForFile<\/code> api, which will make windows assign a default program for an arbitrary file extension:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">utils<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">utils<\/span><span class=\"p\">;<\/span>\r\n<span class=\"nx\">utils<\/span><span class=\"p\">.<\/span><span class=\"nx\">associateExeForFile<\/span><span class=\"p\">(<\/span><span class=\"s1\">'myTestHandler'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'A test handler for unit tests'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'C:\\path\\to\\icon'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'C:\\Program Files\\nodejs\\node.exe %1'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'.zzz'<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>After running the code above, you will see files with the extension of .zzz will be automatically associated with the Node program and their file icon will be changed to the Node file icon.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-11-09-NodeJS-Windows-Registry-fileassoc.png\" alt=\"File Association\" \/><\/p>\n<h3 id=\"launching-process-as-an-admin\">Launching Process as an Admin<\/h3>\n<p>To launch a process as an Administrator, you can call the <code class=\"highlighter-rouge\">utils.elevate<\/code> api, which will launch a process as an Administrator causing the UAC (User Account Control) elevation prompt to appear if required. This is similar to the Windows Explorer command \u201cRun as administrator\u201d. Pass in <code class=\"highlighter-rouge\">FILEPATH<\/code> to the process you want to elevate. Pass in any <code class=\"highlighter-rouge\">PARAMETERS<\/code> to run with the process. Since this is an asynchronous call, pass in a callback to handle user\u2019s selection.<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">utils<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'windows-registry'<\/span><span class=\"p\">).<\/span><span class=\"nx\">utils<\/span><span class=\"p\">;<\/span>\r\n<span class=\"nx\">utils<\/span><span class=\"p\">.<\/span><span class=\"nx\">elevate<\/span><span class=\"p\">(<\/span><span class=\"s1\">'C:\\Program Files\\nodejs\\node.exe'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'index.js'<\/span><span class=\"p\">,<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">,<\/span> <span class=\"nx\">result<\/span><span class=\"p\">){<\/span><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">result<\/span><span class=\"p\">);});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h2 id=\"opportunities-for-reuse\">Opportunities for Reuse<\/h2>\n<p>With <a href=\"https:\/\/github.com\/CatalystCode\/windows-registry-node\">NPM module for Windows Registry<\/a>, developers can now read and write keys to Windows registry, create file associations to make Windows assign default programs to a file extension, and elevate processes to run as an administrator for any Node application running on Windows. With the source code of this NPM module in GitHub, our solution also serves as an example for how to interact with native Windows APIs in Node.js.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this code story, we create an NPM module that enables Node developers to update the Windows Registry and create file associations, as well as show how to use native Windows APIs from Node.js.<\/p>\n","protected":false},"author":21345,"featured_media":11168,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[16],"tags":[165,275,277,390],"class_list":["post-2158","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-electron","tag-node","tag-npm","tag-windows-registry"],"acf":[],"blog_post_summary":"<p>In this code story, we create an NPM module that enables Node developers to update the Windows Registry and create file associations, as well as show how to use native Windows APIs from Node.js.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21345"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2158"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2158\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/11168"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}