Revert "Remove unused project."

This reverts commit eaada771a6e62ca494a625ce1b060f1a94fa9877.

Reason for revert: Breaks build_test and other builds
Bug: 155862492

Change-Id: I1a14b84d54b05596ec250b31ae56e437cf49fd81
diff --git a/find_java2/src/FindJava2Dlg.cpp b/find_java2/src/FindJava2Dlg.cpp
new file mode 100755
index 0000000..fbdd899
--- /dev/null
+++ b/find_java2/src/FindJava2Dlg.cpp
@@ -0,0 +1,268 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+

+#include "stdafx.h"

+#include "utils.h"

+#include "FindJava2Dlg.h"

+#include "afxdialogex.h"

+#include <atlpath.h>                            // ATL CPath

+

+#ifdef _DEBUG

+#define new DEBUG_NEW

+#endif

+

+#define COL_PATH 1

+

+

+CFindJava2Dlg::CFindJava2Dlg(CWnd* pParent /*=NULL*/)

+    : CDialog(CFindJava2Dlg::IDD, pParent), mSelectedIndex(-1) {

+    m_hIcon = AfxGetApp()->LoadIcon(IDI_ANDROID_ICON);

+}

+

+void CFindJava2Dlg::DoDataExchange(CDataExchange* pDX) {

+    CDialog::DoDataExchange(pDX);

+    DDX_Control(pDX, IDC_PATH_LIST, mPathsListCtrl);

+    DDX_Control(pDX, IDOK, mOkButton);

+}

+

+BEGIN_MESSAGE_MAP(CFindJava2Dlg, CDialog)

+    ON_WM_PAINT()

+    ON_WM_QUERYDRAGICON()

+    ON_BN_CLICKED(IDC_BUTTON_ADD, &CFindJava2Dlg::OnBnClickedButtonAdd)

+    ON_NOTIFY(NM_CLICK, IDC_PATH_LIST, &CFindJava2Dlg::OnNMClickPathList)

+    ON_NOTIFY(LVN_ITEMCHANGED, IDC_PATH_LIST, &CFindJava2Dlg::OnLvnItemchangedPathList)

+END_MESSAGE_MAP()

+

+

+// -----

+// CFindJava2Dlg message handlers

+

+BOOL CFindJava2Dlg::OnInitDialog() {

+    CDialog::OnInitDialog();

+

+    SetWindowText(getAppName());

+

+    // Set the icon for this dialog.  The framework does this automatically

+    //  when the application's main window is not a dialog

+    SetIcon(m_hIcon, TRUE);			// Set big icon

+    SetIcon(m_hIcon, FALSE);		// Set small icon

+

+    // Initialize list controls

+    mPathsListCtrl.SetExtendedStyle(

+        mPathsListCtrl.GetExtendedStyle() |

+        LVS_EX_CHECKBOXES | 

+        LVS_EX_FULLROWSELECT | 

+        LVS_EX_GRIDLINES);

+

+    // We want 2 columns: Java version and path

+    mPathsListCtrl.InsertColumn(0, _T("Version"), LVCFMT_RIGHT, 60,  0);

+    mPathsListCtrl.InsertColumn(1, _T("Path"),     LVCFMT_LEFT, 386, 0);

+

+    mJavaFinder->findJavaPaths(&mPaths);

+    fillPathsList();

+    adjustButtons();

+

+    return TRUE;  // return TRUE  unless you set the focus to a control

+}

+

+// If you add a minimize button to your dialog, you will need the code below

+// to draw the icon.  For MFC applications using the document/view model,

+// this is automatically done for you by the framework.

+// [Note: MFC boilerplate, keep as-is]

+void CFindJava2Dlg::OnPaint() {

+    if (IsIconic()) {

+        CPaintDC dc(this); // device context for painting

+

+        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

+

+        // Center icon in client rectangle

+        int cxIcon = GetSystemMetrics(SM_CXICON);

+        int cyIcon = GetSystemMetrics(SM_CYICON);

+        CRect rect;

+        GetClientRect(&rect);

+        int x = (rect.Width() - cxIcon + 1) / 2;

+        int y = (rect.Height() - cyIcon + 1) / 2;

+

+        // Draw the icon

+        dc.DrawIcon(x, y, m_hIcon);

+    } else {

+        CDialog::OnPaint();

+    }

+}

+

+// The system calls this function to obtain the cursor to display while the user drags

+// the minimized window. [Note: MFC boilerplate, keep as-is]

+HCURSOR CFindJava2Dlg::OnQueryDragIcon() {

+    return static_cast<HCURSOR>(m_hIcon);

+}

+

+// Button add has been pressed; use file dialog and add path if it's a valid java.exe

+void CFindJava2Dlg::OnBnClickedButtonAdd() {

+    CFileDialog fileDlg(

+        TRUE,           // true=open dialog,  false=save-as dialog

+        _T("exe"),      // lpszDefExt 

+        _T("java.exe"), // lpszFileName 

+        OFN_FILEMUSTEXIST || OFN_PATHMUSTEXIST,

+        NULL,           // lpszFilter

+        this);          // pParentWnd

+

+    if (fileDlg.DoModal() == IDOK) {

+        CString path = fileDlg.GetPathName();

+

+        CJavaPath javaPath;

+        if (!mJavaFinder->checkJavaPath(path, &javaPath)) {

+            CString msg;

+            if (javaPath.mVersion > 0) {

+                msg.Format(_T("Insufficient Java Version found: expected %s, got %s"), 

+                           CJavaPath(mJavaFinder->getMinVersion(), CPath()).getVersion(),

+                           javaPath.getVersion());

+            } else {

+                msg.Format(_T("No valid Java Version found for %s"), path);

+            }

+            AfxMessageBox(msg, MB_OK);

+

+        } else {

+            if (mPaths.find(javaPath) == mPaths.end()) {

+                // Path isn't known yet so add it and refresh the list.

+                mPaths.insert(javaPath);

+                fillPathsList();

+            }

+

+            // Select item in list and set mSelectedIndex

+            selectPath(-1 /*index*/, &javaPath);

+        }

+    }

+}

+

+// An item in the list has been selected, select checkmark and set mSelectedIndex.

+void CFindJava2Dlg::OnNMClickPathList(NMHDR *pNMHDR, LRESULT *pResult) {

+    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);

+    int index = pNMItemActivate->iItem;

+    selectPath(index, nullptr);

+    *pResult = TRUE;

+}

+

+// An item in the list has changed, toggle checkmark as needed.

+void CFindJava2Dlg::OnLvnItemchangedPathList(NMHDR *pNMHDR, LRESULT *pResult) {

+    *pResult = FALSE;

+    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

+

+    if ((pNMLV->uChanged & LVIF_STATE) != 0) {

+        // Item's state has changed. Check the selection to see if it needs to be adjusted.

+        int index = pNMLV->iItem;

+

+        UINT oldState = pNMLV->uOldState;

+        UINT newState = pNMLV->uNewState;

+

+        if ((oldState & LVIS_STATEIMAGEMASK) != 0 || (newState & LVIS_STATEIMAGEMASK) != 0) {

+            // Checkbox uses the STATEIMAGE: 1 for unchecked, 2 for checked.

+            // Checkbox is checked when (old/new-state & state-image-mask) == INDEXTOSTATEIMAGEMASK(2).

+

+            bool oldChecked = (oldState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2);

+            bool newChecked = (newState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2);

+

+            if (oldChecked && !newChecked && index == mSelectedIndex) {

+                mSelectedIndex = -1;

+                adjustButtons();

+            } else if (!oldChecked && newChecked && index != mSelectedIndex) {

+                // Uncheck any checked rows if any

+                for (int n = mPathsListCtrl.GetItemCount() - 1; n >= 0; --n) {

+                    if (n != index && mPathsListCtrl.GetCheck(n)) {

+                        mPathsListCtrl.SetCheck(n, FALSE);

+                    }

+                }

+

+                mSelectedIndex = index;

+                adjustButtons();

+            }

+            // We handled this case, don't dispatch it further

+            *pResult = TRUE;

+        }

+    }

+}

+

+// -----

+

+const CJavaPath& CFindJava2Dlg::getSelectedPath() {

+    int i = 0;

+    for (const CJavaPath &p : mPaths) {

+        if (i == mSelectedIndex) {

+            return p;

+        }

+        ++i;

+    }

+

+    return CJavaPath::sEmpty;

+}

+

+

+void CFindJava2Dlg::fillPathsList() {

+    mPathsListCtrl.DeleteAllItems();

+    int index = 0;

+

+    for (const CJavaPath& pv : mPaths) {

+        mPathsListCtrl.InsertItem(index, pv.getVersion());        // column 0 = version

+        mPathsListCtrl.SetItemText(index, COL_PATH, pv.mPath);    // column 1 = path

+        mPathsListCtrl.SetCheck(index, mSelectedIndex == index);

+        ++index;

+    }

+}

+

+// Checks the given index if valid. Unchecks all other items.

+//

+// If index >= 0, it is used to select that item from the ListControl.

+// Otherwise if path != nullptr, it is used to find the item and select it.

+//

+// Side effect: in both cases, mSelectedIndex is set to the matching index or -1.

+//

+// If index is invalid and path isn't in the mPaths list, all items are unselected

+// so calling this with (0, nullptr) will clear the current selection.

+void CFindJava2Dlg::selectPath(int index, const CJavaPath *path) {

+

+    const CJavaPath *foundPath;

+    // If index is not defined, find the given path in the internal list.

+    // If path is not defined, find its index in the internal list.

+    int i = 0;

+    int n = mPathsListCtrl.GetItemCount();

+    for (const CJavaPath &p : mPaths) {

+        if (index < 0 && path != nullptr && p == *path) {

+            index = i;

+            foundPath = path;

+        } else if (index == i) {

+            foundPath = &p;

+        }

+

+        // uncheck any marked path

+        if (i != index && i < n && mPathsListCtrl.GetCheck(i)) {

+            mPathsListCtrl.SetCheck(i, FALSE);

+        }

+

+        ++i;

+    }

+

+    mSelectedIndex = index;

+    if (index >= 0 && index <= n) {

+        mPathsListCtrl.SetCheck(index, TRUE);

+    }

+

+    adjustButtons();

+}

+

+void CFindJava2Dlg::adjustButtons() {

+    int n = mPathsListCtrl.GetItemCount();

+    mOkButton.EnableWindow(mSelectedIndex >= 0 && mSelectedIndex < n);

+}

diff --git a/find_java2/src/FindJava2Dlg.h b/find_java2/src/FindJava2Dlg.h
new file mode 100755
index 0000000..7e0943c
--- /dev/null
+++ b/find_java2/src/FindJava2Dlg.h
@@ -0,0 +1,64 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#pragma once

+#include "afxwin.h"

+#include "JavaFinder.h"

+

+#include "resource.h"		// main symbols

+

+

+// CFindJava2Dlg dialog

+class CFindJava2Dlg : public CDialog {

+    // Construction

+public:

+    CFindJava2Dlg(CWnd* pParent = NULL);	// standard constructor

+

+    void setJavaFinder(CJavaFinder *javaFinder) { mJavaFinder = javaFinder;  }

+    const CJavaPath& getSelectedPath();

+

+    // Dialog Data

+    enum { IDD = IDD_FINDJAVA2_DIALOG };

+

+protected:

+    virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

+

+

+    // Implementation

+protected:

+    HICON m_hIcon;

+

+    // Generated message map functions

+    virtual BOOL OnInitDialog();

+    afx_msg void OnPaint();

+    afx_msg HCURSOR OnQueryDragIcon();

+    DECLARE_MESSAGE_MAP()

+

+    afx_msg void OnBnClickedButtonAdd();

+    afx_msg void OnNMClickPathList(NMHDR *pNMHDR, LRESULT *pResult);

+    afx_msg void OnLvnItemchangedPathList(NMHDR *pNMHDR, LRESULT *pResult);

+

+private:

+    std::set<CJavaPath> mPaths;

+    int mSelectedIndex;

+    CJavaFinder *mJavaFinder;

+    CListCtrl mPathsListCtrl;

+    CButton mOkButton;

+

+    void fillPathsList();

+    void adjustButtons();

+    void selectPath(int index = -1, const CJavaPath *path = nullptr);

+};

diff --git a/find_java2/src/JavaFinder.cpp b/find_java2/src/JavaFinder.cpp
new file mode 100755
index 0000000..60a2e23
--- /dev/null
+++ b/find_java2/src/JavaFinder.cpp
@@ -0,0 +1,594 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#include "stdafx.h"

+#include "JavaFinder.h"

+#include "utils.h"

+

+#include <algorithm>        // std::sort and std::unique

+

+#define  _CRT_SECURE_NO_WARNINGS

+

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

+

+#define JF_REGISTRY_KEY         _T("Software\\Android\\FindJava2")

+#define JF_REGISTRY_VALUE_PATH  _T("JavaPath")

+#define JF_REGISTRY_VALUE_VERS  _T("JavaVers")

+

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

+

+

+// Extract the first thing that looks like (digit.digit+).

+// Note: this will break when java reports a version with major > 9.

+// However it will reasonably cope with "1.10", if that ever happens.

+static bool extractJavaVersion(const TCHAR *start,

+                               int length,

+                               CString *outVersionStr,

+                               int *outVersionInt) {

+    const TCHAR *end = start + length;

+    for (const TCHAR *c = start; c < end - 2; c++) {

+        if (isdigit(c[0]) &&

+            c[1] == '.' &&

+            isdigit(c[2])) {

+            const TCHAR *e = c + 2;

+            while (isdigit(e[1])) {

+                e++;

+            }

+            outVersionStr->SetString(c, e - c + 1);

+

+            // major is currently only 1 digit

+            int major = (*c - '0');

+            // add minor

+            int minor = 0;

+            for (int m = 1; *e != '.'; e--, m *= 10) {

+                minor += (*e - '0') * m;

+            }

+            *outVersionInt = JAVA_VERS_TO_INT(major, minor);

+            return true;

+        }

+    }

+    return false;

+}

+

+// Tries to invoke the java.exe at the given path and extract it's

+// version number.

+// - outVersionStr: not null, will capture version as a string (e.g. "1.6")

+// - outVersionInt: not null, will capture version as an int (see JavaPath.h).

+bool getJavaVersion(CPath &javaPath, CString *outVersionStr, int *outVersionInt) {

+    bool result = false;

+

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

+    //

+    // 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.Format(_T("\"%s\" -version"), (LPCTSTR) javaPath);

+

+    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)

+        // In FindJava2, we do not report these errors. Leave commented for reference.

+        // // if (gIsConsole || gIsDebug) displayLastError("CreatePipe failed: ");

+        return false;

+    }

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

+        // In FindJava2, we do not report these errors. Leave commented for reference.

+        // // if (gIsConsole || gIsDebug) 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 = CreateProcess(

+        NULL,                   // program path

+        (LPTSTR)((LPCTSTR) cmd),// 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);

+

+    // In FindJava2, we do not report these errors. Leave commented for reference.

+    // // if ((gIsConsole || gIsDebug) && !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.

+    TCHAR 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

+            // Note: ReadFile uses a char buffer, not a TCHAR one.

+            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 (result && index > 0) {

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

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

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

+        TCHAR *j = _tcsstr(first32, _T("java"));

+        TCHAR *v = _tcsstr(first32, _T("version"));

+        // In FindJava2, we do not report these errors. Leave commented for reference.

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

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

+        // // }

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

+            result = extractJavaVersion(first32, index, outVersionStr, outVersionInt);

+        }

+    }

+

+    return result;

+}

+

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

+

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

+// inOutPath should be the directory where we're looking at.

+// In output, it will be the java path we tested.

+// Returns the java version integer found (e.g. 1006 for 1.6).

+// Return 0 in case of error.

+static int checkPath(CPath *inOutPath) {

+

+    // Append java.exe to path if not already present

+    CString &p = (CString&)*inOutPath;

+    int n = p.GetLength();

+    if (n < 9 || p.Right(9).CompareNoCase(_T("\\java.exe")) != 0) {

+        inOutPath->Append(_T("java.exe"));

+    }

+

+    int result = 0;

+    PVOID oldWow64Value = disableWow64FsRedirection();

+    if (inOutPath->FileExists()) {

+        // Run java -version

+        // Reject the version if it's not at least our current minimum.

+        CString versionStr;

+        if (!getJavaVersion(*inOutPath, &versionStr, &result)) {

+            result = 0;

+        }

+    }

+

+    revertWow64FsRedirection(oldWow64Value);

+    return result;

+}

+

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

+// Returns the Java version found (e.g. 1006 for 1.6) or 0 in case of error.

+static int checkBinPath(CPath *inOutPath) {

+

+    // Append bin to path if not already present

+    CString &p = (CString&)*inOutPath;

+    int n = p.GetLength();

+    if (n < 4 || p.Right(4).CompareNoCase(_T("\\bin")) != 0) {

+        inOutPath->Append(_T("bin"));

+    }

+

+    return checkPath(inOutPath);

+}

+

+// Search java.exe in the environment

+static void findJavaInEnvPath(std::set<CJavaPath> *outPaths) {

+    ::SetLastError(0);

+

+    const TCHAR* envPath = _tgetenv(_T("JAVA_HOME"));

+    if (envPath != NULL) {

+        CPath p(envPath);

+        int v = checkBinPath(&p);

+        if (v > 0) {

+            outPaths->insert(CJavaPath(v, p));

+        }

+    }

+

+    envPath = _tgetenv(_T("PATH"));

+    if (envPath != NULL) {

+        // Otherwise look at the entries in the current path.

+        // If we find more than one, keep the one with the highest version.

+        CString pathTokens(envPath);

+        int curPos = 0;

+        CString tok;

+        do {

+            tok = pathTokens.Tokenize(_T(";"), curPos);

+            if (!tok.IsEmpty()) {

+                CPath p(tok);

+                int v = checkPath(&p);

+                if (v > 0) {

+                    outPaths->insert(CJavaPath(v, p));

+                }

+            }

+        } while (!tok.IsEmpty());

+    }

+}

+

+

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

+

+static bool getRegValue(const TCHAR *keyPath,

+                        const TCHAR *keyName,

+                        REGSAM access,

+                        CString *outValue) {

+    HKEY key;

+    LSTATUS status = RegOpenKeyEx(

+        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

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

+

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

+            ret = RegQueryValueEx(

+                key,                // hKey

+                keyName,            // lpValueName

+                NULL,               // lpReserved

+                NULL,               // lpType

+                (LPBYTE)buffer,     // lpData

+                &size);             // lpcbData

+

+            if (ret == ERROR_MORE_DATA) {

+                size *= 2;

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

+            } else {

+                buffer[size] = 0;

+            }

+        }

+

+        if (ret != ERROR_MORE_DATA) {

+            outValue->SetString(buffer);

+        }

+

+        free(buffer);

+        RegCloseKey(key);

+

+        return (ret != ERROR_MORE_DATA);

+    }

+

+    return false;

+}

+

+// Explore the registry to find a suitable version of Java.

+// Returns an int which is the version of Java found (e.g. 1006 for 1.6) and the

+// matching path in outJavaPath.

+// Returns 0 if nothing suitable was found.

+static int exploreJavaRegistry(const TCHAR *entry, REGSAM access, std::set<CJavaPath> *outPaths) {

+

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

+    CPath rootKey(_T("SOFTWARE\\JavaSoft\\"));

+    rootKey.Append(entry);

+

+    CString currentVersion;

+    CPath subKey(rootKey);

+    if (getRegValue(subKey, _T("CurrentVersion"), access, &currentVersion)) {

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

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

+        subKey.Append(currentVersion);

+        CString value;

+        if (getRegValue(subKey, _T("JavaHome"), access, &value)) {

+            CPath javaHome(value);

+            int v = checkBinPath(&javaHome);

+            if (v > 0) {

+                outPaths->insert(CJavaPath(v, javaHome));

+            }

+        }

+    }

+

+    // Try again, but this time look at all the versions available

+    HKEY javaHomeKey;

+    LSTATUS status = RegOpenKeyEx(

+        HKEY_LOCAL_MACHINE,         // hKey

+        _T("SOFTWARE\\JavaSoft"),   // lpSubKey

+        0,                          // ulOptions

+        KEY_READ | access,          // samDesired

+        &javaHomeKey);              // phkResult

+    if (status == ERROR_SUCCESS) {

+        TCHAR name[MAX_PATH + 1];

+        DWORD index = 0;

+        CPath javaHome;

+        for (LONG result = ERROR_SUCCESS; result == ERROR_SUCCESS; index++) {

+            DWORD nameLen = MAX_PATH;

+            name[nameLen] = 0;

+            result = RegEnumKeyEx(

+                javaHomeKey,  // hKey

+                index,        // dwIndex

+                name,         // lpName

+                &nameLen,     // lpcName

+                NULL,         // lpReserved

+                NULL,         // lpClass

+                NULL,         // lpcClass,

+                NULL);        // lpftLastWriteTime

+            if (result == ERROR_SUCCESS && nameLen < MAX_PATH) {

+                name[nameLen] = 0;

+                CPath subKey(rootKey);

+                subKey.Append(name);

+

+                CString value;

+                if (getRegValue(subKey, _T("JavaHome"), access, &value)) {

+                    CPath javaHome(value);

+                    int v = checkBinPath(&javaHome);

+                    if (v > 0) {

+                        outPaths->insert(CJavaPath(v, javaHome));

+                    }

+                }

+            }

+        }

+

+        RegCloseKey(javaHomeKey);

+    }

+

+    return 0;

+}

+

+static void findJavaInRegistry(std::set<CJavaPath> *outPaths) {

+    // 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 tests should be equivalent so we just

+    // need the first case.

+

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

+    exploreJavaRegistry(_T("Java Runtime Environment"), 0, outPaths);

+    exploreJavaRegistry(_T("Java Development Kit"), 0, outPaths);

+

+    // Get the app sysinfo state (the one hidden by WOW64)

+    SYSTEM_INFO sysInfo;

+    GetSystemInfo(&sysInfo);

+    WORD programArch = sysInfo.wProcessorArchitecture;

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

+    GetNativeSystemInfo(&sysInfo);

+    WORD actualArch = sysInfo.wProcessorArchitecture;

+

+    // Only try to access the WOW64-32 redirected keys on a 64-bit system.

+    // There's no point in doing this on a 32-bit system.

+    if (actualArch == PROCESSOR_ARCHITECTURE_AMD64) {

+        if (programArch != PROCESSOR_ARCHITECTURE_INTEL) {

+            // If we did the 32-bit case earlier, don't do it twice.

+            exploreJavaRegistry(_T("Java Runtime Environment"), KEY_WOW64_32KEY, outPaths);

+            exploreJavaRegistry(_T("Java Development Kit"),     KEY_WOW64_32KEY, outPaths);

+

+        } else if (programArch != PROCESSOR_ARCHITECTURE_AMD64) {

+            // If we did the 64-bit case earlier, don't do it twice.

+            exploreJavaRegistry(_T("Java Runtime Environment"), KEY_WOW64_64KEY, outPaths);

+            exploreJavaRegistry(_T("Java Development Kit"),     KEY_WOW64_64KEY, outPaths);

+        }

+    }

+}

+

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

+

+static void checkProgramFiles(std::set<CJavaPath> *outPaths) {

+

+    TCHAR programFilesPath[MAX_PATH + 1];

+    HRESULT result = SHGetFolderPath(

+        NULL,                       // hwndOwner

+        CSIDL_PROGRAM_FILES,        // nFolder

+        NULL,                       // hToken

+        SHGFP_TYPE_CURRENT,         // dwFlags

+        programFilesPath);          // pszPath

+

+    CPath path(programFilesPath);

+    path.Append(_T("Java"));

+

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

+    if (!path.IsDirectory()) {

+        return;

+    }

+

+    CPath glob(path);

+    glob.Append(_T("j*"));

+

+    WIN32_FIND_DATA findData;

+    HANDLE findH = FindFirstFile(glob, &findData);

+    if (findH == INVALID_HANDLE_VALUE) {

+        return;

+    }

+    do {

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

+            CPath temp(path);

+            temp.Append(findData.cFileName);

+            // Check C:\\Program Files[x86]\\Java\\j*\\bin\\java.exe

+            int v = checkBinPath(&temp);

+            if (v > 0) {

+                outPaths->insert(CJavaPath(v, temp));

+            }

+        }

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

+    FindClose(findH);

+}

+

+static void findJavaInProgramFiles(std::set<CJavaPath> *outPaths) {

+    // 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.

+    checkProgramFiles(outPaths);

+

+    // 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();

+        checkProgramFiles(outPaths);

+        revertWow64FsRedirection(oldWow64Value);

+    }

+}

+

+//------

+

+

+CJavaFinder::CJavaFinder(int minVersion) : mMinVersion(minVersion) {

+}

+

+

+CJavaFinder::~CJavaFinder() {

+}

+

+/*

+ * Checks whether there's a recorded path in the registry and whether

+ * this path still points to a valid Java executable.

+ * Returns false if any of these do not match,

+ * Returns true if both condition match,

+ * outPath contains the result path when returning true.

+*/

+CJavaPath CJavaFinder::getRegistryPath() {

+    CString existing;

+    CRegKey rk;

+

+    if (rk.Open(HKEY_CURRENT_USER, JF_REGISTRY_KEY, KEY_READ) == ERROR_SUCCESS) {

+        ULONG sLen = MAX_PATH;

+        TCHAR s[MAX_PATH + 1];

+        if (rk.QueryStringValue(JF_REGISTRY_VALUE_PATH, s, &sLen) == ERROR_SUCCESS) {

+            existing.SetString(s);

+        }

+        rk.Close();

+    }

+

+    if (!existing.IsEmpty()) {

+        CJavaPath javaPath;

+        if (checkJavaPath(existing, &javaPath)) {

+            return javaPath;

+        }

+    }

+

+    return CJavaPath::sEmpty;

+}

+

+bool CJavaFinder::setRegistryPath(const CJavaPath &javaPath) {

+    CRegKey rk;

+

+    if (rk.Create(HKEY_CURRENT_USER, JF_REGISTRY_KEY) == ERROR_SUCCESS) {

+        bool ok = rk.SetStringValue(JF_REGISTRY_VALUE_PATH, javaPath.mPath, REG_SZ) == ERROR_SUCCESS &&

+                  rk.SetStringValue(JF_REGISTRY_VALUE_VERS, javaPath.getVersion(), REG_SZ) == ERROR_SUCCESS;

+        rk.Close();

+        return ok;

+    }

+

+    return false;

+}

+

+void CJavaFinder::findJavaPaths(std::set<CJavaPath> *paths) {

+    findJavaInEnvPath(paths);

+    findJavaInProgramFiles(paths);

+    findJavaInRegistry(paths);

+

+    // Exclude any entries that do not match the minimum version.

+    // The set is going to be fairly small so it's easier to do it here

+    // than add the filter logic in all the static methods above.

+    if (mMinVersion > 0) {

+        for (auto it = paths->begin(); it != paths->end(); ) {

+            if (it->mVersion < mMinVersion) {

+                it = paths->erase(it);  // C++11 set.erase returns an iterator to the *next* element

+            } else {

+                ++it;

+            }

+        }

+    }

+}

+

+bool CJavaFinder::checkJavaPath(const CString &path, CJavaPath *outPath) {

+    CPath p(path);

+

+    // try this path (if it ends with java.exe) or path\\java.exe

+    int v = checkPath(&p);

+    if (v == 0) {

+        // reset path and try path\\bin\\java.exe

+        p = CPath(path);

+        v = checkBinPath(&p);

+    }

+

+    if (v > 0) {

+        outPath->set(v, p);

+        return v >= mMinVersion;

+    }

+

+    return false;

+}

+

diff --git a/find_java2/src/JavaFinder.h b/find_java2/src/JavaFinder.h
new file mode 100755
index 0000000..c22b008
--- /dev/null
+++ b/find_java2/src/JavaFinder.h
@@ -0,0 +1,52 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#pragma once

+

+

+#include <set>                                  // STL std::set

+#include "JavaPath.h"

+

+class CJavaFinder {

+public:

+    // Creates a new JavaFinder.

+    // minVersion to accept, using JAVA_VERS_TO_INT macro. 0 to accept everything.

+    CJavaFinder(int minVersion = 0);

+    ~CJavaFinder();

+

+    int getMinVersion() const { return mMinVersion;  }

+

+    // Returns the path recorded in the registry.

+    // If there is no path or it is no longer valid, returns an empty string.

+    CJavaPath getRegistryPath();

+

+    // Sets the given path as the default to use in the registry.

+    // Returns true on success.

+    bool setRegistryPath(const CJavaPath &javaPath);

+

+    // Scans the registry, the environment and program files for potential Java.exe locations.

+    // Fills the given set with the tuples (version, path) found, guaranteed sorted and unique.

+    void findJavaPaths(std::set<CJavaPath> *paths);

+

+    // Checks the given path for a given java.exe.

+    // Input path variation tried are: path as-is, path/java.exe or path/bin/java.exe.

+    // Places the java path and version in outPath;

+    // Returns true if a java path was found *and* its version is at least mMinVersion.

+    bool checkJavaPath(const CString &path, CJavaPath *outPath);

+

+private:

+    int mMinVersion;

+};

diff --git a/find_java2/src/JavaPath.cpp b/find_java2/src/JavaPath.cpp
new file mode 100755
index 0000000..ebe30c5
--- /dev/null
+++ b/find_java2/src/JavaPath.cpp
@@ -0,0 +1,97 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#include "stdafx.h"

+#include "JavaPath.h"

+#include "utils.h"

+

+#define  _CRT_SECURE_NO_WARNINGS

+

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

+

+const CJavaPath CJavaPath::sEmpty = CJavaPath();

+

+CJavaPath::CJavaPath(int version, CPath path) : mVersion(version), mPath(path) {

+    mPath.Canonicalize();

+}

+

+bool CJavaPath::isEmpty() const {

+    return mVersion <= 0;

+}

+

+void CJavaPath::clear() {

+    mVersion = 0;

+    mPath = CPath();

+}

+

+void CJavaPath::set(int version, CPath path) {

+    mVersion = version;

+    mPath = path;

+    mPath.Canonicalize();

+}

+

+CString CJavaPath::getVersion() const {

+    CString s;

+    s.Format(_T("%d.%d"), JAVA_MAJOR(mVersion), JAVA_MINOR(mVersion));

+    return s;

+}

+

+

+bool CJavaPath::toShortPath() {

+    const TCHAR *longPath = mPath;

+    if (longPath == nullptr) {

+        return false;

+    }

+

+    DWORD lenShort = _tcslen(longPath) + 1;

+    TCHAR *shortPath = (TCHAR *)malloc(lenShort * sizeof(TCHAR));

+

+    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 = (TCHAR *)malloc(length);

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

+    }

+

+    if (length != 0) {

+        mPath = CPath(shortPath);

+    }

+

+    free(shortPath);

+    return length != 0;

+}

+

+bool CJavaPath::operator< (const CJavaPath& rhs) const {

+    if (mVersion != rhs.mVersion) {

+        // sort in reverse order on the version

+        return rhs.mVersion > mVersion;

+    }

+    // sort in normal order on the path

+    const CString &pl = mPath;

+    const CString &pr = rhs.mPath;

+    return pl.Compare(pr) < 0;

+}

+

+bool CJavaPath::operator== (const CJavaPath& rhs) const {

+    if (mVersion == rhs.mVersion) {

+        const CString &pl = mPath;

+        const CString &pr = rhs.mPath;

+        return pl.Compare(pr) == 0;

+    }

+    return false;

+}

diff --git a/find_java2/src/JavaPath.h b/find_java2/src/JavaPath.h
new file mode 100755
index 0000000..b7f40a5
--- /dev/null
+++ b/find_java2/src/JavaPath.h
@@ -0,0 +1,57 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#pragma once

+

+#include <atlpath.h>                            // ATL CPath

+

+

+// Transforms a Java major.minor number (e.g. "1.7") to internal int value (1007)

+#define JAVA_VERS_TO_INT(major, minor)  ((major) * 1000 + (minor))

+// Extracts the major part from the internal int major.minor number

+#define JAVA_MAJOR(majorMinor)          ((majorMinor) / 1000)

+// Extracts the minor part from the internal int major.minor number

+#define JAVA_MINOR(majorMinor)          ((majorMinor) % 1000)

+

+

+struct CJavaPath {

+    int mVersion;

+    CPath mPath;

+

+    // Static empty path that can be returned as a reference.

+    static const CJavaPath sEmpty;

+

+    CJavaPath() : mVersion(0) {}

+    CJavaPath(int version, CPath path);

+    void set(int version, CPath path);

+

+    // Returns true if path/version is empty/0

+    bool isEmpty() const;

+

+    // Clears path and version to 0

+    void clear();

+

+    // Converts the internal path into a short DOS path.

+    // Returns true if this was possible and false if the conversion failed.

+    bool toShortPath();

+

+    // Returns the version formatted as a string (e.g. "1.7" instead of 1007.)

+    CString getVersion() const;

+

+    // Operators < and == for this to be suitable in an ordered std::set

+    bool operator<  (const CJavaPath& rhs) const;

+    bool operator== (const CJavaPath& rhs) const;

+};

diff --git a/find_java2/src/WinLauncher2App.cpp b/find_java2/src/WinLauncher2App.cpp
new file mode 100755
index 0000000..392ad9e
--- /dev/null
+++ b/find_java2/src/WinLauncher2App.cpp
@@ -0,0 +1,154 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+

+#include "stdafx.h"

+#include "WinLauncher2App.h"

+

+#include "utils.h"

+#include "JavaFinder.h"

+#include "FindJava2Dlg.h"

+

+#ifdef _DEBUG

+#define new DEBUG_NEW

+#endif

+

+

+// CWinLauncher2App

+

+BEGIN_MESSAGE_MAP(CWinLauncher2App, CWinApp)

+    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)

+END_MESSAGE_MAP()

+

+

+// The one and only CWinLauncher2App object

+CWinLauncher2App theApp;

+

+class CLauncherCmdLineInfo : public CCommandLineInfo {

+public:

+    bool mDoHelp;

+    bool mDoForceUi;

+    bool mDoJava1_7;

+    CString mFilename;

+

+    CLauncherCmdLineInfo() : mDoHelp(false), mDoForceUi(false), mDoJava1_7(false) {}

+

+    virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast) {

+        // Expected command line:

+        // /h | help  : msg box with command line arguments

+        // /f | force : force UI selection

+        // /7         : require java 1.7

+        // path-to-launch

+

+        if (!bFlag) {

+            mFilename = pszParam;

+        } else if (_tcsnccmp(pszParam, _T("h"), 2) == 0) {

+            mDoHelp = true;

+        } else if (_tcsnccmp(pszParam, _T("f"), 2) == 0) {

+            mDoForceUi = true;

+        } else if (_tcsnccmp(pszParam, _T("7"), 2) == 0) {

+            mDoJava1_7 = true;

+        }

+    }

+};

+

+

+CWinLauncher2App::CWinLauncher2App() {

+    // support Restart Manager

+    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

+

+    // TODO: add construction code here,

+    // Place all significant initialization in InitInstance

+}

+

+BOOL CWinLauncher2App::InitInstance() {

+    // InitCommonControlsEx() is required on Windows XP if an application

+    // manifest specifies use of ComCtl32.dll version 6 or later to enable

+    // visual styles.  Otherwise, any window creation will fail.

+    INITCOMMONCONTROLSEX InitCtrls;

+    InitCtrls.dwSize = sizeof(InitCtrls);

+    // Set this to include all the common control classes you want to use

+    // in your application.

+    InitCtrls.dwICC = ICC_WIN95_CLASSES;

+    InitCommonControlsEx(&InitCtrls);

+

+    CWinApp::InitInstance();

+    AfxEnableControlContainer();

+

+    // Create the shell manager, in case the dialog contains

+    // any shell tree view or shell list view controls.

+    CShellManager *pShellManager = new CShellManager;

+

+    // Activate "Windows Native" visual manager for enabling themes in MFC controls

+    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

+

+    // Set CWinApp default registry key. Must be consistent with all apps using findjava2.

+    SetRegistryKey(_T("Android-FindJava2"));

+

+    // Use VERSIONINFO.FileDescription as the canonical app name

+    initUtils(NULL);

+

+    CLauncherCmdLineInfo cmdLine;

+    ParseCommandLine(cmdLine);

+

+    if (cmdLine.mDoHelp) {

+        const TCHAR *msg =

+            _T("WinLauncher2 [/7|/f|/h]\r\n")

+            _T("/7 : Requires Java 1.7 instead of 1.6\r\n")

+            _T("/f : Force UI\r\n")

+            _T("/h : Help\r\n");

+            AfxMessageBox(msg);

+        return FALSE; // quit without starting MFC app msg loop

+    }

+

+    CJavaFinder javaFinder(JAVA_VERS_TO_INT(1, cmdLine.mDoJava1_7 ? 7 : 6));

+    CJavaPath javaPath = javaFinder.getRegistryPath();

+    if (cmdLine.mDoForceUi || javaPath.isEmpty()) {

+        javaPath.clear();

+

+        CFindJava2Dlg dlg;

+        dlg.setJavaFinder(&javaFinder);

+        m_pMainWnd = &dlg;

+        INT_PTR nResponse = dlg.DoModal();

+

+        if (nResponse == IDOK) {

+            // Use choice selected by user and save in registry.

+            javaPath = dlg.getSelectedPath();

+            javaFinder.setRegistryPath(javaPath);

+        } else if (nResponse == IDCANCEL) {

+            // Canceled by user, exit silently.

+        } else if (nResponse == -1) {

+            TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");

+        }

+    }

+

+    if (!javaPath.isEmpty()) {

+        // TODO actually launch configured app instead of just printing path.

+        CString msg(_T("PLACEHOLDER TODO run app using "));

+        msg.Append(javaPath.mPath);

+        AfxMessageBox(msg);

+    }

+

+    // Delete the shell manager created above.

+    if (pShellManager != NULL) {

+        delete pShellManager;

+    }

+

+    // Since the dialog has been closed, return FALSE so that we exit the

+    // application, rather than start the application's message pump.

+    return FALSE;

+}

+

diff --git a/find_java2/src/WinLauncher2App.h b/find_java2/src/WinLauncher2App.h
new file mode 100755
index 0000000..11aca97
--- /dev/null
+++ b/find_java2/src/WinLauncher2App.h
@@ -0,0 +1,43 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#pragma once

+

+#ifndef __AFXWIN_H__

+	#error "include 'stdafx.h' before including this file for PCH"

+#endif

+

+#include "resource.h"		// main symbols

+

+

+// CWinLauncher2App:

+// See WinLauncher2.cpp for the implementation of this class

+//

+

+class CWinLauncher2App : public CWinApp {

+public:

+	CWinLauncher2App();

+

+// Overrides

+public:

+	virtual BOOL InitInstance();

+

+// Implementation

+

+	DECLARE_MESSAGE_MAP()

+};

+

+extern CWinLauncher2App theApp;
\ No newline at end of file
diff --git a/find_java2/src/utils.cpp b/find_java2/src/utils.cpp
new file mode 100755
index 0000000..7c8c66b
--- /dev/null
+++ b/find_java2/src/utils.cpp
@@ -0,0 +1,282 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#include "stdafx.h"

+#include "utils.h"

+

+// 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;

+

+// Application name used in error dialog. Defined using initUtils()

+static CString gAppName("Find Java 2");

+

+// Called by the application to initialize the app name used in error dialog boxes.

+void initUtils(const TCHAR *appName) {

+    if (appName != NULL) {

+        gAppName = CString(appName);

+        return;

+    }

+

+    // Try to get the VERSIONINFO.FileDescription and use as app name

+    // Errors are ignored, in which case the default app name is used.

+

+    // First get the module (aka app instance) filename.

+    TCHAR moduleName[MAX_PATH + 1];

+    DWORD sz = ::GetModuleFileName(NULL /*AfxGetInstanceHandle()*/, moduleName, MAX_PATH);

+    if (sz == 0) {

+        // GetModuleFileName failed. Do nothing.

+        return;

+    }

+    moduleName[sz] = '\0';  // make sure string is properly terminated.

+

+    // Get the size of the FileVersionInfo buffer

+    DWORD obsoleteHandle; // see http://blogs.msdn.com/b/oldnewthing/archive/2007/07/31/4138786.aspx

+    DWORD fviSize = ::GetFileVersionInfoSize(moduleName, &obsoleteHandle);

+    if (fviSize == 0) {

+        return; // do nothing on error

+    }

+

+    char *fviBuffer = new char[fviSize];

+    if (::GetFileVersionInfo(moduleName, 0, fviSize, fviBuffer) != 0) {

+        VOID *vBuffer;

+        UINT vLen;

+

+        struct LANGUAGE_CODEPAGE {

+            WORD mLanguage;

+            WORD mCodePage;

+        } *lgcpBuffer;

+

+        UINT lgcpSize;

+

+        // Read the list of languages and code pages (c.f. MSDN for VerQueryValue)

+        if (::VerQueryValue(fviBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lgcpBuffer, &lgcpSize) != 0 &&

+                lgcpSize >= sizeof(LANGUAGE_CODEPAGE)) {

+            // Use the first available language and code page

+            CString subBlock;

+            subBlock.Format(_T("\\StringFileInfo\\%04x%04x\\FileDescription"),

+                            lgcpBuffer[0].mLanguage,

+                            lgcpBuffer[0].mCodePage);

+            if (::VerQueryValue(fviBuffer, subBlock, &vBuffer, &vLen) != 0) {

+                gAppName.SetString((LPCTSTR)vBuffer, vLen);

+            }

+        }

+    }

+    delete[] fviBuffer;

+}

+

+CString getAppName() {

+    return gAppName;

+}

+

+

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

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

+    CString formatted;

+    va_list ap;

+    va_start(ap, text);

+    formatted.FormatV(text, ap);

+    va_end(ap);

+

+    // TODO global CString to get app name

+    MessageBox(NULL, formatted, gAppName, MB_OK | MB_ICONINFORMATION);

+}

+

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

+// If message is non-null, it is prepended to the last error string.

+CString getLastWin32Error(const TCHAR* message) {

+    DWORD err = GetLastError();

+    CString result;

+    LPTSTR errStr;

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

+                      FORMAT_MESSAGE_FROM_SYSTEM,

+                      NULL,                             /* lpSource */

+                      err,                              /* dwMessageId */

+                      0,                                /* dwLanguageId */

+                      (LPTSTR) &errStr,                 /* out lpBuffer */

+                      0,                                /* nSize */

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

+        if (message == NULL) {

+            result.Format(_T("[%d] %s"), err, errStr);

+        } else {

+            result.Format(_T("%s[%d] %s"), message, err, errStr);

+        }

+        LocalFree(errStr);

+    }

+    return result;

+}

+

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

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

+    CString formatted;

+    va_list ap;

+    va_start(ap, description);

+    formatted.FormatV(description, ap);

+    va_end(ap);

+

+    CString error = getLastWin32Error(NULL);

+    formatted.Append(_T("\r\n"));

+    formatted.Append(error);

+

+    if (gIsConsole) {

+        _ftprintf(stderr, _T("%s\n"), (LPCTSTR) formatted);

+    } else {

+        CString name(gAppName);

+        name.Append(_T(" - Error"));

+        MessageBox(NULL, formatted, name, 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 TCHAR *app, const TCHAR *params, const TCHAR *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 = CreateProcess(

+        app,                                        /* program path */

+        (TCHAR *)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 TCHAR *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 = CreateProcess(

+        NULL,                                       /* program path */

+        (LPTSTR)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) {

+    TCHAR programDir[MAX_PATH];

+    int ret = GetModuleFileName(NULL, programDir, sizeof(programDir) / sizeof(programDir[0]));

+    if (ret != 0) {

+        CPath dir(programDir);

+        dir.RemoveFileSpec();

+        *outDir = dir;

+        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(_T("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(_T("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);

+    }

+}

diff --git a/find_java2/src/utils.h b/find_java2/src/utils.h
new file mode 100755
index 0000000..3557f58
--- /dev/null
+++ b/find_java2/src/utils.h
@@ -0,0 +1,59 @@
+/*

+* Copyright (C) 2014 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.

+*/

+

+#pragma once

+

+#include <atlpath.h>                            // ATL CPath

+

+// Global flag indicating whether this is running in debug mode (more printfs)

+extern bool gIsDebug;

+// Global flag indicating whether this is running in console mode or GUI.

+// In console mode, errors are written on the console; in GUI they use a MsgBox.

+extern bool gIsConsole;

+

+// Must be called by the application to initialize the app name used in error dialog boxes.

+// If NULL is used, fetches VERSIONINFO.FileDescription from resources if available.

+void initUtils(const TCHAR *appName);

+

+// Returns the app name set in initUtils

+CString getAppName();

+

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

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

+

+// Displays GetLastError prefixed with a description in an error dialog box. Useful in console mode.

+void displayLastError(const TCHAR *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 TCHAR *app, const TCHAR *params, const TCHAR *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 TCHAR *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);