Repository: electron/electron (language: cpp)

Issue:
[Feature Request]: Launch utility process without loading spinner on Windows
### Preflight Checklist

- [X] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [X] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [X] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.

### Problem Description

When launching a utility process on Windows, a loading spinner shows next to the mouse cursor.

![Loading cursor](https://github.com/user-attachments/assets/65c3b277-8e92-4cf8-b246-ee8c956433b9)

My app can sometimes launch utility processes every 2-5 seconds, leaving the mouse cursor in a constant loading state. To my users, this is annoying.

For context: Windows shows this loading spinner whenever a process is launched. This is helpful as a loading indicator when GUI applications are being launched. For utility processes, which do background activities that users might not be aware of, I don't think showing a loading spinner is appropriate.

#### Test case gist

https://gist.github.com/a705df773120f46805d521c6485a9f2e

### Proposed Solution

Chromium already supports turning the loading spinner off. When launching the utility process, set `feedback_cursor_off = true` on the `LaunchOptions` object ([link to Chrome code](https://github.com/chromium/chromium/blob/1d36e3ca354b932dd280db35c8c4f7e0b54512f6/base/process/launch.h#L111)). Then no loading spinner will appear.

I assume the change will need to happen in `patches/chromium/feat_configure_launch_options_for_service_process.patch`.

(Under the hood, this will set `STARTF_FORCEOFFFEEDBACK` in the `dwFlags` of the `STARTUPINFO` passed to `CreateProcess()`.)

### Alternatives Considered

Launch fewer but longer-running utility processes.

However, even then seeing a random loading spinner will confuse users.

### Additional Information

#### Demonstration video

https://github.com/user-attachments/assets/45fbdabb-4cd9-42a7-9f46-b879376ebaaf


Discussion / hints:

Fix patch:
diff --git a/patches/chromium/feat_configure_launch_options_for_service_process.patch b/patches/chromium/feat_configure_launch_options_for_service_process.patch
index 62ef63212b647..123df36d14b8c 100644
--- a/patches/chromium/feat_configure_launch_options_for_service_process.patch
+++ b/patches/chromium/feat_configure_launch_options_for_service_process.patch
@@ -6,8 +6,9 @@ Subject: feat: configure launch options for service process
 - POSIX:
   Allows configuring base::LaunchOptions::fds_to_remap when launching the child process.
 - Win:
-  Allows configuring base::LaunchOptions::handles_to_inherit, base::LaunchOptions::stdout_handle
-  and base::LaunchOptions::stderr_handle when launching the child process.
+  Allows configuring base::LaunchOptions::handles_to_inherit, base::LaunchOptions::stdout_handle,
+  base::LaunchOptions::stderr_handle and base::LaunchOptions::feedback_cursor_off when launching
+  the child process.
 - All:
   Allows configuring base::LauncOptions::current_directory, base::LaunchOptions::enviroment
   and base::LaunchOptions::clear_environment.
@@ -110,7 +111,7 @@ index f1a415f7bd56ece5ab07d2408dbfddf658b45ff3..49bf8f75583cc7b2de415f4ebb427573
  }
  
 diff --git a/content/browser/child_process_launcher_helper_win.cc b/content/browser/child_process_launcher_helper_win.cc
-index 2a01487c8ff837357f6d62dba80115b0ec64c343..8b1ed51630dc4fe77bd0edadb85f04fb8962cdd8 100644
+index 2a01487c8ff837357f6d62dba80115b0ec64c343..74343f6a3bfb1eab2aaf1c0b5fba6ceaf9399ef6 100644
 --- a/content/browser/child_process_launcher_helper_win.cc
 +++ b/content/browser/child_process_launcher_helper_win.cc
 @@ -24,6 +24,8 @@
@@ -122,7 +123,7 @@ index 2a01487c8ff837357f6d62dba80115b0ec64c343..8b1ed51630dc4fe77bd0edadb85f04fb
  namespace {
  
  // Helper to avoid marking the log file as non-executable every time we launch a
-@@ -132,6 +134,30 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
+@@ -132,6 +134,31 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
      mojo_channel_->PrepareToPassRemoteEndpoint(&options->handles_to_inherit,
                                                 command_line());
    }
@@ -150,10 +151,11 @@ index 2a01487c8ff837357f6d62dba80115b0ec64c343..8b1ed51630dc4fe77bd0edadb85f04fb
 +  options->current_directory = delegate_->GetCurrentDirectory();
 +  options->environment = delegate_->GetEnvironment();
 +  options->clear_environment = !delegate_->ShouldInheritEnvironment();
++  options->feedback_cursor_off = !delegate_->ShouldShowFeedbackCursor();
    return true;
  }
  
-@@ -159,7 +185,7 @@ ChildProcessLauncherHelper::LaunchProcessOnLauncherThread(
+@@ -159,7 +186,7 @@ ChildProcessLauncherHelper::LaunchProcessOnLauncherThread(
    ChildProcessLauncherHelper::Process process;
    *launch_result =
        StartSandboxedProcess(delegate_.get(), *command_line(),
@@ -163,16 +165,17 @@ index 2a01487c8ff837357f6d62dba80115b0ec64c343..8b1ed51630dc4fe77bd0edadb85f04fb
  }
  
 diff --git a/content/browser/service_process_host_impl.cc b/content/browser/service_process_host_impl.cc
-index bdd5bec301f5fcff2d3e3d7994ecbc4eae46da36..45cf31157c535a0cdc9236a07e2ffffd166ba412 100644
+index bdd5bec301f5fcff2d3e3d7994ecbc4eae46da36..f6082bada22c5f4e70af60ea6f555b0f363919c5 100644
 --- a/content/browser/service_process_host_impl.cc
 +++ b/content/browser/service_process_host_impl.cc
-@@ -205,6 +205,16 @@ void LaunchServiceProcess(mojo::GenericPendingReceiver receiver,
+@@ -205,6 +205,17 @@ void LaunchServiceProcess(mojo::GenericPendingReceiver receiver,
        options.allow_gpu_client.value()) {
      host->SetAllowGpuClient();
    }
 +
 +#if BUILDFLAG(IS_WIN)
 +  host->SetStdioHandles(std::move(options.stdout_handle), std::move(options.stderr_handle));
++  host->SetFeedbackCursorOff(options.feedback_cursor_off);
 +#elif BUILDFLAG(IS_POSIX)
 +  host->SetAdditionalFds(std::move(options.fds_to_remap));
 +#endif
@@ -184,7 +187,7 @@ index bdd5bec301f5fcff2d3e3d7994ecbc4eae46da36..45cf31157c535a0cdc9236a07e2ffffd
    host->GetChildProcess()->BindServiceInterface(std::move(receiver));
  }
 diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
-index bb266d4baddd1fa4d49ef7fac1ac8d5d85c934d4..8550dbc7209c1ac2b6a4b6d493167cfc05d8adbc 100644
+index bb266d4baddd1fa4d49ef7fac1ac8d5d85c934d4..61369ff1ffe9ab511224b7e72b283df9e9262fd6 100644
 --- a/content/browser/utility_process_host.cc
 +++ b/content/browser/utility_process_host.cc
 @@ -179,11 +179,13 @@ const ChildProcessData& UtilityProcessHost::GetData() {
@@ -203,7 +206,7 @@ index bb266d4baddd1fa4d49ef7fac1ac8d5d85c934d4..8550dbc7209c1ac2b6a4b6d493167cfc
  
  bool UtilityProcessHost::Start() {
    return StartProcess();
-@@ -230,6 +232,24 @@ void UtilityProcessHost::SetZygoteForTesting(ZygoteCommunication* handle) {
+@@ -230,6 +232,30 @@ void UtilityProcessHost::SetZygoteForTesting(ZygoteCommunication* handle) {
  }
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -224,11 +227,17 @@ index bb266d4baddd1fa4d49ef7fac1ac8d5d85c934d4..8550dbc7209c1ac2b6a4b6d493167cfc
 +    const base::FilePath& cwd) {
 +  current_directory_ = cwd;
 +}
++
++#if BUILDFLAG(IS_WIN)
++void UtilityProcessHost::SetFeedbackCursorOff(bool feedback_cursor_off) {
++  feedback_cursor_off_ = feedback_cursor_off;
++}
++#endif  // BUILDFLAG(IS_WIN)
 +
  mojom::ChildProcess* UtilityProcessHost::GetChildProcess() {
    return static_cast<ChildProcessHostImpl*>(process_->GetHost())
        ->child_process();
-@@ -437,9 +457,22 @@ bool UtilityProcessHost::StartProcess() {
+@@ -437,9 +463,26 @@ bool UtilityProcessHost::StartProcess() {
      }
  #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
  
@@ -249,11 +258,15 @@ index bb266d4baddd1fa4d49ef7fac1ac8d5d85c934d4..8550dbc7209c1ac2b6a4b6d493167cfc
 -            sandbox_type_, env_, *cmd_line);
 +            sandbox_type_, env_, current_directory_, *cmd_line,
 +            inherit_environment_);
++
++#if BUILDFLAG(IS_WIN)
++    delegate->SetFeedbackCursorOff(feedback_cursor_off_);
++#endif  // BUILDFLAG(IS_WIN)
  
  #if BUILDFLAG(IS_WIN)
      if (!preload_libraries_.empty()) {
 diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
-index 9791ae2f761043b9eecd9064a6fd39a6e2339af4..1083f1683a05825f51f5b2d71f8107d910fa2474 100644
+index 9791ae2f761043b9eecd9064a6fd39a6e2339af4..c1809298c830b814f886859c2626d6bce7b9ac8c 100644
 --- a/content/browser/utility_process_host.h
 +++ b/content/browser/utility_process_host.h
 @@ -29,6 +29,10 @@
@@ -283,7 +296,7 @@ index 9791ae2f761043b9eecd9064a6fd39a6e2339af4..1083f1683a05825f51f5b2d71f8107d9
  
    // Starts the utility process.
    bool Start();
-@@ -138,6 +146,16 @@ class CONTENT_EXPORT UtilityProcessHost
+@@ -138,6 +146,21 @@ class CONTENT_EXPORT UtilityProcessHost
    void SetZygoteForTesting(ZygoteCommunication* handle);
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -296,11 +309,16 @@ index 9791ae2f761043b9eecd9064a6fd39a6e2339af4..1083f1683a05825f51f5b2d71f8107d9
 +
 +  // Sets the working directory of the process.
 +  void SetCurrentDirectory(const base::FilePath& cwd);
++
++#if BUILDFLAG(IS_WIN)
++  // Specifies if the process should trigger mouse cursor feedback.
++  void SetFeedbackCursorOff(bool feedback_cursor_off);
++#endif  // BUILDFLAG(IS_WIN)
 +
    // Returns a control interface for the running child process.
    mojom::ChildProcess* GetChildProcess();
  
-@@ -191,6 +209,22 @@ class CONTENT_EXPORT UtilityProcessHost
+@@ -191,6 +214,27 @@ class CONTENT_EXPORT UtilityProcessHost
    std::optional<raw_ptr<ZygoteCommunication>> zygote_for_testing_;
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -319,12 +337,17 @@ index 9791ae2f761043b9eecd9064a6fd39a6e2339af4..1083f1683a05825f51f5b2d71f8107d9
 +
 +  // Inherit enviroment from parent process.
 +  bool inherit_environment_ = true;
++
++#if BUILDFLAG(IS_WIN)
++  // Specifies if the process should trigger mouse cursor feedback.
++  bool feedback_cursor_off_ = false;
++#endif  // BUILDFLAG(IS_WIN)
 +
    // Indicates whether the process has been successfully launched yet, or if
    // launch failed.
    enum class LaunchState {
 diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc
-index ad5ad7b27da8bc1b435bbb91e9e0eaa98aef9612..4f469e32f0e3ae88d11e6a6a1bb577c1302c624d 100644
+index ad5ad7b27da8bc1b435bbb91e9e0eaa98aef9612..f72fadc75ecf165fe29ac2f1bd8c63a718a0c610 100644
 --- a/content/browser/utility_sandbox_delegate.cc
 +++ b/content/browser/utility_sandbox_delegate.cc
 @@ -34,17 +34,19 @@ UtilitySandboxedProcessLauncherDelegate::
@@ -351,7 +374,7 @@ index ad5ad7b27da8bc1b435bbb91e9e0eaa98aef9612..4f469e32f0e3ae88d11e6a6a1bb577c1
  #if DCHECK_IS_ON()
    bool supported_sandbox_type =
        sandbox_type_ == sandbox::mojom::Sandbox::kNoSandbox ||
-@@ -107,11 +109,17 @@ UtilitySandboxedProcessLauncherDelegate::GetSandboxType() {
+@@ -107,11 +109,28 @@ UtilitySandboxedProcessLauncherDelegate::GetSandboxType() {
    return sandbox_type_;
  }
  
@@ -368,11 +391,22 @@ index ad5ad7b27da8bc1b435bbb91e9e0eaa98aef9612..4f469e32f0e3ae88d11e6a6a1bb577c1
 +base::FilePath UtilitySandboxedProcessLauncherDelegate::GetCurrentDirectory() {
 +  return current_directory_;
 +}
++
++#if BUILDFLAG(IS_WIN)
++void UtilitySandboxedProcessLauncherDelegate::SetFeedbackCursorOff(
++    bool feedback_cursor_off) {
++  feedback_cursor_off_ = feedback_cursor_off;
++}
++
++bool UtilitySandboxedProcessLauncherDelegate::ShouldShowFeedbackCursor() {
++  return !feedback_cursor_off_;
++}
++#endif  // BUILDFLAG(IS_WIN)
  
  #if BUILDFLAG(USE_ZYGOTE)
  ZygoteCommunication* UtilitySandboxedProcessLauncherDelegate::GetZygote() {
 diff --git a/content/browser/utility_sandbox_delegate.h b/content/browser/utility_sandbox_delegate.h
-index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..57c0d369e7373f755391da3fafbdaea86358d962 100644
+index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..f5238dcd76d74e6705061063ee847f8447650deb 100644
 --- a/content/browser/utility_sandbox_delegate.h
 +++ b/content/browser/utility_sandbox_delegate.h
 @@ -30,7 +30,9 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
@@ -386,7 +420,7 @@ index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..57c0d369e7373f755391da3fafbdaea8
    ~UtilitySandboxedProcessLauncherDelegate() override;
  
    sandbox::mojom::Sandbox GetSandboxType() override;
-@@ -56,18 +58,16 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
+@@ -56,18 +58,21 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
    ZygoteCommunication* GetZygote() override;
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -395,6 +429,11 @@ index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..57c0d369e7373f755391da3fafbdaea8
 -#endif  // BUILDFLAG(IS_POSIX)
 +  bool ShouldInheritEnvironment() override;
 +  base::FilePath GetCurrentDirectory() override;
++
++#if BUILDFLAG(IS_WIN)
++  void SetFeedbackCursorOff(bool feedback_cursor_off);
++  bool ShouldShowFeedbackCursor() override;
++#endif  // BUILDFLAG(IS_WIN)
  
  #if BUILDFLAG(USE_ZYGOTE)
    void SetZygote(ZygoteCommunication* handle);
@@ -407,7 +446,7 @@ index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..57c0d369e7373f755391da3fafbdaea8
  
  #if BUILDFLAG(IS_WIN)
    std::vector<base::FilePath> preload_libraries_;
-@@ -77,12 +77,14 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
+@@ -77,12 +82,17 @@ class CONTENT_EXPORT UtilitySandboxedProcessLauncherDelegate
    std::optional<raw_ptr<ZygoteCommunication>> zygote_;
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -419,6 +458,9 @@ index 368fb567e46a55bdc44820d5b7a2a08ac6cc4ffd..57c0d369e7373f755391da3fafbdaea8
  #endif  // BUILDFLAG(IS_WIN)
    base::CommandLine cmd_line_;
 +  bool inherit_environment_;
++#if BUILDFLAG(IS_WIN)
++  bool feedback_cursor_off_ = false;
++#endif  // BUILDFLAG(IS_WIN)
  };
  }  // namespace content
  
@@ -445,10 +487,10 @@ index b96d6a879e8b6664559bac69f726321fdb02b40f..bfeec6ddb98d4127c1dcfe5999894f1c
  
  }  // namespace content
 diff --git a/content/public/browser/service_process_host.cc b/content/public/browser/service_process_host.cc
-index 8defae52a201a97c402e304216ce772a717a9f7e..a3cdeab1c22cf9f1b5ea0c25d2d7cbff9b68b683 100644
+index 8defae52a201a97c402e304216ce772a717a9f7e..4aee78366398c018e315ef15e631d0792ee79c47 100644
 --- a/content/public/browser/service_process_host.cc
 +++ b/content/public/browser/service_process_host.cc
-@@ -52,12 +52,45 @@ ServiceProcessHost::Options::WithExtraCommandLineSwitches(
+@@ -52,12 +52,53 @@ ServiceProcessHost::Options::WithExtraCommandLineSwitches(
    return *this;
  }
  
@@ -490,12 +532,20 @@ index 8defae52a201a97c402e304216ce772a717a9f7e..a3cdeab1c22cf9f1b5ea0c25d2d7cbff
 +  clear_environment = new_environment;
 +  return *this;
 +}
++
++#if BUILDFLAG(IS_WIN)
++ServiceProcessHost::Options& ServiceProcessHost::Options::WithFeedbackCursorOff(
++    bool turn_feedback_cursor_off) {
++  feedback_cursor_off = turn_feedback_cursor_off;
++  return *this;
++}
++#endif  // #if BUILDFLAG(IS_WIN)
 +
  #if BUILDFLAG(IS_WIN)
  ServiceProcessHost::Options&
  ServiceProcessHost::Options::WithPreloadedLibraries(
 diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
-index 0062d2cb6634b8b29977a0312516b1b13936b40a..22e1191b57f56aa31b2c82fcc3ec0972f16752a8 100644
+index 0062d2cb6634b8b29977a0312516b1b13936b40a..611a52e908f4cb70fbe5628e220a082e45320b70 100644
 --- a/content/public/browser/service_process_host.h
 +++ b/content/public/browser/service_process_host.h
 @@ -14,6 +14,7 @@
@@ -517,7 +567,7 @@ index 0062d2cb6634b8b29977a0312516b1b13936b40a..22e1191b57f56aa31b2c82fcc3ec0972
  namespace base {
  class Process;
  }  // namespace base
-@@ -94,11 +99,30 @@ class CONTENT_EXPORT ServiceProcessHost {
+@@ -94,11 +99,35 @@ class CONTENT_EXPORT ServiceProcessHost {
      // Specifies extra command line switches to append before launch.
      Options& WithExtraCommandLineSwitches(std::vector<std::string> switches);
  
@@ -544,11 +594,16 @@ index 0062d2cb6634b8b29977a0312516b1b13936b40a..22e1191b57f56aa31b2c82fcc3ec0972
 +    // environment from the parent process.
 +    Options& WithEnvironment(const base::EnvironmentMap& environment,
 +                             bool new_environment);
++
++#if BUILDFLAG(IS_WIN)
++    // Specifies if the process should trigger mouse cursor feedback.
++    Options& WithFeedbackCursorOff(bool feedback_cursor_off);
++#endif  // #if BUILDFLAG(IS_WIN)
 +
  #if BUILDFLAG(IS_WIN)
      // Specifies libraries to preload before the sandbox is locked down. Paths
      // should be absolute paths. Libraries will be preloaded before sandbox
-@@ -127,11 +151,20 @@ class CONTENT_EXPORT ServiceProcessHost {
+@@ -127,11 +156,23 @@ class CONTENT_EXPORT ServiceProcessHost {
      std::optional<GURL> site;
      std::optional<int> child_flags;
      std::vector<std::string> extra_switches;
@@ -566,6 +621,9 @@ index 0062d2cb6634b8b29977a0312516b1b13936b40a..22e1191b57f56aa31b2c82fcc3ec0972
 +    base::FilePath current_directory;
 +    base::EnvironmentMap environment;
 +    bool clear_environment = false;
++#if BUILDFLAG(IS_WIN)
++    bool feedback_cursor_off = false;
++#endif  // BUILDFLAG(IS_WIN)
    };
  
    // An interface which can be implemented and registered/unregistered with
@@ -583,10 +641,10 @@ index 9bb4b30ba0f5d37ec2b28f0848d94f34c24f9423..b614fef01ee5cdf81b7112be721b851c
  
  }  // namespace content
 diff --git a/content/public/common/sandboxed_process_launcher_delegate.cc b/content/public/common/sandboxed_process_launcher_delegate.cc
-index 9c1aa450f32b6812d4a87cd0b9ee0dfb1a9557f4..3360302b4511ed914ac2d5756dcc7edf7e675631 100644
+index 9c1aa450f32b6812d4a87cd0b9ee0dfb1a9557f4..c281fc33709376dbd50af281c219f3f5bda5635b 100644
 --- a/content/public/common/sandboxed_process_launcher_delegate.cc
 +++ b/content/public/common/sandboxed_process_launcher_delegate.cc
-@@ -68,11 +68,17 @@ ZygoteCommunication* SandboxedProcessLauncherDelegate::GetZygote() {
+@@ -68,11 +68,23 @@ ZygoteCommunication* SandboxedProcessLauncherDelegate::GetZygote() {
  }
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -603,11 +661,17 @@ index 9c1aa450f32b6812d4a87cd0b9ee0dfb1a9557f4..3360302b4511ed914ac2d5756dcc7edf
 +base::FilePath SandboxedProcessLauncherDelegate::GetCurrentDirectory() {
 +  return base::FilePath();
 +}
++
++#if BUILDFLAG(IS_WIN)
++bool SandboxedProcessLauncherDelegate::ShouldShowFeedbackCursor() {
++  return true;
++}
++#endif  // #if BUILDFLAG(IS_WIN)
  
  #if BUILDFLAG(IS_MAC)
  
 diff --git a/content/public/common/sandboxed_process_launcher_delegate.h b/content/public/common/sandboxed_process_launcher_delegate.h
-index cb43aa14c9742f3788ae58c3e49b890cd532f327..6a738f7aade504f2ff3bb6647a0da8f8d1933de2 100644
+index cb43aa14c9742f3788ae58c3e49b890cd532f327..276b2a06fabba559eb1caaaa9129b9f78058aa9f 100644
 --- a/content/public/common/sandboxed_process_launcher_delegate.h
 +++ b/content/public/common/sandboxed_process_launcher_delegate.h
 @@ -6,6 +6,7 @@
@@ -618,7 +682,7 @@ index cb43aa14c9742f3788ae58c3e49b890cd532f327..6a738f7aade504f2ff3bb6647a0da8f8
  #include "base/files/scoped_file.h"
  #include "base/process/process.h"
  #include "build/build_config.h"
-@@ -57,10 +58,14 @@ class CONTENT_EXPORT SandboxedProcessLauncherDelegate
+@@ -57,10 +58,19 @@ class CONTENT_EXPORT SandboxedProcessLauncherDelegate
    virtual ZygoteCommunication* GetZygote();
  #endif  // BUILDFLAG(USE_ZYGOTE)
  
@@ -632,6 +696,11 @@ index cb43aa14c9742f3788ae58c3e49b890cd532f327..6a738f7aade504f2ff3bb6647a0da8f8
 +
 +  // Specifies the directory to change to before executing the process.
 +  virtual base::FilePath GetCurrentDirectory();
++
++#if BUILDFLAG(IS_WIN)
++  // Override this if the process should not trigger mouse cursor feedback.
++  virtual bool ShouldShowFeedbackCursor();
++#endif  // #if BUILDFLAG(IS_WIN)
  
  #if BUILDFLAG(IS_MAC)
    // Whether or not to disclaim TCC responsibility for the process, defaults to
diff --git a/shell/browser/api/electron_api_utility_process.cc b/shell/browser/api/electron_api_utility_process.cc
index 10050210e2b48..333e4b66c5149 100644
--- a/shell/browser/api/electron_api_utility_process.cc
+++ b/shell/browser/api/electron_api_utility_process.cc
@@ -166,6 +166,7 @@ UtilityProcessWrapper::UtilityProcessWrapper(
 #if BUILDFLAG(IS_WIN)
           .WithStdoutHandle(std::move(stdout_write))
           .WithStderrHandle(std::move(stderr_write))
+          .WithFeedbackCursorOff(true)
 #elif BUILDFLAG(IS_POSIX)
           .WithAdditionalFds(std::move(fds_to_remap))
 #endif


Test patch: