Windows: detect if started from Windows Explorer

Bazel now detects whether it was started from a
command line (or as a subprocess), or from Windows
Explorer (by clicking its icon). In the latter
case it displays an error message asking the user
to run it from a command line, and waiting for a
keypress so the user has time to read this
message.

Change-Id: I4b0430e30d2f1f243cec6ff63cb3abac907e60e3
PiperOrigin-RevId: 163338527
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index 653c672..cca002d 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -1323,6 +1323,13 @@
 
   globals = new GlobalVariables(option_processor);
   blaze::SetupStdStreams();
+  if (argc == 1 && blaze::WarnIfStartedFromDesktop()) {
+    // Only check and warn for from-desktop start if there were no args.
+    // In this case the user probably clicked Bazel's icon (as opposed to either
+    // starting it from a terminal, or as a subprocess with args, or on Windows
+    // from a ".lnk" file with some args).
+    return blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR;
+  }
 
   // Best-effort operation to raise the resource limits from soft to hard.  We
   // do this early during the main program instead of just before execing the
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index 7e57492..a40ce95 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -198,6 +198,11 @@
 
 void UnsetEnv(const std::string& name);
 
+// Returns true and prints a warning if Bazel was started by clicking its icon.
+// This is typical on Windows. Other platforms should return false, unless they
+// wish to handle this case too.
+bool WarnIfStartedFromDesktop();
+
 // Ensure we have open file descriptors for stdin/stdout/stderr.
 void SetupStdStreams();
 
diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc
index 4915f99..fcf6d5c 100644
--- a/src/main/cpp/blaze_util_posix.cc
+++ b/src/main/cpp/blaze_util_posix.cc
@@ -512,6 +512,8 @@
   unsetenv(name.c_str());
 }
 
+bool WarnIfStartedFromDesktop() { return false; }
+
 void SetupStdStreams() {
   // Set non-buffered output mode for stderr/stdout. The server already
   // line-buffers messages where it makes sense, so there's no need to do set
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index dce52d5..cffe06f 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -1166,6 +1166,25 @@
 
 void UnsetEnv(const string& name) { SetEnv(name, ""); }
 
+bool WarnIfStartedFromDesktop() {
+  // GetConsoleProcessList returns:
+  //   0, if no console attached (Bazel runs as a subprocess)
+  //   1, if Bazel was started by clicking on its icon
+  //   2, if Bazel was started from the command line (even if its output is
+  //      redirected)
+  DWORD dummy[2] = {0};
+  if (GetConsoleProcessList(dummy, 2) != 1) {
+    return false;
+  }
+  printf(
+      "Bazel is a command line tool.\n\n"
+      "Try opening a console, such as the Windows Command Prompt (cmd.exe) "
+      "or PowerShell, and running \"bazel help\".\n\n"
+      "Press Enter to close this window...");
+  ReadFile(GetStdHandle(STD_INPUT_HANDLE), dummy, 1, dummy, NULL);
+  return true;
+}
+
 #ifndef ENABLE_PROCESSED_OUTPUT
 // From MSDN about BOOL SetConsoleMode(HANDLE, DWORD).
 #define ENABLE_PROCESSED_OUTPUT 0x0001