electron_api_shell.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include <string>
  5. #include "shell/common/gin_converters/callback_converter.h"
  6. #include "shell/common/gin_converters/file_path_converter.h"
  7. #include "shell/common/gin_converters/guid_converter.h"
  8. #include "shell/common/gin_converters/gurl_converter.h"
  9. #include "shell/common/gin_helper/dictionary.h"
  10. #include "shell/common/gin_helper/error_thrower.h"
  11. #include "shell/common/gin_helper/promise.h"
  12. #include "shell/common/node_includes.h"
  13. #include "shell/common/platform_util.h"
  14. #if BUILDFLAG(IS_WIN)
  15. #include "base/win/scoped_com_initializer.h"
  16. #include "base/win/shortcut.h"
  17. #include "shell/common/thread_restrictions.h"
  18. namespace gin {
  19. template <>
  20. struct Converter<base::win::ShortcutOperation> {
  21. static bool FromV8(v8::Isolate* isolate,
  22. v8::Local<v8::Value> val,
  23. base::win::ShortcutOperation* out) {
  24. std::string operation;
  25. if (!ConvertFromV8(isolate, val, &operation))
  26. return false;
  27. if (operation.empty() || operation == "create")
  28. *out = base::win::ShortcutOperation::kCreateAlways;
  29. else if (operation == "update")
  30. *out = base::win::ShortcutOperation::kUpdateExisting;
  31. else if (operation == "replace")
  32. *out = base::win::ShortcutOperation::kReplaceExisting;
  33. else
  34. return false;
  35. return true;
  36. }
  37. };
  38. } // namespace gin
  39. #endif
  40. namespace {
  41. void OnOpenFinished(gin_helper::Promise<void> promise,
  42. const std::string& error) {
  43. if (error.empty())
  44. promise.Resolve();
  45. else
  46. promise.RejectWithErrorMessage(error);
  47. }
  48. v8::Local<v8::Promise> OpenExternal(const GURL& url, gin::Arguments* args) {
  49. gin_helper::Promise<void> promise(args->isolate());
  50. v8::Local<v8::Promise> handle = promise.GetHandle();
  51. platform_util::OpenExternalOptions options;
  52. gin_helper::Dictionary obj;
  53. if (args->GetNext(&obj)) {
  54. obj.Get("activate", &options.activate);
  55. obj.Get("workingDirectory", &options.working_dir);
  56. obj.Get("logUsage", &options.log_usage);
  57. }
  58. platform_util::OpenExternal(
  59. url, options, base::BindOnce(&OnOpenFinished, std::move(promise)));
  60. return handle;
  61. }
  62. v8::Local<v8::Promise> OpenPath(v8::Isolate* isolate,
  63. const base::FilePath& full_path) {
  64. gin_helper::Promise<const std::string&> promise(isolate);
  65. v8::Local<v8::Promise> handle = promise.GetHandle();
  66. platform_util::OpenPath(
  67. full_path,
  68. base::BindOnce(
  69. [](gin_helper::Promise<const std::string&> promise,
  70. const std::string& err_msg) { promise.Resolve(err_msg); },
  71. std::move(promise)));
  72. return handle;
  73. }
  74. v8::Local<v8::Promise> TrashItem(v8::Isolate* isolate,
  75. const base::FilePath& path) {
  76. gin_helper::Promise<void> promise(isolate);
  77. v8::Local<v8::Promise> handle = promise.GetHandle();
  78. platform_util::TrashItem(
  79. path, base::BindOnce(
  80. [](gin_helper::Promise<void> promise, bool success,
  81. const std::string& error) {
  82. if (success) {
  83. promise.Resolve();
  84. } else {
  85. promise.RejectWithErrorMessage(error);
  86. }
  87. },
  88. std::move(promise)));
  89. return handle;
  90. }
  91. #if BUILDFLAG(IS_WIN)
  92. bool WriteShortcutLink(const base::FilePath& shortcut_path,
  93. gin_helper::Arguments* args) {
  94. base::win::ShortcutOperation operation =
  95. base::win::ShortcutOperation::kCreateAlways;
  96. args->GetNext(&operation);
  97. auto options = gin::Dictionary::CreateEmpty(args->isolate());
  98. if (!args->GetNext(&options)) {
  99. args->ThrowError();
  100. return false;
  101. }
  102. base::win::ShortcutProperties properties;
  103. base::FilePath path;
  104. std::wstring str;
  105. UUID toastActivatorClsid;
  106. int index;
  107. if (options.Get("target", &path))
  108. properties.set_target(path);
  109. if (options.Get("cwd", &path))
  110. properties.set_working_dir(path);
  111. if (options.Get("args", &str))
  112. properties.set_arguments(str);
  113. if (options.Get("description", &str))
  114. properties.set_description(str);
  115. if (options.Get("icon", &path) && options.Get("iconIndex", &index))
  116. properties.set_icon(path, index);
  117. if (options.Get("appUserModelId", &str))
  118. properties.set_app_id(str);
  119. if (options.Get("toastActivatorClsid", &toastActivatorClsid))
  120. properties.set_toast_activator_clsid(toastActivatorClsid);
  121. electron::ScopedAllowBlockingForElectron allow_blocking;
  122. base::win::ScopedCOMInitializer com_initializer;
  123. return base::win::CreateOrUpdateShortcutLink(shortcut_path, properties,
  124. operation);
  125. }
  126. v8::Local<v8::Value> ReadShortcutLink(gin_helper::ErrorThrower thrower,
  127. const base::FilePath& path) {
  128. using base::win::ShortcutProperties;
  129. auto options = gin::Dictionary::CreateEmpty(thrower.isolate());
  130. electron::ScopedAllowBlockingForElectron allow_blocking;
  131. base::win::ScopedCOMInitializer com_initializer;
  132. base::win::ShortcutProperties properties;
  133. if (!base::win::ResolveShortcutProperties(
  134. path, ShortcutProperties::PROPERTIES_ALL, &properties)) {
  135. thrower.ThrowError("Failed to read shortcut link");
  136. return v8::Null(thrower.isolate());
  137. }
  138. options.Set("target", properties.target);
  139. options.Set("cwd", properties.working_dir);
  140. options.Set("args", properties.arguments);
  141. options.Set("description", properties.description);
  142. options.Set("icon", properties.icon);
  143. options.Set("iconIndex", properties.icon_index);
  144. options.Set("appUserModelId", properties.app_id);
  145. options.Set("toastActivatorClsid", properties.toast_activator_clsid);
  146. return gin::ConvertToV8(thrower.isolate(), options);
  147. }
  148. #endif
  149. void Initialize(v8::Local<v8::Object> exports,
  150. v8::Local<v8::Value> unused,
  151. v8::Local<v8::Context> context,
  152. void* priv) {
  153. gin_helper::Dictionary dict(context->GetIsolate(), exports);
  154. dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder);
  155. dict.SetMethod("openPath", &OpenPath);
  156. dict.SetMethod("openExternal", &OpenExternal);
  157. dict.SetMethod("trashItem", &TrashItem);
  158. dict.SetMethod("beep", &platform_util::Beep);
  159. #if BUILDFLAG(IS_WIN)
  160. dict.SetMethod("writeShortcutLink", &WriteShortcutLink);
  161. dict.SetMethod("readShortcutLink", &ReadShortcutLink);
  162. #endif
  163. }
  164. } // namespace
  165. NODE_LINKED_BINDING_CONTEXT_AWARE(electron_common_shell, Initialize)