win-deskutils.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. Copyright 2022 Intel Corporation
  3. @author Bryan Roe
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. //
  15. // win-deskutils is a utility module that exposes various desktop related features for Windows
  16. // such as MouseTrails Accessability and Windows Desktop Background
  17. //
  18. //
  19. // MSDN documention for the system call this module relies on can be found at:
  20. // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
  21. //
  22. var SPI_GETDESKWALLPAPER = 0x0073;
  23. var SPI_SETDESKWALLPAPER = 0x0014;
  24. var SPI_GETMOUSETRAILS = 0x005E;
  25. var SPI_SETMOUSETRAILS = 0x005D;
  26. var GM = require('_GenericMarshal');
  27. var user32 = GM.CreateNativeProxy('user32.dll');
  28. user32.CreateMethod('SystemParametersInfoA');
  29. //
  30. // This function is a helper method to dispatch method calls to different user sessions
  31. //
  32. function sessionDispatch(tsid, parent, method, args)
  33. {
  34. //
  35. // Check to see if the process owner of the current processor is root
  36. //
  37. var sid = undefined;
  38. var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
  39. /*
  40. The following is the list of possible values for stype.
  41. If the current process owner is root, we set the stype to user,
  42. because we cannot set/get any properties from this user, we
  43. must switch to a user session.. Default behavior for stype(1)
  44. is that it will context switch to the logged in user. If
  45. this is not intended, then an actual user TSID must be specified, using
  46. ILibProcessPipe_SpawnTypes_SPECIFIED_USER and the actual TSID
  47. ------------------------------------------------------------------------
  48. ILibProcessPipe_SpawnTypes_DEFAULT = 0,
  49. ILibProcessPipe_SpawnTypes_USER = 1,
  50. ILibProcessPipe_SpawnTypes_WINLOGON = 2,
  51. ILibProcessPipe_SpawnTypes_TERM = 3,
  52. ILibProcessPipe_SpawnTypes_DETACHED = 4,
  53. ILibProcessPipe_SpawnTypes_SPECIFIED_USER = 5,
  54. ILibProcessPipe_SpawnTypes_POSIX_DETACHED = 0x8000
  55. ------------------------------------------------------------------------
  56. */
  57. console.log('stype: ' + stype);
  58. if (stype == 1)
  59. {
  60. if (tsid == null && require('MeshAgent')._tsid != null)
  61. {
  62. stype = 5; // ILibProcessPipe_SpawnTypes_SPECIFIED_USER
  63. sid = require('MeshAgent')._tsid; // If this is set, it was set via user selection UI
  64. }
  65. else
  66. {
  67. sid = tsid; // Set the SID to be whatever was passed in
  68. }
  69. }
  70. // Spawn a child process in the appropriate user session, and relay the response back via stdout
  71. var mod = Buffer.from(getJSModule('win-deskutils')).toString('base64');
  72. var prog = "try { addModule('win-deskutils', process.env['win_deskutils']);} catch (x) { } var x;try{x=require('win-deskutils').dispatch('" + parent + "', '" + method + "', " + JSON.stringify(args) + ");console.log(x);}catch(z){console.log(z);process.exit(1);}process.exit(0);";
  73. var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', Buffer.from(prog).toString('base64')], { type: stype, uid: sid, env: { win_deskutils: getJSModule('win-deskutils') } });
  74. child.stdout.str = '';
  75. child.stdout.on('data', function (c) { this.str += c.toString(); });
  76. child.stderr.on('data', function (c) { });
  77. child.on('exit', function (c) { this.exitCode = c; });
  78. child.waitExit();
  79. if (child.exitCode == 0)
  80. {
  81. return (child.stdout.str.trim()); // If the return code was 0, then relay the response from stdout
  82. }
  83. else
  84. {
  85. throw (child.stdout.str.trim()); // If the return code was nonzero, then the stdout response is the exception that should be bubbled
  86. }
  87. }
  88. //
  89. // This function gets the path of the windows desktop background of the specified user desktop session
  90. //
  91. function background_get(tsid)
  92. {
  93. if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
  94. {
  95. // Need to disatch to different session first
  96. return (sessionDispatch(tsid, 'background', 'get', []));
  97. }
  98. var v = GM.CreateVariable(1024);
  99. var ret = user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, v._size, v, 0);
  100. if (ret.Val == 0)
  101. {
  102. throw ('Error occured trying to fetch wallpaper');
  103. }
  104. return (v.String);
  105. }
  106. //
  107. // This function sets the path for the windows desktop background of the specified user desktop session
  108. //
  109. function background_set(path, tsid)
  110. {
  111. if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
  112. {
  113. // Need to disatch to different session first
  114. return (sessionDispatch(tsid, 'background', 'set', [path]));
  115. }
  116. var nb = GM.CreateVariable(path);
  117. var ret = user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, nb._size, nb, 0);
  118. if (ret.Val == 0)
  119. {
  120. throw ('Error occured trying to set wallpaper');
  121. }
  122. return;
  123. }
  124. //
  125. // This is a helper function that is called by the child process from sessionDispatch()
  126. //
  127. function dispatch(parent, method, args)
  128. {
  129. try
  130. {
  131. return (this[parent][method].apply(this, args));
  132. }
  133. catch (e)
  134. {
  135. console.log('ERROR: ' + e);
  136. throw ('Error occured trying to dispatch: ' + method);
  137. }
  138. }
  139. //
  140. // This function sets the mousetrail accessibility feature, for the specified user desktop session.
  141. // Setting value 0 or one disables this feature
  142. // Otherwise, value is the number of cursors to render for this feature
  143. //
  144. function mousetrails_set(value, tsid)
  145. {
  146. if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
  147. {
  148. // Need to disatch to different session first
  149. return (sessionDispatch(tsid, 'mouse', 'setTrails', [value]));
  150. }
  151. var ret = user32.SystemParametersInfoA(SPI_SETMOUSETRAILS, value, 0, 0);
  152. if (ret.Val == 0)
  153. {
  154. throw ('Error occured trying to fetch wallpaper');
  155. }
  156. }
  157. //
  158. // This function returns the number of cursors the mousetrail accessibility feature will render
  159. // A value of 0 or 1 means the feature is disabled, otherwise it is the number of cursors that will be rendered
  160. //
  161. function mousetrails_get(tsid)
  162. {
  163. if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
  164. {
  165. // Need to disatch to different session first
  166. return (sessionDispatch(tsid, 'mouse', 'getTrails', []));
  167. }
  168. var v = GM.CreateVariable(4);
  169. var ret = user32.SystemParametersInfoA(SPI_GETMOUSETRAILS, v._size, v, 0);
  170. if (ret.Val == 0)
  171. {
  172. throw ('Error occured trying to fetch wallpaper');
  173. }
  174. return (v.toBuffer().readUInt32LE());
  175. }
  176. module.exports = { background: { get: background_get, set: background_set } };
  177. module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set };
  178. module.exports.dispatch = dispatch;