Windows: "find_java" exe and lib for android.bat

This adds a "find_java.exe" that will be packages
in SDK/tools/lib. It will be used by android.bat
and the other launchers to locate the best version
of java to use for our tools (currently we have
a find_java.bat that uses DOS commands to achieve
something similar but more limited).

In addition this creates a static "findjavalib"
that is used by the NSIS installer to locate
java and get its version (to complain in case we
only find a Java 1.4 or lesser). The goal is for
the installer to use the same logic as the tools
will use to locate the java binary.

Change-Id: Ic2efb388135087bab9687c3332882047fd041b1c
diff --git a/find_java/.gitignore b/find_java/.gitignore
new file mode 100644
index 0000000..c2e7014
--- /dev/null
+++ b/find_java/.gitignore
@@ -0,0 +1 @@
+images/find_java_icon.o
diff --git a/find_java/Android.mk b/find_java/Android.mk
new file mode 100644
index 0000000..892f772
--- /dev/null
+++ b/find_java/Android.mk
@@ -0,0 +1,70 @@
+# Copyright 2011 The Android Open Source Project
+#
+# Android.mk for find_java.exe & static library
+
+
+LOCAL_PATH := $(call my-dir)
+
+# find_java static library for host (used by find_java.exe and installer)
+# =======================================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libfindjava
+LOCAL_SRC_FILES := find_java.cpp utils.cpp
+
+LOCAL_CFLAGS += -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY -DUSE_MINGW
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# "find_java.exe", to be used from android.bat & co
+# =================================================
+
+include $(CLEAR_VARS)
+
+ifeq ($(HOST_OS),windows)
+
+LOCAL_SRC_FILES := \
+	win_android.cpp
+
+LOCAL_MODULE := find_java
+LOCAL_STATIC_LIBRARIES := libfindjava
+
+LOCAL_CFLAGS += -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY -DUSE_MINGW
+
+LOCAL_MODULE_TAGS := optional
+
+# Locate windres executable
+WINDRES := windres
+ifneq ($(USE_MINGW),)
+  # When building the Windows resources under Linux, use the MinGW one
+  WINDRES := i586-mingw32msvc-windres
+endif
+
+# Link the Windows icon file as well into the executable, based on the technique
+# used in external/qemu/Makefile.android.  The variables need to have different
+# names to not interfere with the ones from qemu/Makefile.android.
+#
+INTERMEDIATE         := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+FIND_JAVA_ICON_OBJ  := find_java_icon.o
+FIND_JAVA_ICON_PATH := $(LOCAL_PATH)/images
+$(FIND_JAVA_ICON_PATH)/$(FIND_JAVA_ICON_OBJ): $(FIND_JAVA_ICON_PATH)/android_icon.rc
+	$(WINDRES) $< -I $(FIND_JAVA_ICON_PATH) -o $@
+
+# seems to be the only way to add an object file that was not generated from
+# a C/C++/Java source file to our build system. and very unfortunately,
+# $(TOPDIR)/$(LOCALPATH) will always be prepended to this value, which forces
+# us to put the object file in the source directory...
+#
+LOCAL_PREBUILT_OBJ_FILES += images/$(FIND_JAVA_ICON_OBJ)
+
+include $(BUILD_HOST_EXECUTABLE)
+
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+
+endif
+
+
diff --git a/find_java/NOTICE b/find_java/NOTICE
new file mode 100644
index 0000000..7317ae2
--- /dev/null
+++ b/find_java/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2011, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/find_java/find_java.exe.manifest b/find_java/find_java.exe.manifest
new file mode 100755
index 0000000..d949f07
--- /dev/null
+++ b/find_java/find_java.exe.manifest
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

+

+<!--

+  For details on the Assembly Manifest, please look here:

+  http://msdn.microsoft.com/en-us/library/aa374191(VS.85).aspx

+-->

+

+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

+

+    <application>

+        <!--The ID below indicates application support for Windows Vista -->

+        <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />

+        <!--The ID below indicates application support for Windows 7 -->

+        <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />

+    </application>

+

+    <assemblyIdentity version="1.0.0.0"

+        processorArchitecture="x86"

+        name="Android.SDK.FindJava"

+        type="win32"

+        />

+

+    <description>Utility to find java.exe on the local system.</description>

+

+    <!-- Identify the application security requirements. -->

+    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

+        <security>

+            <requestedPrivileges>

+                <requestedExecutionLevel level="asInvoker" uiAccess="false" />

+            </requestedPrivileges>

+        </security>

+    </trustInfo>

+</assembly>

diff --git a/find_java/find_java.h b/find_java/find_java.h
new file mode 100755
index 0000000..b578903
--- /dev/null
+++ b/find_java/find_java.h
@@ -0,0 +1,30 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifndef _H_FIND_JAVA

+#define _H_FIND_JAVA

+

+#ifdef _WIN32

+

+#include "utils.h"

+

+bool findJavaInEnvPath(CPath *outJavaPath);

+bool findJavaInRegistry(CPath *outJavaPath);

+bool findJavaInProgramFiles(CPath *outJavaPath);

+bool getJavaVersion(CPath &javaPath, CString *version);

+

+#endif /* _WIN32 */

+#endif /* _H_FIND_JAVA */

diff --git a/find_java/find_java_exe.cpp b/find_java/find_java_exe.cpp
new file mode 100644
index 0000000..74f8ac1
--- /dev/null
+++ b/find_java/find_java_exe.cpp
@@ -0,0 +1,133 @@
+/*

+ * Copyright (C) 2012 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/*

+ * "find_java.exe", for Windows only.

+ * Tries to find a Java binary in a variety of places and prints the

+ * first one found on STDOUT and returns 0.

+ *

+ * If not found, returns error 1 with no message

+ * (unless ANDROID_SDKMAN_DEBUG or -d if set, in which case there's a message on STDERR).

+ *

+ * Implementation details:

+ * - We don't have access to ATL or MFC.

+ * - We don't want to pull in things like STL.

+ * - No Unicode/MBCS support for now.

+ *

+ * TODO for later version:

+ * - provide an env variable to let users override which version is being used.

+ * - if there's more than one java.exe found, enumerate them all.

+ * - and in that case take the one with the highest Java version number.

+ * - since that operation is expensive, do it only once and cache the result

+ *   in a temp file. If the temp file is not found or the java binary no

+ *   longer exists, re-run the enumaration.

+ */

+

+#ifdef _WIN32

+

+#include "utils.h"

+#include "find_java.h"

+#include <io.h>

+#include <fcntl.h>

+

+static void testFindJava() {

+

+    CPath javaPath("<not found>");

+    bool ok = findJavaInEnvPath(&javaPath);

+    printf("findJavaInEnvPath: [%s] %s\n", ok ? "OK" : "FAIL", javaPath.cstr());

+

+    javaPath.set("<not found>");

+    ok = findJavaInRegistry(&javaPath);

+    printf("findJavaInRegistry [%s] %s\n", ok ? "OK" : "FAIL", javaPath.cstr());

+

+    javaPath.set("<not found>");

+    ok = findJavaInProgramFiles(&javaPath);

+    printf("findJavaInProgramFiles [%s] %s\n", ok ? "OK" : "FAIL", javaPath.cstr());

+}

+

+

+int main(int argc, char* argv[]) {

+

+    gIsConsole = true; // tell utils to to print errors to stderr

+    gIsDebug = (getenv("ANDROID_SDKMAN_DEBUG") != NULL);

+    bool doShortPath = false;

+    bool doVersion = false;

+

+    for (int i = 1; i < argc; i++) {

+        if (strncmp(argv[i], "-t", 2) == 0) {

+            testFindJava();

+            return 0;

+

+        } else if (strncmp(argv[i], "-d", 2) == 0) {

+            gIsDebug = true;

+

+        } else if (strncmp(argv[i], "-s", 2) == 0) {

+            doShortPath = true;

+

+        } else if (strncmp(argv[i], "-v", 2) == 0) {

+            doVersion = true;

+

+        } else {

+            printf(

+                "Outputs the path of the first Java.exe found on the local system.\n"

+                "Returns code 0 when found, 1 when not found.\n"

+                "Options:\n"

+                "-h / -help   : This help.\n"

+                "-t / -test   : Internal test.\n"

+                "-s / -short  : Print path in short DOS form.\n"

+                "-v / -version: Only prints the Java version found.\n"

+                );

+            return 2;

+        }

+    }

+

+    CPath javaPath;

+    if (!findJavaInEnvPath(&javaPath) &&

+        !findJavaInRegistry(&javaPath) &&

+        !findJavaInProgramFiles(&javaPath)) {

+            if (gIsDebug) {

+                fprintf(stderr, "Failed to find Java on your system.\n");

+            }

+            return 1;

+    }

+    _ASSERT(!javaPath.isEmpty());

+

+    if (doShortPath) {

+        if (!javaPath.toShortPath(&javaPath)) {

+            fprintf(stderr,

+                "Failed to convert path to a short DOS path: %s\n",

+                javaPath.cstr());

+            return 1;

+        }

+    }

+

+    if (doVersion) {

+        // Print version found

+        CString version;

+        if (getJavaVersion(javaPath, &version)) {

+            printf("%s", version.cstr());

+            return 0;

+        } else {

+            fprintf(stderr, "Failed to get version of %s\n", javaPath.cstr());

+        }

+    }

+

+    // Print java.exe path found

+    printf("%s", javaPath.cstr());

+    return 0;

+}

+

+#endif /* _WIN32 */

diff --git a/find_java/find_java_lib.cpp b/find_java/find_java_lib.cpp
new file mode 100755
index 0000000..508147b
--- /dev/null
+++ b/find_java/find_java_lib.cpp
@@ -0,0 +1,388 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifdef _WIN32

+

+#include "find_java.h"

+#include <shlobj.h>

+

+// Check whether we can find $PATH/java.exe

+static bool checkPath(CPath *inOutPath) {

+    inOutPath->addPath("java.exe");

+

+    bool result = false;

+    PVOID oldWow64Value = disableWow64FsRedirection();

+    if (inOutPath->fileExists()) {

+        // Make sure we can actually run "java -version".

+        CString cmd;

+        cmd.setf("\"%s\" -version", inOutPath->cstr());

+        int code = execWait(cmd.cstr());

+        result = (code == 0);

+    }

+

+    revertWow64FsRedirection(oldWow64Value);

+    return result;

+}

+

+// Check whether we can find $PATH/bin/java.exe

+static bool checkBinPath(CPath *inOutPath) {

+    inOutPath->addPath("bin");

+    return checkPath(inOutPath);

+}

+

+// Search java.exe in the environment

+bool findJavaInEnvPath(CPath *outJavaPath) {

+    SetLastError(0);

+

+    const char* envPath = getenv("JAVA_HOME");

+    if (envPath != NULL) {

+        CPath p(envPath);

+        if (checkBinPath(&p)) {

+            if (gIsDebug) msgBox("Java found via JAVA_HOME: %s", p.cstr());

+            *outJavaPath = p;

+            return true;

+        }

+    }

+

+    envPath = getenv("PATH");

+    if (!envPath) return false;

+

+    CArray<CString> *paths = CString(envPath).split(';');

+    for(int i = 0; i < paths->size(); i++) {

+        CPath p((*paths)[i].cstr());

+        if (checkPath(&p)) {

+            if (gIsDebug) msgBox("Java found via env PATH: %s", p.cstr());

+            *outJavaPath = p;

+            delete paths;

+            return true;

+        }

+    }

+

+    delete paths;

+    return false;

+}

+

+// --------------

+

+bool getRegValue(const char *keyPath, const char *keyName, REGSAM access, CString *outValue) {

+    HKEY key;

+    LSTATUS status = RegOpenKeyExA(

+        HKEY_LOCAL_MACHINE,         // hKey

+        keyPath,                    // lpSubKey

+        0,                          // ulOptions

+        KEY_READ | access,          // samDesired,

+        &key);                      // phkResult

+    if (status == ERROR_SUCCESS) {

+

+        LSTATUS ret = ERROR_MORE_DATA;

+        DWORD size = 4096; // MAX_PATH is 260, so 4 KB should be good enough

+        char* buffer = (char*) malloc(size);

+

+        while (ret == ERROR_MORE_DATA && size < (1<<16) /*64 KB*/) {

+            ret = RegQueryValueExA(

+                key,                // hKey

+                keyName,            // lpValueName

+                NULL,               // lpReserved

+                NULL,               // lpType

+                (LPBYTE) buffer,    // lpData

+                &size);             // lpcbData

+

+            if (ret == ERROR_MORE_DATA) {

+                size *= 2;

+                buffer = (char*) realloc(buffer, size);

+            } else {

+                buffer[size] = 0;

+            }

+        }

+

+        if (ret != ERROR_MORE_DATA) outValue->set(buffer);

+

+        free(buffer);

+        RegCloseKey(key);

+

+        return (ret != ERROR_MORE_DATA);

+    }

+

+    return false;

+}

+

+bool exploreJavaRegistry(const char *entry, REGSAM access, CPath *outJavaPath) {

+

+    // Let's visit HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment [CurrentVersion]

+    CPath subKey("SOFTWARE\\JavaSoft\\");

+    subKey.addPath(entry);

+

+    CString currVersion;

+    if (getRegValue(subKey.cstr(), "CurrentVersion", access, &currVersion)) {

+        // CurrentVersion should be something like "1.7".

+        // We want to read HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.7 [JavaHome]

+        subKey.addPath(currVersion);

+        CPath javaHome;

+        if (getRegValue(subKey.cstr(), "JavaHome", access, &javaHome)) {

+            if (checkBinPath(&javaHome)) {

+                *outJavaPath = javaHome;

+                return true;

+            }

+        }

+    }

+

+    return false;

+}

+

+bool findJavaInRegistry(CPath *outJavaPath) {

+    // We'll do the registry test 3 times: first using the default mode,

+    // then forcing the use of the 32-bit registry then forcing the use of

+    // 64-bit registry. On Windows 2k, the 2 latter will fail since the

+    // flags are not supported. On a 32-bit OS the 64-bit is obviously

+    // useless and the 2 first test should be equivalent so we just

+    // need the first case.

+

+    // Check the JRE first, then the JDK.

+    if (exploreJavaRegistry("Java Runtime Environment", 0, outJavaPath) ||

+            exploreJavaRegistry("Java Development Kit", 0, outJavaPath)) {

+        return true;

+    }

+

+    // Check the real sysinfo state (not the one hidden by WOW64) for x86

+    SYSTEM_INFO sysInfo;

+    GetNativeSystemInfo(&sysInfo);

+

+    if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {

+        if (exploreJavaRegistry("Java Runtime Environment", KEY_WOW64_32KEY, outJavaPath) ||

+                exploreJavaRegistry("Java Development Kit", KEY_WOW64_32KEY, outJavaPath)) {

+            return true;

+        }

+

+        if (exploreJavaRegistry("Java Runtime Environment", KEY_WOW64_64KEY, outJavaPath) ||

+                exploreJavaRegistry("Java Development Kit", KEY_WOW64_64KEY, outJavaPath)) {

+            return true;

+        }

+    }

+

+    return false;

+}

+

+// --------------

+

+static bool checkProgramFiles(CPath *outJavaPath) {

+

+    char programFilesPath[MAX_PATH + 1];

+    HRESULT result = SHGetFolderPathA(

+        NULL,                       // hwndOwner

+        CSIDL_PROGRAM_FILES,        // nFolder

+        NULL,                       // hToken

+        SHGFP_TYPE_CURRENT,         // dwFlags

+        programFilesPath);          // pszPath

+    if (FAILED(result)) return false;

+

+    CPath path(programFilesPath);

+    path.addPath("Java");

+

+    // Do we have a C:\\Program Files\\Java directory?

+    if (!path.dirExists()) return false;

+

+    CPath glob(path);

+    glob.addPath("j*");

+

+    bool found = false;

+    WIN32_FIND_DATAA findData;

+    HANDLE findH = FindFirstFileA(glob.cstr(), &findData);

+    if (findH == INVALID_HANDLE_VALUE) return false;

+    do {

+        if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {

+            CPath temp(path);

+            temp.addPath(findData.cFileName);

+            // Check C:\\Program Files[x86]\\Java\\{jdk,jre}*\\bin\\java.exe

+            if (checkBinPath(&temp)) {

+                found = true;

+                *outJavaPath = temp;

+            }

+        }

+    } while (!found && FindNextFileA(findH, &findData) != 0);

+    FindClose(findH);

+

+    return found;

+}

+

+bool findJavaInProgramFiles(CPath *outJavaPath) {

+    // Check the C:\\Program Files (x86) directory

+    // With WOW64 fs redirection in place by default, we should get the x86

+    // version on a 64-bit OS since this app is a 32-bit itself.

+    if (checkProgramFiles(outJavaPath)) return true;

+

+    // Check the real sysinfo state (not the one hidden by WOW64) for x86

+    SYSTEM_INFO sysInfo;

+    GetNativeSystemInfo(&sysInfo);

+

+    if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {

+        // On a 64-bit OS, try again by disabling the fs redirection so

+        // that we can try the real C:\\Program Files directory.

+        PVOID oldWow64Value = disableWow64FsRedirection();

+        bool found = checkProgramFiles(outJavaPath);

+        revertWow64FsRedirection(oldWow64Value);

+        return found;

+    }

+

+    return false;

+}

+

+// --------------

+

+bool getJavaVersion(CPath &javaPath, CString *version) {

+    bool result = false;

+

+    // Run "java -version", which outputs something like to *STDERR*:

+    //

+    // java version "1.6.0_29"

+    // Java(TM) SE Runtime Environment (build 1.6.0_29-b11)

+    // Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode, sharing)

+    //

+    // We want to capture the first line, and more exactly the "1.6" part.

+

+

+    CString cmd;

+    cmd.setf("\"%s\" -version", javaPath.cstr());

+

+    SECURITY_ATTRIBUTES   saAttr;

+    STARTUPINFO           startup;

+    PROCESS_INFORMATION   pinfo;

+

+    // Want to inherit pipe handle

+    ZeroMemory(&saAttr, sizeof(saAttr));

+    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 

+    saAttr.bInheritHandle = TRUE; 

+    saAttr.lpSecurityDescriptor = NULL; 

+

+    // Create pipe for stdout

+    HANDLE stdoutPipeRd, stdoutPipeWt;

+    if (!CreatePipe(

+            &stdoutPipeRd,      // hReadPipe,

+            &stdoutPipeWt,      // hWritePipe,

+            &saAttr,            // lpPipeAttributes,

+            0)) {               // nSize (0=default buffer size)

+        displayLastError("CreatePipe failed: ");

+        return false;

+    }

+    if (!SetHandleInformation(stdoutPipeRd, HANDLE_FLAG_INHERIT, 0)) {

+        displayLastError("SetHandleInformation failed: ");

+        return false;

+    }

+

+    ZeroMemory(&pinfo, sizeof(pinfo));

+

+    ZeroMemory(&startup, sizeof(startup));

+    startup.cb          = sizeof(startup);

+    startup.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

+    startup.wShowWindow = SW_HIDE|SW_MINIMIZE;

+    // Capture both stderr and stdout

+    startup.hStdError   = stdoutPipeWt;

+    startup.hStdOutput  = stdoutPipeWt;

+    startup.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);

+

+    BOOL ok = CreateProcessA(

+            NULL,                   // program path

+            (LPSTR) cmd.cstr(),     // command-line

+            NULL,                   // process handle is not inheritable

+            NULL,                   // thread handle is not inheritable

+            TRUE,                   // yes, inherit some handles

+            0,                      // process creation flags

+            NULL,                   // use parent's environment block

+            NULL,                   // use parent's starting directory

+            &startup,               // startup info, i.e. std handles

+            &pinfo);

+

+    if (gIsConsole && !ok) displayLastError("CreateProcess failed: ");

+

+    // Close the write-end of the output pipe (we're only reading from it)

+    CloseHandle(stdoutPipeWt);

+

+    // Read from the output pipe. We don't need to read everything,

+    // the first line should be 'Java version "1.2.3_45"\r\n'

+    // so reading about 32 chars is all we need.

+    char first32[32 + 1];

+    int index = 0;

+    first32[0] = 0;

+

+    if (ok) {

+

+        #define SIZE 1024

+        char buffer[SIZE];

+        DWORD sizeRead = 0;

+

+        while (ok) {

+            // Keep reading in the same buffer location

+            ok = ReadFile(stdoutPipeRd,     // hFile

+                          buffer,           // lpBuffer

+                          SIZE,             // DWORD buffer size to read

+                          &sizeRead,        // DWORD buffer size read

+                          NULL);            // overlapped

+            if (!ok || sizeRead == 0 || sizeRead > SIZE) break;

+

+            // Copy up to the first 32 characters

+            if (index < 32) {

+                DWORD n = 32 - index;

+                if (n > sizeRead) n = sizeRead;

+                // copy as lowercase to simplify checks later

+                for (char *b = buffer; n > 0; n--, b++, index++) {

+                    char c = *b;

+                    if (c >= 'A' && c <= 'Z') c += 'a' - 'A';

+                    first32[index] = c;

+                }

+                first32[index] = 0;

+            }

+        }

+

+        WaitForSingleObject(pinfo.hProcess, INFINITE);

+

+        DWORD exitCode;

+        if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {

+            // this should not return STILL_ACTIVE (259)

+            result = exitCode == 0;

+        }

+

+        CloseHandle(pinfo.hProcess);

+        CloseHandle(pinfo.hThread);

+    }

+    CloseHandle(stdoutPipeRd);

+

+    if (index > 0) {

+        // Look for a few keywords in the output however we don't

+        // care about specific ordering or case-senstiviness.

+        // We only captures roughtly the first line in lower case.

+        char *j = strstr(first32, "java");

+        char *v = strstr(first32, "version");

+        if (gIsDebug && gIsConsole && (!j || !v)) {

+            fprintf(stderr, "Error: keywords 'java version' not found in '%s'\n", first32);

+        }

+        if (j != NULL && v != NULL) {

+            // Now extract the first thing that looks like digit.digit

+            for (int i = 0; i < index - 2; i++) {

+                if (isdigit(first32[i]) &&

+                        first32[i+1] == '.' &&

+                        isdigit(first32[i+2])) {

+                    version->set(first32 + i, 3);

+                    result = true;

+                    break;

+                }

+            }

+        }

+    }

+

+    return result;

+}

+

+

+#endif /* _WIN32 */

diff --git a/find_java/images/android_icon.ico b/find_java/images/android_icon.ico
new file mode 100644
index 0000000..bd25179
--- /dev/null
+++ b/find_java/images/android_icon.ico
Binary files differ
diff --git a/find_java/images/android_icon.rc b/find_java/images/android_icon.rc
new file mode 100644
index 0000000..7ff37f2
--- /dev/null
+++ b/find_java/images/android_icon.rc
@@ -0,0 +1,2 @@
+1 ICON "../images/android_icon.ico"

+1 RT_MANIFEST "../find_java.exe.manifest"

diff --git a/find_java/utils.cpp b/find_java/utils.cpp
new file mode 100755
index 0000000..bb679b8
--- /dev/null
+++ b/find_java/utils.cpp
@@ -0,0 +1,202 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifdef _WIN32

+

+#include "utils.h"

+

+#define _CRT_SECURE_NO_WARNINGS 1

+

+// Set to true to get some extra debug information

+bool gIsDebug = false;

+// Set to true to output errors to stderr (for a Console app)

+// or to false to output using msg box (for a Windows UI app)

+bool gIsConsole = false;

+

+// Displays a message in an ok+info dialog box.

+void msgBox(const char* text, ...) {

+    CString formatted;

+    va_list ap;

+    va_start(ap, text);

+    formatted.setv(text, ap);

+    va_end(ap);

+

+    MessageBoxA(NULL, formatted.cstr(), "Android SDK Manager", MB_OK | MB_ICONINFORMATION);

+}

+

+// Displays GetLastError prefixed with a description in an error dialog box

+void displayLastError(const char *description, ...) {

+    CString formatted;

+    va_list ap;

+    va_start(ap, description);

+    formatted.setv(description, ap);

+    va_end(ap);

+

+    CString error;

+    error.setLastWin32Error();

+    formatted.add("\r\n");

+    formatted.add(error.cstr());

+

+    if (gIsConsole) {

+        fprintf(stderr, "%s\n", formatted.cstr());

+    } else {

+        MessageBox(NULL, formatted.cstr(), "Android SDK Manager - Error", MB_OK | MB_ICONERROR);

+    }

+}

+

+// Executes the command line. Does not wait for the program to finish.

+// The return code is from CreateProcess (0 means failure), not the running app.

+int execNoWait(const char *app, const char *params, const char *workDir) {

+    STARTUPINFO           startup;

+    PROCESS_INFORMATION   pinfo;

+

+    ZeroMemory(&pinfo, sizeof(pinfo));

+

+    ZeroMemory(&startup, sizeof(startup));

+    startup.cb          = sizeof(startup);

+    startup.dwFlags     = STARTF_USESHOWWINDOW;

+    startup.wShowWindow = SW_SHOWDEFAULT;

+

+    int ret = CreateProcessA(

+            (LPSTR) app,                                /* program path */

+            (LPSTR) params,                             /* command-line */

+            NULL,                  /* process handle is not inheritable */

+            NULL,                   /* thread handle is not inheritable */

+            TRUE,                          /* yes, inherit some handles */

+            0,                                          /* create flags */

+            NULL,                     /* use parent's environment block */

+            workDir,                 /* use parent's starting directory */

+            &startup,                 /* startup info, i.e. std handles */

+            &pinfo);

+

+    if (ret) {

+        CloseHandle(pinfo.hProcess);

+        CloseHandle(pinfo.hThread);

+    }

+

+    return ret;

+}

+

+// Executes command, waits for completion and returns exit code.

+// As indicated in MSDN for CreateProcess, callers should double-quote the program name

+// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";

+int execWait(const char *cmd) {

+    STARTUPINFO           startup;

+    PROCESS_INFORMATION   pinfo;

+

+    ZeroMemory(&pinfo, sizeof(pinfo));

+

+    ZeroMemory(&startup, sizeof(startup));

+    startup.cb          = sizeof(startup);

+    startup.dwFlags     = STARTF_USESHOWWINDOW;

+    startup.wShowWindow = SW_HIDE|SW_MINIMIZE;

+

+    int ret = CreateProcessA(

+            NULL,                                       /* program path */

+            (LPSTR) cmd,                                /* command-line */

+            NULL,                  /* process handle is not inheritable */

+            NULL,                   /* thread handle is not inheritable */

+            TRUE,                          /* yes, inherit some handles */

+            CREATE_NO_WINDOW,                /* we don't want a console */

+            NULL,                     /* use parent's environment block */

+            NULL,                    /* use parent's starting directory */

+            &startup,                 /* startup info, i.e. std handles */

+            &pinfo);

+

+    int result = -1;

+    if (ret) {

+        WaitForSingleObject(pinfo.hProcess, INFINITE);

+

+        DWORD exitCode;

+        if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {

+            // this should not return STILL_ACTIVE (259)

+            result = exitCode;

+        }

+        CloseHandle(pinfo.hProcess);

+        CloseHandle(pinfo.hThread);

+    }

+

+    return result;

+}

+

+bool getModuleDir(CPath *outDir) {

+    CHAR programDir[MAX_PATH];

+    int ret = GetModuleFileName(NULL, programDir, sizeof(programDir));

+    if (ret != 0) {

+        // Remove the last segment to keep only the directory.

+        int pos = ret - 1;

+        while (pos > 0 && programDir[pos] != '\\') {

+            --pos;

+        }

+        outDir->set(programDir, pos);

+        return true;

+    }

+    return false;

+}

+

+// Disables the FS redirection done by WOW64.

+// Because this runs as a 32-bit app, Windows automagically remaps some

+// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").

+// This prevents the app from correctly searching for java.exe in these folders.

+// The registry is also remapped. This method disables this redirection.

+// Caller should restore the redirection later by using revertWow64FsRedirection().

+PVOID disableWow64FsRedirection() {

+

+    // The call we want to make is the following:

+    //    PVOID oldWow64Value;

+    //    Wow64DisableWow64FsRedirection(&oldWow64Value);

+    // However that method may not exist (e.g. on XP non-64 systems) so

+    // we must not call it directly.

+

+    PVOID oldWow64Value = 0;

+

+    HMODULE hmod = LoadLibrary("kernel32.dll");

+    if (hmod != NULL) {

+        FARPROC proc = GetProcAddress(hmod, "Wow64DisableWow64FsRedirection");

+        if (proc != NULL) {

+            typedef BOOL (WINAPI *disableWow64FuncType)(PVOID *);

+            disableWow64FuncType funcPtr = (disableWow64FuncType)proc;

+            funcPtr(&oldWow64Value);

+        }

+

+        FreeLibrary(hmod);

+    }

+

+    return oldWow64Value;

+}

+

+// Reverts the redirection disabled in disableWow64FsRedirection.

+void revertWow64FsRedirection(PVOID oldWow64Value) {

+

+    // The call we want to make is the following:

+    //    Wow64RevertWow64FsRedirection(oldWow64Value);

+    // However that method may not exist (e.g. on XP non-64 systems) so

+    // we must not call it directly.

+

+    HMODULE hmod = LoadLibrary("kernel32.dll");

+    if (hmod != NULL) {

+        FARPROC proc = GetProcAddress(hmod, "Wow64RevertWow64FsRedirection");

+        if (proc != NULL) {

+            typedef BOOL (WINAPI *revertWow64FuncType)(PVOID);

+            revertWow64FuncType funcPtr = (revertWow64FuncType)proc;

+            funcPtr(oldWow64Value);

+        }

+

+        FreeLibrary(hmod);

+    }

+}

+

+#endif /* _WIN32 */

diff --git a/find_java/utils.h b/find_java/utils.h
new file mode 100755
index 0000000..a2260b6
--- /dev/null
+++ b/find_java/utils.h
@@ -0,0 +1,375 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifndef _H_UTILS

+#define _H_UTILS

+

+#ifdef _WIN32

+

+#define _CRT_SECURE_NO_WARNINGS 1

+

+#include <direct.h>

+#include <stdio.h>

+#include <stdarg.h>

+#include <string.h>

+#include <windows.h>

+

+// VS vs MINGW specific includes

+#ifdef USE_VS_CRT

+    #include <crtdbg.h>     // for _ASSERT

+#else

+    #define _ASSERT(x)      // undef

+#endif

+

+extern bool gIsDebug;

+extern bool gIsConsole;

+

+// An array that knows its own size. Not dynamically resizable.

+template <class T> class CArray {

+    T* mPtr;

+    int mSize;

+public:

+    explicit CArray(int size) {

+        mSize = size;

+        mPtr = new T[size];

+    }

+

+    ~CArray() {

+        if (mPtr != NULL) {

+            delete[] mPtr;

+            mPtr = NULL;

+        }

+        mSize = 0;

+    }

+

+    T& operator[](int i) {

+        _ASSERT(i >= 0 && i < mSize);

+        return mPtr[i];

+    }

+

+    int size() const {

+        return mSize;

+    }

+};

+

+// A simple string class wrapper.

+class CString {

+protected:

+    char *mStr;

+public:

+    CString()                              { mStr = NULL; }

+    CString(const CString &str)            { mStr = NULL; set(str.mStr); }

+    explicit CString(const char *str)      { mStr = NULL; set(str); }

+    CString(const char *start, int length) { mStr = NULL; set(start, length); }

+

+    CString& operator=(const CString &str) {

+        return set(str.cstr());

+    }

+

+    CString& set(const char *str) {

+        if (str != mStr) {

+            _free();

+            if (str != NULL) {

+                mStr = _strdup(str);

+            }

+        }

+        return *this;

+    }

+

+    CString& set(const char *start, int length) {

+        _free();

+        if (start != NULL) {

+            mStr = (char *)malloc(length + 1);

+            strncpy(mStr, start, length);

+            mStr[length] = 0;

+        }

+        return *this;

+    }

+

+    CString& setv(const char *str, va_list ap) {

+        _free();

+        // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.

+        // Instead we'll iterate till we have enough space to generate the string.

+        int len = strlen(str) + 1024;

+        mStr = (char *)malloc(len);

+        strcpy(mStr, str); // provide a default in case vsnprintf totally fails

+        for (int guard = 0; guard < 10; guard++) {

+            int ret = vsnprintf(mStr, len, str, ap);

+            if (ret == -1) {

+                // Some implementations don't give the proper size needed

+                // so double the space and try again.

+                len *= 2;

+            } else if (ret >= len) {

+                len = ret + 1;

+            } else {

+                // There was enough space to write.

+                break;

+            }

+            mStr = (char *)realloc((void *)mStr, len);

+            strcpy(mStr, str); // provide a default in case vsnprintf totally fails

+        }

+        return *this;

+    }

+

+    CString& setf(const char *str, ...) {

+        _free();

+        va_list ap;

+        va_start(ap, str);

+        setv(str, ap);

+        va_end(ap);

+        return *this;

+    }

+

+    virtual ~CString() { _free(); }

+

+    // Returns the C string owned by this CString. It will be

+    // invalid as soon as this CString is deleted or out of scope.

+    const char * cstr() const {

+        return mStr;

+    }

+

+    bool isEmpty() const {

+        return mStr == NULL || *mStr == 0;

+    }

+

+    int length() const {

+        return mStr == NULL ? 0 : strlen(mStr);

+    }

+

+    CString& add(const char *str) {

+        if (mStr == NULL) {

+            set(str);

+        } else {

+            mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1);

+            strcat(mStr, str);

+        }

+        return *this;

+    }

+

+    CString& add(const char *str, int length) {

+        if (mStr == NULL) {

+            set(str, length);

+        } else {

+            int   l1 = strlen(mStr);

+            mStr = (char *)realloc((void *)mStr, l1 + length + 1);

+            strncpy(mStr + l1, str, length);

+            mStr[l1 + length] = 0;

+        }

+        return *this;

+    }

+

+    CArray<CString> * split(char sep) const {

+        if (mStr == NULL) {

+            return new CArray<CString>(0);

+        }

+        const char *last = NULL;

+        int n = 0;

+        for (const char *s = mStr; *s; s++) {

+            if (*s == sep && s != mStr && (last == NULL || s > last+1)) {

+                n++;

+                last = s;

+            }

+        }

+

+        CArray<CString> *result = new CArray<CString>(n);

+        last = NULL;

+        n = 0;

+        for (const char *s = mStr; *s; s++) {

+            if (*s == sep) {

+                if (s != mStr && (last == NULL || s > last+1)) {

+                    const char *start = last ? last : mStr;

+                    (*result)[n++].set(start, s-start);

+                }

+                last = s+1;

+            }

+        }

+

+        return result;

+    }

+

+    // Sets the string to the message matching Win32 GetLastError.

+    CString& setLastWin32Error() {

+        DWORD err = GetLastError();

+        LPSTR errStr;

+        if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */

+                          FORMAT_MESSAGE_FROM_SYSTEM,

+                          NULL,                             /* lpSource */

+                          err,                              /* dwMessageId */

+                          0,                                /* dwLanguageId */

+                          (LPSTR)&errStr,                   /* lpBuffer */

+                          0,                                /* nSize */

+                          NULL) != 0) {                     /* va_list args */

+            setf("[%d] %s", err, errStr);

+            LocalFree(errStr);

+        }

+        return *this;

+    }

+

+private:

+    void _free() {

+        if (mStr != NULL) {

+            free((void *)mStr);

+            mStr = NULL;

+        }

+    }

+

+};

+

+// A simple path class wrapper.

+class CPath : public CString {

+public:

+    CPath()                              : CString()    { }

+    CPath(const CString &str)            : CString(str) { }

+    CPath(const CPath &str)              : CString(str) { }

+    explicit CPath(const char *str)      : CString(str) { }

+    CPath(const char *start, int length) : CString(start, length) { }

+

+    CPath& operator=(const CPath &str) {

+        set(str.cstr());

+        return *this;

+    }

+

+    // Appends a path segment, adding a \ as necessary.

+    CPath& addPath(const CString &s) {

+        return addPath(s.cstr());

+    }

+

+    // Appends a path segment, adding a \ as necessary.

+    CPath& addPath(const char *s) {

+        _ASSERT(s != NULL);

+        if (s != NULL && s[0] != 0) {

+            int n = length();

+            if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");

+            add(s);

+        }

+        return *this;

+    }

+

+    // Returns true if file exist and is not a directory.

+    // There's no garantee we have rights to access it.

+    bool fileExists() const {

+        if (mStr == NULL) return false;

+        DWORD attribs = GetFileAttributesA(mStr);

+        return attribs != INVALID_FILE_ATTRIBUTES &&

+             !(attribs & FILE_ATTRIBUTE_DIRECTORY);

+    }

+

+    // Returns true if file exist and is a directory.

+    // There's no garantee we have rights to access it.

+    bool dirExists() const {

+        if (mStr == NULL) return false;

+        DWORD attribs = GetFileAttributesA(mStr);

+        return attribs != INVALID_FILE_ATTRIBUTES &&

+              (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;

+    }

+

+    // Returns a copy of the directory portion of the path, if any

+    CPath dirName() const {

+        CPath result;

+        if (mStr != NULL) {

+            char *pos = strrchr(mStr, '\\');

+            if (pos != NULL) {

+                result.set(mStr, pos - mStr);

+            }

+        }

+        return result;

+    }

+

+    // Returns a pointer to the baseName part of the path.

+    // It becomes invalid if the path changes.

+    const char * baseName() const {

+        if (mStr != NULL) {

+            char *pos = strrchr(mStr, '\\');

+            if (pos != NULL) {

+                return pos + 1;

+            }

+        }

+        return NULL;

+    }

+

+    // If the path ends with the given searchName, replace in-place by the new name

+    void replaceName(const char *searchName, const char* newName) {

+        if (mStr == NULL) return;

+        int n = length();

+        int sn = strlen(searchName);

+        if (n < sn) return;

+        // if mStr ends with searchName

+        if (strcmp(mStr + n - sn, searchName) == 0) {

+            int sn2 = strlen(newName);

+            if (sn2 > sn) {

+                mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);

+            }

+            strcpy(mStr + n - sn, newName);

+            mStr[n + sn2 - sn] = 0;

+        }

+    }

+

+    // Returns a copy of this path as a DOS short path in the destination.

+    // Returns true if the Win32 getShortPathName method worked.

+    // In case of error, returns false and does not change the destination.

+    // It's OK to invoke this->toShortPath(this).

+    bool toShortPath(CPath *dest) {

+        const char *longPath = mStr;

+        if (mStr == NULL) return false;

+

+        DWORD lenShort = strlen(longPath) + 1;

+        char * shortPath = (char *)malloc(lenShort);

+

+        DWORD length = GetShortPathName(longPath, shortPath, lenShort);

+        if (length > lenShort) {

+            // The buffer wasn't big enough, this is the size to use.

+            free(shortPath);

+            lenShort = length;

+            shortPath = (char *)malloc(length);

+            length = GetShortPathName(longPath, shortPath, lenShort);

+        }

+

+        if (length != 0) dest->set(shortPath);

+

+        free(shortPath);

+        return length != 0;

+    }

+};

+

+// Displays a message in an ok+info dialog box.

+void msgBox(const char* text, ...);

+

+// Displays GetLastError prefixed with a description in an error dialog box

+void displayLastError(const char *description, ...);

+

+// Executes the command line. Does not wait for the program to finish.

+// The return code is from CreateProcess (0 means failure), not the running app.

+int execNoWait(const char *app, const char *params, const char *workDir);

+

+// Executes command, waits for completion and returns exit code.

+// As indicated in MSDN for CreateProcess, callers should double-quote the program name

+// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";

+int execWait(const char *cmd);

+

+bool getModuleDir(CPath *outDir);

+

+// Disables the FS redirection done by WOW64.

+// Because this runs as a 32-bit app, Windows automagically remaps some

+// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").

+// This prevents the app from correctly searching for java.exe in these folders.

+// The registry is also remapped.

+PVOID disableWow64FsRedirection();

+

+// Reverts the redirection disabled in disableWow64FsRedirection.

+void revertWow64FsRedirection(PVOID oldWow64Value);

+

+#endif /* _WIN32 */

+#endif /* _H_UTILS */