1 /*
   2  * Copyright (c) 2014, 2017, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 
  34 #include "Platform.h"
  35 
  36 #ifdef WINDOWS
  37 
  38 #include "JavaVirtualMachine.h"
  39 #include "WindowsPlatform.h"
  40 #include "Package.h"
  41 #include "Helpers.h"
  42 #include "PlatformString.h"
  43 #include "Macros.h"
  44 
  45 #include <map>
  46 #include <vector>
  47 #include <regex>
  48 
  49 
  50 //--------------------------------------------------------------------------------------------------
  51 
  52 class Registry {
  53 private:
  54     HKEY FKey;
  55     HKEY FOpenKey;
  56     bool FOpen;
  57 
  58 public:
  59     Registry(HKEY Key) {
  60         FOpen = false;
  61         FKey = Key;
  62     }
  63 
  64     ~Registry() {
  65         Close();
  66     }
  67 
  68     void Close() {
  69         if (FOpen == true) {
  70             RegCloseKey(FOpenKey);
  71         }
  72     }
  73 
  74     bool Open(TString SubKey) {
  75         bool result = false;
  76         Close();
  77 
  78         if (RegOpenKeyEx(FKey, SubKey.data(), 0, KEY_READ, &FOpenKey) == ERROR_SUCCESS) {
  79             result = true;
  80         }
  81 
  82         return result;
  83     }
  84 
  85     std::list<TString> GetKeys() {
  86         std::list<TString> result;
  87         DWORD count;
  88 
  89         if (RegQueryInfoKey(FOpenKey, NULL, NULL, NULL, NULL, NULL, NULL,
  90                             &count, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  91 
  92             DWORD length = 255;
  93             DynamicBuffer<TCHAR> buffer(length);
  94 
  95             for (unsigned int index = 0; index < count; index++) {
  96                 buffer.Zero();
  97                 DWORD status = RegEnumValue(FOpenKey, index, buffer.GetData(),
  98                                             &length, NULL, NULL, NULL, NULL);
  99 
 100                 while (status == ERROR_MORE_DATA) {
 101                     length = length * 2;
 102                     buffer.Resize(length);
 103                     status = RegEnumValue(FOpenKey, index, buffer.GetData(),
 104                                           &length, NULL, NULL, NULL, NULL);
 105                 }
 106 
 107                 if (status == ERROR_SUCCESS) {
 108                     TString value = buffer.GetData();
 109                     result.push_back(value);
 110                 }
 111             }
 112         }
 113 
 114         return result;
 115     }
 116 
 117     TString ReadString(TString Name) {
 118         TString result;
 119         DWORD length;
 120         DWORD dwRet;
 121         DynamicBuffer<wchar_t> buffer(0);
 122         length = 0;
 123 
 124         dwRet = RegQueryValueEx(FOpenKey, Name.data(), NULL, NULL, NULL, &length);
 125         if (dwRet == ERROR_MORE_DATA || dwRet == 0) {
 126             buffer.Resize(length + 1);
 127             dwRet = RegQueryValueEx(FOpenKey, Name.data(), NULL, NULL, (LPBYTE)buffer.GetData(), &length);
 128             result = buffer.GetData();
 129         }
 130 
 131         return result;
 132     }
 133 };
 134 
 135 //--------------------------------------------------------------------------------------------------
 136 
 137 WindowsPlatform::WindowsPlatform(void) : Platform(), GenericPlatform() {
 138     FMainThread = ::GetCurrentThreadId();
 139 }
 140 
 141 WindowsPlatform::~WindowsPlatform(void) {
 142 }
 143 
 144 TCHAR* WindowsPlatform::ConvertStringToFileSystemString(TCHAR* Source, bool &release) {
 145     // Not Implemented.
 146     return NULL;
 147 }
 148 
 149 TCHAR* WindowsPlatform::ConvertFileSystemStringToString(TCHAR* Source, bool &release) {
 150     // Not Implemented.
 151     return NULL;
 152 }
 153 
 154 void WindowsPlatform::SetCurrentDirectory(TString Value) {
 155     _wchdir(Value.data());
 156 }
 157 
 158 TString WindowsPlatform::GetPackageRootDirectory() {
 159     TString filename = GetModuleFileName();
 160     return FilePath::ExtractFilePath(filename);
 161 }
 162 
 163 TString WindowsPlatform::GetAppDataDirectory() {
 164     TString result;
 165     TCHAR path[MAX_PATH];
 166 
 167     if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path) == S_OK) {
 168         result = path;
 169     }
 170 
 171     return result;
 172 }
 173 
 174 #define BUFFER_SIZE 256
 175 
 176 // try to find current Java Home from registry
 177 //
 178 // HKLM\Software\JavaSoft\Java Runtime Environment\CurrentVersion
 179 // HKLM\Software\JavaSoft\Java Runtime Environment\[CurrentVersion]\JavaHome
 180 //
 181 // note that this has been changed in JDK9 to
 182 //
 183 // HKLM\Software\JavaSoft\JRE\CurrentVersion
 184 // HKLM\Software\JavaSoft\JRE\[CurrentVersion]\JavaHome
 185 //
 186 // return non-empty string as path if found
 187 // return empty string otherwise
 188 
 189 TString GetSystemJREForSubkey(TString javaRuntimeSubkey) {
 190     Registry registry(HKEY_LOCAL_MACHINE);
 191     TString result;
 192 
 193     if (registry.Open(javaRuntimeSubkey)) {
 194         TString version = registry.ReadString(_T("CurrentVersion"));
 195 
 196         if (!version.empty()) {
 197             if (registry.Open(javaRuntimeSubkey + TString(_T("\\")) + TString(version))) {
 198                 TString javaHome = registry.ReadString(_T("JavaHome"));
 199 
 200                 if (FilePath::DirectoryExists(javaHome)) {
 201                     result = javaHome;
 202                 }
 203             }
 204         }
 205     }
 206 
 207     return result;
 208 }
 209 
 210 TString WindowsPlatform::GetSystemJRE() {
 211     if (GetAppCDSState() != cdsDisabled) {
 212         //TODO throw exception
 213         return _T("");
 214     }
 215 
 216     TString result;
 217     result = GetSystemJREForSubkey(_T("SOFTWARE\\JavaSoft\\JRE"));
 218     if (!result.empty()) {
 219         return result;
 220     }
 221 
 222     result = GetSystemJREForSubkey(_T("SOFTWARE\\JavaSoft\\Java Runtime Environment"));
 223     if (!result.empty()) {
 224         return result;
 225     }
 226 
 227     return result;
 228 }
 229 
 230 void WindowsPlatform::ShowMessage(TString title, TString description) {
 231     MessageBox(NULL, description.data(), !title.empty() ? title.data() : description.data(), MB_ICONERROR | MB_OK);
 232 }
 233 
 234 void WindowsPlatform::ShowMessage(TString description) {
 235     TString appname = GetModuleFileName();
 236     appname = FilePath::ExtractFileName(appname);
 237     MessageBox(NULL, description.data(), appname.data(), MB_ICONERROR | MB_OK);
 238 }
 239 
 240 MessageResponse WindowsPlatform::ShowResponseMessage(TString title, TString description) {
 241     MessageResponse result = mrCancel;
 242 
 243     if (::MessageBox(NULL, description.data(), title.data(), MB_OKCANCEL) == IDOK) {
 244         result = mrOK;
 245     }
 246 
 247     return result;
 248 }
 249 
 250 //MessageResponse WindowsPlatform::ShowResponseMessage(TString description) {
 251 //    TString appname = GetModuleFileName();
 252 //    appname = FilePath::ExtractFileName(appname);
 253 //    return ShowResponseMessage(appname, description);
 254 //}
 255 
 256 TString WindowsPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) {
 257     TString result = FilePath::IncludeTrailingSeparater(RuntimePath) +
 258         _T("jre\\bin\\jli.dll");
 259 
 260     if (FilePath::FileExists(result) == false) {
 261         result = FilePath::IncludeTrailingSeparater(RuntimePath) +
 262             _T("bin\\jli.dll");
 263     }
 264 
 265     return result;
 266 }
 267 
 268 TString WindowsPlatform::GetSystemJVMLibraryFileName() {
 269     TString result;
 270     TString jvmPath = GetSystemJRE();
 271 
 272     if (jvmPath.empty() == false) {
 273         result = GetBundledJVMLibraryFileName(jvmPath);
 274     }
 275 
 276     return result;
 277 }
 278 
 279 ISectionalPropertyContainer* WindowsPlatform::GetConfigFile(TString FileName) {
 280     IniFile *result = new IniFile();
 281 
 282     if (result->LoadFromFile(FileName) == false) {
 283         // New property file format was not found, attempt to load old property file format.
 284         Helpers::LoadOldConfigFile(FileName, result);
 285     }
 286 
 287     return result;
 288 }
 289 
 290 TString WindowsPlatform::GetModuleFileName() {
 291     TString result;
 292     DynamicBuffer<wchar_t> buffer(MAX_PATH);
 293     ::GetModuleFileName(NULL, buffer.GetData(), buffer.GetSize());
 294 
 295     while (ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
 296         buffer.Resize(buffer.GetSize() * 2);
 297         ::GetModuleFileName(NULL, buffer.GetData(), buffer.GetSize());
 298     }
 299 
 300     result = buffer.GetData();
 301     return result;
 302 }
 303 
 304 Module WindowsPlatform::LoadLibrary(TString FileName) {
 305     return ::LoadLibrary(FileName.data());
 306 }
 307 
 308 void WindowsPlatform::FreeLibrary(Module AModule) {
 309     ::FreeLibrary((HMODULE)AModule);
 310 }
 311 
 312 Procedure WindowsPlatform::GetProcAddress(Module AModule, std::string MethodName) {
 313     return ::GetProcAddress((HMODULE)AModule, MethodName.c_str());
 314 }
 315 
 316 bool WindowsPlatform::IsMainThread() {
 317     bool result = (FMainThread == ::GetCurrentThreadId());
 318     return result;
 319 }
 320 
 321 static BOOL CALLBACK enumWindows(HWND winHandle, LPARAM lParam) {
 322     DWORD pid = (DWORD)lParam, wPid = 0;
 323     GetWindowThreadProcessId(winHandle, &wPid);
 324     if (pid == wPid)  {
 325         SetForegroundWindow(winHandle);
 326         return FALSE;
 327     }
 328     return TRUE;
 329 }
 330 
 331 void WindowsPlatform::reactivateAnotherInstance() {
 332     if (singleInstanceProcessId == 0) {
 333         printf("Unable to reactivate another instance, PID is undefined");
 334         return;
 335     }
 336     EnumWindows(&enumWindows, (LPARAM)singleInstanceProcessId);
 337 }
 338 
 339 // returns true if another instance is already running.
 340 // if false, we need to continue regular launch.
 341 bool WindowsPlatform::CheckForSingleInstance(TString name) {
 342     if (SingleInstance::getInstance(name)->IsAnotherInstanceRunning()) {
 343         // read PID
 344         DWORD pid = SingleInstance::getInstance(name)->readPid();
 345         if (pid != 0) {
 346             singleInstanceProcessId = pid;
 347             return true;
 348         }
 349     } else {
 350         // it is the first intance
 351         // write pid and continue regular launch
 352         SingleInstance::getInstance(name)->writePid(GetCurrentProcessId());
 353     }
 354     return false;
 355 }
 356 
 357 SingleInstance::SingleInstance(TString& name_): BUF_SIZE(256), _name(name_), _hMapFile(NULL), _pBuf(NULL) {
 358     _mutex = CreateMutex(NULL, TRUE, name_.data());
 359     _lastError = GetLastError();
 360     _sharedMemoryName = _T("Local\\javapackager-") + _name;
 361 }
 362 
 363 SingleInstance::~SingleInstance() {
 364     if (_pBuf != NULL) {
 365         UnmapViewOfFile(_pBuf);
 366         _pBuf = NULL;
 367     }
 368 
 369     if (_hMapFile != NULL) {
 370         CloseHandle(_hMapFile);
 371         _hMapFile = NULL;
 372     }
 373 
 374     if (_mutex != NULL) {
 375         CloseHandle(_mutex);
 376         _mutex = NULL;
 377     }
 378 }
 379 
 380 bool SingleInstance::writePid(DWORD pid) {
 381     _hMapFile = CreateFileMapping(
 382                  INVALID_HANDLE_VALUE,
 383                  NULL,
 384                  PAGE_READWRITE,
 385                  0,
 386                  BUF_SIZE,
 387                  _sharedMemoryName.data());
 388 
 389     if (_hMapFile == NULL) {
 390         return false;
 391     }
 392 
 393     _pBuf = (LPTSTR) MapViewOfFile(_hMapFile,
 394                         FILE_MAP_ALL_ACCESS,
 395                         0,
 396                         0,
 397                         BUF_SIZE);
 398 
 399     if (_pBuf == NULL) {
 400         CloseHandle(_hMapFile);
 401         _hMapFile = NULL;
 402         return false;
 403     }
 404 
 405     CopyMemory((PVOID)_pBuf, &pid, sizeof(DWORD));
 406 
 407     return true;
 408 }
 409 
 410 DWORD SingleInstance::readPid() {
 411     _hMapFile = OpenFileMapping(
 412                    FILE_MAP_ALL_ACCESS,
 413                    FALSE,
 414                    _sharedMemoryName.data());
 415 
 416     if (_hMapFile == NULL) {
 417         return 0;
 418     }
 419 
 420    _pBuf = (LPTSTR) MapViewOfFile(_hMapFile,
 421                FILE_MAP_ALL_ACCESS,
 422                0,
 423                0,
 424                BUF_SIZE);
 425 
 426     if (_pBuf == NULL) {
 427         CloseHandle(_hMapFile);
 428         _hMapFile = NULL;
 429         return 0;
 430     }
 431 
 432     DWORD pid = 0;
 433     CopyMemory(&pid, (PVOID)_pBuf,  sizeof(DWORD));
 434 
 435     return pid;
 436 }
 437 
 438 TPlatformNumber WindowsPlatform::GetMemorySize() {
 439     SYSTEM_INFO si;
 440     GetSystemInfo(&si);
 441     size_t result = (size_t)si.lpMaximumApplicationAddress;
 442     result = result / 1048576; // Convert from bytes to megabytes.
 443     return result;
 444 }
 445 
 446 std::vector<TString> WindowsPlatform::GetLibraryImports(const TString FileName) {
 447  std::vector<TString> result;
 448     WindowsLibrary library(FileName);
 449     result = library.GetImports();
 450  return result;
 451 }
 452 
 453 std::vector<TString> FilterList(std::vector<TString> &Items, std::wregex Pattern) {
 454     std::vector<TString> result;
 455 
 456     for (std::vector<TString>::iterator it = Items.begin(); it != Items.end(); ++it) {
 457         TString item = *it;
 458         std::wsmatch match;
 459 
 460         if (std::regex_search(item, match, Pattern)) {
 461             result.push_back(item);
 462         }
 463     }
 464     return result;
 465 }
 466 
 467 std::vector<TString> WindowsPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) {
 468  std::vector<TString> result;
 469 
 470     Package& package = Package::GetInstance();
 471     Macros& macros = Macros::GetInstance();
 472     TString runtimeDir = macros.ExpandMacros(package.GetJVMRuntimeDirectory());
 473     std::vector<TString> filelist = FilterList(Imports, std::wregex(_T("MSVCR.*.DLL"), std::regex_constants::icase));
 474 
 475     for (std::vector<TString>::iterator it = filelist.begin(); it != filelist.end(); ++it) {
 476         TString filename = *it;
 477         TString msvcr100FileName = FilePath::IncludeTrailingSeparater(runtimeDir) + _T("jre\\bin\\") + filename;
 478 
 479         if (FilePath::FileExists(msvcr100FileName) == true) {
 480             result.push_back(msvcr100FileName);
 481             break;
 482         }
 483         else {
 484             msvcr100FileName = FilePath::IncludeTrailingSeparater(runtimeDir) + _T("bin\\") + filename;
 485 
 486             if (FilePath::FileExists(msvcr100FileName) == true) {
 487                 result.push_back(msvcr100FileName);
 488                 break;
 489             }
 490         }
 491     }
 492 
 493  return result;
 494 }
 495 
 496 Process* WindowsPlatform::CreateProcess() {
 497     return new WindowsProcess();
 498 }
 499 
 500 #ifdef DEBUG
 501 bool WindowsPlatform::IsNativeDebuggerPresent() {
 502     bool result = false;
 503 
 504     if (IsDebuggerPresent() == TRUE) {
 505         result = true;
 506     }
 507 
 508     return result;
 509 }
 510 
 511 int WindowsPlatform::GetProcessID() {
 512     int pid = GetProcessId(GetCurrentProcess());
 513     return pid;
 514 }
 515 #endif //DEBUG
 516 
 517 //--------------------------------------------------------------------------------------------------
 518 
 519 WindowsJavaUserPreferences::WindowsJavaUserPreferences(void) : JavaUserPreferences() {
 520 }
 521 
 522 WindowsJavaUserPreferences::~WindowsJavaUserPreferences(void) {
 523 }
 524 
 525 // Java Preferences API encodes it's strings, so we need to match what Java does to work with Java.
 526 // CAVEAT: Java also does unicode encoding which this doesn't do yet. Should be sufficient for jvm args.
 527 // See WindowsPreferences.java toWindowsName()
 528 TString ConvertStringToJavaEcodedString(TString Value) {
 529     TString result;
 530     TCHAR* p = (TCHAR*)Value.c_str();
 531     TCHAR c = *p;
 532 
 533     while (c != 0) {
 534         switch (c) {
 535             case '\\':
 536                 result += _T("//");
 537                 break;
 538 
 539             case '/':
 540                 result += '\\';
 541                 break;
 542             default:
 543                 if ((c >= 'A') && (c <= 'Z')) {
 544                     result += '/';
 545                     result += c;
 546                 }
 547                 else
 548                     result += c;
 549                 break;
 550         }
 551 
 552         p++;
 553         c = *p;
 554     }
 555 
 556     return result;
 557 }
 558 
 559 // Java Preferences API encodes it's strings, so we need to match what Java does to work with Java.
 560 // CAVEAT: Java also does unicode encoding which this doesn't do yet. Should be sufficient for jvm args.
 561 // See WindowsPreferences.java toJavaName()
 562 TString ConvertJavaEcodedStringToString(TString Value) {
 563     TString result;
 564 
 565     for (size_t index = 0; index < Value.length(); index++) {
 566         TCHAR c = Value[index];
 567 
 568         switch (c) {
 569             case '/':
 570                 if ((index + 1) < Value.length()) {
 571                     index++;
 572                     TCHAR nextc = Value[index];
 573 
 574                     if (nextc >= 'A' && nextc <= 'Z') {
 575                         result += nextc;
 576                     }
 577                     else if (nextc == '/') {
 578                         result += '\\';
 579                     }
 580                 }
 581                 break;
 582             case '\\':
 583                 result += '/';
 584                 break;
 585             default:
 586                 result += c;
 587                 break;
 588         }
 589     }
 590 
 591     return result;
 592 }
 593 
 594 bool WindowsJavaUserPreferences::Load(TString Appid) {
 595     bool result = false;
 596     TString lappid = Helpers::ConvertIdToFilePath(Appid);
 597     lappid = ConvertStringToJavaEcodedString(Appid);
 598     TString registryKey = TString(_T("SOFTWARE\\JavaSoft\\Prefs\\")) + lappid + TString(_T("\\/J/V/M/User/Options"));
 599     Registry registry(HKEY_CURRENT_USER);
 600 
 601     if (registry.Open(registryKey) == true) {
 602         std::list<TString> keys = registry.GetKeys();
 603         OrderedMap<TString, TString> mapOfKeysAndValues;
 604 
 605         for (std::list<TString>::const_iterator iterator = keys.begin(); iterator != keys.end(); iterator++) {
 606             TString key = *iterator;
 607             TString value = registry.ReadString(key);
 608             key = ConvertJavaEcodedStringToString(key);
 609             value = ConvertJavaEcodedStringToString(value);
 610 
 611             if (key.empty() == false) {
 612                 mapOfKeysAndValues.Append(key, value);
 613                 result = true;
 614             }
 615         }
 616 
 617         FMap = mapOfKeysAndValues;
 618     }
 619 
 620     return result;
 621 }
 622 
 623 //--------------------------------------------------------------------------------------------------
 624 
 625 FileHandle::FileHandle(std::wstring FileName) {
 626     FHandle = ::CreateFile(FileName.data(), GENERIC_READ, FILE_SHARE_READ, NULL,
 627                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
 628 }
 629 
 630 FileHandle::~FileHandle() {
 631     if (IsValid() == true) {
 632         ::CloseHandle(FHandle);
 633     }
 634 }
 635 
 636 bool FileHandle::IsValid() {
 637     return FHandle != INVALID_HANDLE_VALUE;
 638 }
 639 
 640 HANDLE FileHandle::GetHandle() {
 641     return FHandle;
 642 }
 643 
 644 FileMappingHandle::FileMappingHandle(HANDLE FileHandle) {
 645     FHandle = ::CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
 646 }
 647 
 648 bool FileMappingHandle::IsValid() {
 649     return FHandle != NULL;
 650 }
 651 
 652 FileMappingHandle::~FileMappingHandle() {
 653     if (IsValid() == true) {
 654         ::CloseHandle(FHandle);
 655     }
 656 }
 657 
 658 HANDLE FileMappingHandle::GetHandle() {
 659     return FHandle;
 660 }
 661 
 662 FileData::FileData(HANDLE Handle) {
 663     FBaseAddress = ::MapViewOfFile(Handle, FILE_MAP_READ, 0, 0, 0);
 664 }
 665 
 666 FileData::~FileData() {
 667     if (IsValid() == true) {
 668         ::UnmapViewOfFile(FBaseAddress);
 669     }
 670 }
 671 
 672 bool FileData::IsValid() {
 673     return FBaseAddress != NULL;
 674 }
 675 
 676 LPVOID FileData::GetBaseAddress() {
 677     return FBaseAddress;
 678 }
 679 
 680 
 681 WindowsLibrary::WindowsLibrary(std::wstring FileName) {
 682     FFileName = FileName;
 683 }
 684 
 685 std::vector<TString> WindowsLibrary::GetImports() {
 686     std::vector<TString> result;
 687     FileHandle library(FFileName);
 688 
 689     if (library.IsValid() == true) {
 690         FileMappingHandle mapping(library.GetHandle());
 691 
 692         if (mapping.IsValid() == true) {
 693             FileData fileData(mapping.GetHandle());
 694 
 695             if (fileData.IsValid() == true) {
 696                 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileData.GetBaseAddress();
 697                 PIMAGE_FILE_HEADER pImgFileHdr = (PIMAGE_FILE_HEADER)fileData.GetBaseAddress();
 698 
 699                 if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
 700                     result = DumpPEFile(dosHeader);
 701                 }
 702             }
 703         }
 704     }
 705 
 706     return result;
 707 }
 708 
 709 // Given an RVA, look up the section header that encloses it and return a
 710 // pointer to its IMAGE_SECTION_HEADER
 711 PIMAGE_SECTION_HEADER WindowsLibrary::GetEnclosingSectionHeader(DWORD rva,
 712                                                 PIMAGE_NT_HEADERS pNTHeader) {
 713     PIMAGE_SECTION_HEADER result = 0;
 714     PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
 715 
 716     for (unsigned index = 0; index < pNTHeader->FileHeader.NumberOfSections; index++, section++) {
 717         // Is the RVA is within this section?
 718         if ((rva >= section->VirtualAddress) &&
 719             (rva < (section->VirtualAddress + section->Misc.VirtualSize))) {
 720             result = section;
 721         }
 722     }
 723 
 724     return result;
 725 }
 726 
 727 LPVOID WindowsLibrary::GetPtrFromRVA(DWORD rva, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase) {
 728     LPVOID result = 0;
 729     PIMAGE_SECTION_HEADER pSectionHdr = GetEnclosingSectionHeader(rva, pNTHeader);
 730 
 731     if (pSectionHdr != NULL) {
 732         INT delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
 733         result = (PVOID)(imageBase + rva - delta);
 734     }
 735 
 736     return result;
 737 }
 738 
 739 std::vector<TString> WindowsLibrary::GetImportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader) {
 740     std::vector<TString> result;
 741 
 742     // Look up where the imports section is located. Normally in the .idata section,
 743     // but not necessarily so. Therefore, grab the RVA from the data dir.
 744     DWORD importsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
 745 
 746     if (importsStartRVA != NULL) {
 747         // Get the IMAGE_SECTION_HEADER that contains the imports. This is
 748         // usually the .idata section, but doesn't have to be.
 749         PIMAGE_SECTION_HEADER pSection = GetEnclosingSectionHeader(importsStartRVA, pNTHeader);
 750 
 751         if (pSection != NULL) {
 752             PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA(importsStartRVA, pNTHeader,base);
 753 
 754             if (importDesc != NULL) {
 755                 while (true)
 756                 {
 757                     // See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR
 758                     if ((importDesc->TimeDateStamp == 0) && (importDesc->Name == 0))
 759                         break;
 760 
 761                     std::string filename = (char*)GetPtrFromRVA(importDesc->Name, pNTHeader, base);
 762                     result.push_back(PlatformString(filename));
 763                     importDesc++;   // advance to next IMAGE_IMPORT_DESCRIPTOR
 764                 }
 765             }
 766         }
 767     }
 768 
 769     return result;
 770 }
 771 
 772 std::vector<TString> WindowsLibrary::DumpPEFile(PIMAGE_DOS_HEADER dosHeader) {
 773     std::vector<TString> result;
 774     PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(dosHeader) + (DWORD)(dosHeader->e_lfanew));
 775 
 776     // Verify that the e_lfanew field gave us a reasonable
 777     // pointer and the PE signature.
 778     // TODO: To really fix JDK-8131321 this condition needs to be changed. There is a matching change
 779     // in JavaVirtualMachine.cpp that also needs to be changed.
 780     if (pNTHeader->Signature == IMAGE_NT_SIGNATURE) {
 781         DWORD base = (DWORD)dosHeader;
 782         result = GetImportsSection(base, pNTHeader);
 783     }
 784 
 785     return result;
 786 }
 787 
 788 //--------------------------------------------------------------------------------------------------
 789 
 790 #include <TlHelp32.h>
 791 
 792 WindowsJob::WindowsJob() {
 793     FHandle = NULL;
 794 }
 795 
 796 WindowsJob::~WindowsJob() {
 797     if (FHandle != NULL) {
 798         CloseHandle(FHandle);
 799     }
 800 }
 801 
 802 HANDLE WindowsJob::GetHandle() {
 803     if (FHandle == NULL) {
 804         FHandle = CreateJobObject(NULL, NULL); // GLOBAL
 805 
 806         if (FHandle == NULL)
 807         {
 808             ::MessageBox( 0, _T("Could not create job object"), _T("TEST"), MB_OK);
 809         }
 810         else
 811         {
 812             JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
 813 
 814             // Configure all child processes associated with the job to terminate when the
 815             jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
 816             if (0 == SetInformationJobObject(FHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
 817             {
 818                 ::MessageBox( 0, _T("Could not SetInformationJobObject"), _T("TEST"), MB_OK);
 819             }
 820         }
 821     }
 822 
 823     return FHandle;
 824 }
 825 
 826 // Initialize static member of WindowsProcess
 827 WindowsJob WindowsProcess::FJob;
 828 
 829 WindowsProcess::WindowsProcess() : Process() {
 830     FRunning = false;
 831 }
 832 
 833 WindowsProcess::~WindowsProcess() {
 834     Terminate();
 835 }
 836 
 837 void WindowsProcess::Cleanup() {
 838     CloseHandle(FProcessInfo.hProcess);
 839     CloseHandle(FProcessInfo.hThread);
 840 }
 841 
 842 bool WindowsProcess::IsRunning() {
 843     bool result = false;
 844 
 845     HANDLE handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
 846     PROCESSENTRY32 process = { 0 };
 847     process.dwSize = sizeof(process);
 848 
 849     if (::Process32First(handle, &process)) {
 850         do {
 851             if (process.th32ProcessID == FProcessInfo.dwProcessId) {
 852                 result = true;
 853                 break;
 854             }
 855         }
 856         while (::Process32Next(handle, &process));
 857     }
 858 
 859     CloseHandle(handle);
 860 
 861     return result;
 862 }
 863 
 864 bool WindowsProcess::Terminate() {
 865     bool result = false;
 866 
 867     if (IsRunning() == true && FRunning == true) {
 868         FRunning = false;
 869     }
 870 
 871     return result;
 872 }
 873 
 874 bool WindowsProcess::Execute(const TString Application, const std::vector<TString> Arguments, bool AWait) {
 875     bool result = false;
 876 
 877     if (FRunning == false) {
 878         FRunning = true;
 879 
 880         STARTUPINFO startupInfo;
 881         ZeroMemory(&startupInfo, sizeof(startupInfo));
 882         startupInfo.cb = sizeof(startupInfo);
 883         ZeroMemory(&FProcessInfo, sizeof(FProcessInfo));
 884 
 885         TString command = Application;
 886 
 887         for (std::vector<TString>::const_iterator iterator = Arguments.begin(); iterator != Arguments.end(); iterator++) {
 888             command += TString(_T(" ")) + *iterator;
 889         }
 890 
 891         if (::CreateProcess(Application.data(), (wchar_t*)command.data(), NULL,
 892             NULL, FALSE, 0, NULL, NULL, &startupInfo, &FProcessInfo) == FALSE) {
 893             TString message = PlatformString::Format(_T("Error: Unable to create process %s"), Application.data());
 894             throw Exception(message);
 895         }
 896         else {
 897             if (FJob.GetHandle() != NULL) {
 898                 if (::AssignProcessToJobObject(FJob.GetHandle(), FProcessInfo.hProcess) == 0) {
 899                     // Failed to assign process to job. It doesn't prevent anything from continuing so continue.
 900                 }
 901             }
 902 
 903             // Wait until child process exits.
 904             if (AWait == true) {
 905                 Wait();
 906                 // Close process and thread handles.
 907                 Cleanup();
 908             }
 909         }
 910     }
 911 
 912     return result;
 913 }
 914 
 915 bool WindowsProcess::Wait() {
 916     bool result = false;
 917 
 918     WaitForSingleObject(FProcessInfo.hProcess, INFINITE);
 919     return result;
 920 }
 921 
 922 TProcessID WindowsProcess::GetProcessID() {
 923     return FProcessInfo.dwProcessId;
 924 }
 925 
 926 bool WindowsProcess::ReadOutput() {
 927     bool result = false;
 928     //TODO implement
 929     return result;
 930 }
 931 
 932 void WindowsProcess::SetInput(TString Value) {
 933     //TODO implement
 934 }
 935 
 936 std::list<TString> WindowsProcess::GetOutput() {
 937     ReadOutput();
 938     return Process::GetOutput();
 939 }
 940 
 941 #endif //WINDOWS