1 /*
   2  * Copyright (c) 2014, 2016, 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 void WindowsPlatform::ShowMessage(TString title, TString description) {
 175     MessageBox(NULL, description.data(), !title.empty() ? title.data() : description.data(), MB_ICONERROR | MB_OK);
 176 }
 177 
 178 void WindowsPlatform::ShowMessage(TString description) {
 179     TString appname = GetModuleFileName();
 180     appname = FilePath::ExtractFileName(appname);
 181     MessageBox(NULL, description.data(), appname.data(), MB_ICONERROR | MB_OK);
 182 }
 183 
 184 MessageResponse WindowsPlatform::ShowResponseMessage(TString title, TString description) {
 185     MessageResponse result = mrCancel;
 186 
 187     if (::MessageBox(NULL, description.data(), title.data(), MB_OKCANCEL) == IDOK) {
 188         result = mrOK;
 189     }
 190 
 191     return result;
 192 }
 193 
 194 //MessageResponse WindowsPlatform::ShowResponseMessage(TString description) {
 195 //    TString appname = GetModuleFileName();
 196 //    appname = FilePath::ExtractFileName(appname);
 197 //    return ShowResponseMessage(appname, description);
 198 //}
 199 
 200 TString WindowsPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) {
 201     TString result = FilePath::IncludeTrailingSeparater(RuntimePath) +
 202         _T("jre\\bin\\jli.dll");
 203 
 204     if (FilePath::FileExists(result) == false) {
 205         result = FilePath::IncludeTrailingSeparater(RuntimePath) +
 206             _T("bin\\jli.dll");
 207     }
 208 
 209     return result;
 210 }
 211 
 212 ISectionalPropertyContainer* WindowsPlatform::GetConfigFile(TString FileName) {
 213     IniFile *result = new IniFile();
 214 
 215     if (result->LoadFromFile(FileName) == false) {
 216         // New property file format was not found, attempt to load old property file format.
 217         Helpers::LoadOldConfigFile(FileName, result);
 218     }
 219 
 220     return result;
 221 }
 222 
 223 TString WindowsPlatform::GetModuleFileName() {
 224     TString result;
 225     DynamicBuffer<wchar_t> buffer(MAX_PATH);
 226     ::GetModuleFileName(NULL, buffer.GetData(), buffer.GetSize());
 227 
 228     while (ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
 229         buffer.Resize(buffer.GetSize() * 2);
 230         ::GetModuleFileName(NULL, buffer.GetData(), buffer.GetSize());
 231     }
 232 
 233     result = buffer.GetData();
 234     return result;
 235 }
 236 
 237 Module WindowsPlatform::LoadLibrary(TString FileName) {
 238     return ::LoadLibrary(FileName.data());
 239 }
 240 
 241 void WindowsPlatform::FreeLibrary(Module AModule) {
 242     ::FreeLibrary((HMODULE)AModule);
 243 }
 244 
 245 Procedure WindowsPlatform::GetProcAddress(Module AModule, std::string MethodName) {
 246     return ::GetProcAddress((HMODULE)AModule, MethodName.c_str());
 247 }
 248 
 249 bool WindowsPlatform::IsMainThread() {
 250     bool result = (FMainThread == ::GetCurrentThreadId());
 251     return result;
 252 }
 253 
 254 TPlatformNumber WindowsPlatform::GetMemorySize() {
 255     SYSTEM_INFO si;
 256     GetSystemInfo(&si);
 257     size_t result = (size_t)si.lpMaximumApplicationAddress;
 258     result = result / 1048576; // Convert from bytes to megabytes.
 259     return result;
 260 }
 261 
 262 std::vector<TString> WindowsPlatform::GetLibraryImports(const TString FileName) {
 263  std::vector<TString> result;
 264     WindowsLibrary library(FileName);
 265     result = library.GetImports();
 266  return result;
 267 }
 268 
 269 std::vector<TString> FilterList(std::vector<TString> &Items, std::wregex Pattern) {
 270     std::vector<TString> result;
 271 
 272     for (std::vector<TString>::iterator it = Items.begin(); it != Items.end(); ++it) {
 273         TString item = *it;
 274         std::wsmatch match;
 275 
 276         if (std::regex_search(item, match, Pattern)) {
 277             result.push_back(item);
 278         }
 279     }
 280     return result;
 281 }
 282 
 283 std::vector<TString> WindowsPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) {
 284  std::vector<TString> result;
 285 
 286     Package& package = Package::GetInstance();
 287     Macros& macros = Macros::GetInstance();
 288     TString runtimeDir = macros.ExpandMacros(package.GetJVMRuntimeDirectory());
 289     std::vector<TString> filelist = FilterList(Imports, std::wregex(_T("MSVCR.*.DLL"), std::regex_constants::icase));
 290 
 291     for (std::vector<TString>::iterator it = filelist.begin(); it != filelist.end(); ++it) {
 292         TString filename = *it;
 293         TString msvcr100FileName = FilePath::IncludeTrailingSeparater(runtimeDir) + _T("jre\\bin\\") + filename;
 294 
 295         if (FilePath::FileExists(msvcr100FileName) == true) {
 296             result.push_back(msvcr100FileName);
 297             break;
 298         }
 299         else {
 300             msvcr100FileName = FilePath::IncludeTrailingSeparater(runtimeDir) + _T("bin\\") + filename;
 301 
 302             if (FilePath::FileExists(msvcr100FileName) == true) {
 303                 result.push_back(msvcr100FileName);
 304                 break;
 305             }
 306         }
 307     }
 308 
 309  return result;
 310 }
 311 
 312 Process* WindowsPlatform::CreateProcess() {
 313     return new WindowsProcess();
 314 }
 315 
 316 #ifdef DEBUG
 317 bool WindowsPlatform::IsNativeDebuggerPresent() {
 318     bool result = false;
 319 
 320     if (IsDebuggerPresent() == TRUE) {
 321         result = true;
 322     }
 323 
 324     return result;
 325 }
 326 
 327 int WindowsPlatform::GetProcessID() {
 328     int pid = GetProcessId(GetCurrentProcess());
 329     return pid;
 330 }
 331 #endif //DEBUG
 332 
 333 //--------------------------------------------------------------------------------------------------
 334 
 335 WindowsJavaUserPreferences::WindowsJavaUserPreferences(void) : JavaUserPreferences() {
 336 }
 337 
 338 WindowsJavaUserPreferences::~WindowsJavaUserPreferences(void) {
 339 }
 340 
 341 // Java Preferences API encodes it's strings, so we need to match what Java does to work with Java.
 342 // CAVEAT: Java also does unicode encoding which this doesn't do yet. Should be sufficient for jvm args.
 343 // See WindowsPreferences.java toWindowsName()
 344 TString ConvertStringToJavaEcodedString(TString Value) {
 345     TString result;
 346     TCHAR* p = (TCHAR*)Value.c_str();
 347     TCHAR c = *p;
 348 
 349     while (c != 0) {
 350         switch (c) {
 351             case '\\':
 352                 result += _T("//");
 353                 break;
 354 
 355             case '/':
 356                 result += '\\';
 357                 break;
 358             default:
 359                 if ((c >= 'A') && (c <= 'Z')) {
 360                     result += '/';
 361                     result += c;
 362                 }
 363                 else
 364                     result += c;
 365                 break;
 366         }
 367 
 368         p++;
 369         c = *p;
 370     }
 371 
 372     return result;
 373 }
 374 
 375 // Java Preferences API encodes it's strings, so we need to match what Java does to work with Java.
 376 // CAVEAT: Java also does unicode encoding which this doesn't do yet. Should be sufficient for jvm args.
 377 // See WindowsPreferences.java toJavaName()
 378 TString ConvertJavaEcodedStringToString(TString Value) {
 379     TString result;
 380 
 381     for (size_t index = 0; index < Value.length(); index++) {
 382         TCHAR c = Value[index];
 383 
 384         switch (c) {
 385             case '/':
 386                 if ((index + 1) < Value.length()) {
 387                     index++;
 388                     TCHAR nextc = Value[index];
 389 
 390                     if (nextc >= 'A' && nextc <= 'Z') {
 391                         result += nextc;
 392                     }
 393                     else if (nextc == '/') {
 394                         result += '\\';
 395                     }
 396                 }
 397                 break;
 398             case '\\':
 399                 result += '/';
 400                 break;
 401             default:
 402                 result += c;
 403                 break;
 404         }
 405     }
 406 
 407     return result;
 408 }
 409 
 410 bool WindowsJavaUserPreferences::Load(TString Appid) {
 411     bool result = false;
 412     TString lappid = Helpers::ConvertIdToFilePath(Appid);
 413     lappid = ConvertStringToJavaEcodedString(Appid);
 414     TString registryKey = TString(_T("SOFTWARE\\JavaSoft\\Prefs\\")) + lappid + TString(_T("\\/J/V/M/User/Options"));
 415     Registry registry(HKEY_CURRENT_USER);
 416 
 417     if (registry.Open(registryKey) == true) {
 418         std::list<TString> keys = registry.GetKeys();
 419         OrderedMap<TString, TString> mapOfKeysAndValues;
 420 
 421         for (std::list<TString>::const_iterator iterator = keys.begin(); iterator != keys.end(); iterator++) {
 422             TString key = *iterator;
 423             TString value = registry.ReadString(key);
 424             key = ConvertJavaEcodedStringToString(key);
 425             value = ConvertJavaEcodedStringToString(value);
 426 
 427             if (key.empty() == false) {
 428                 mapOfKeysAndValues.Append(key, value);
 429                 result = true;
 430             }
 431         }
 432 
 433         FMap = mapOfKeysAndValues;
 434     }
 435 
 436     return result;
 437 }
 438 
 439 //--------------------------------------------------------------------------------------------------
 440 
 441 FileHandle::FileHandle(std::wstring FileName) {
 442     FHandle = ::CreateFile(FileName.data(), GENERIC_READ, FILE_SHARE_READ, NULL,
 443                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
 444 }
 445 
 446 FileHandle::~FileHandle() {
 447     if (IsValid() == true) {
 448         ::CloseHandle(FHandle);
 449     }
 450 }
 451 
 452 bool FileHandle::IsValid() {
 453     return FHandle != INVALID_HANDLE_VALUE;
 454 }
 455 
 456 HANDLE FileHandle::GetHandle() {
 457     return FHandle;
 458 }
 459 
 460 FileMappingHandle::FileMappingHandle(HANDLE FileHandle) {
 461     FHandle = ::CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
 462 }
 463 
 464 bool FileMappingHandle::IsValid() {
 465     return FHandle != NULL;
 466 }
 467 
 468 FileMappingHandle::~FileMappingHandle() {
 469     if (IsValid() == true) {
 470         ::CloseHandle(FHandle);
 471     }
 472 }
 473 
 474 HANDLE FileMappingHandle::GetHandle() {
 475     return FHandle;
 476 }
 477 
 478 FileData::FileData(HANDLE Handle) {
 479     FBaseAddress = ::MapViewOfFile(Handle, FILE_MAP_READ, 0, 0, 0);
 480 }
 481 
 482 FileData::~FileData() {
 483     if (IsValid() == true) {
 484         ::UnmapViewOfFile(FBaseAddress);
 485     }
 486 }
 487 
 488 bool FileData::IsValid() {
 489     return FBaseAddress != NULL;
 490 }
 491 
 492 LPVOID FileData::GetBaseAddress() {
 493     return FBaseAddress;
 494 }
 495 
 496 
 497 WindowsLibrary::WindowsLibrary(std::wstring FileName) {
 498     FFileName = FileName;
 499 }
 500 
 501 std::vector<TString> WindowsLibrary::GetImports() {
 502     std::vector<TString> result;
 503     FileHandle library(FFileName);
 504 
 505     if (library.IsValid() == true) {
 506         FileMappingHandle mapping(library.GetHandle());
 507 
 508         if (mapping.IsValid() == true) {
 509             FileData fileData(mapping.GetHandle());
 510 
 511             if (fileData.IsValid() == true) {
 512                 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileData.GetBaseAddress();
 513                 PIMAGE_FILE_HEADER pImgFileHdr = (PIMAGE_FILE_HEADER)fileData.GetBaseAddress();
 514 
 515                 if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
 516                     result = DumpPEFile(dosHeader);
 517                 }
 518             }
 519         }
 520     }
 521 
 522     return result;
 523 }
 524 
 525 // Given an RVA, look up the section header that encloses it and return a
 526 // pointer to its IMAGE_SECTION_HEADER
 527 PIMAGE_SECTION_HEADER WindowsLibrary::GetEnclosingSectionHeader(DWORD rva,
 528                                                 PIMAGE_NT_HEADERS pNTHeader) {
 529     PIMAGE_SECTION_HEADER result = 0;
 530     PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
 531 
 532     for (unsigned index = 0; index < pNTHeader->FileHeader.NumberOfSections; index++, section++) {
 533         // Is the RVA is within this section?
 534         if ((rva >= section->VirtualAddress) &&
 535             (rva < (section->VirtualAddress + section->Misc.VirtualSize))) {
 536             result = section;
 537         }
 538     }
 539 
 540     return result;
 541 }
 542 
 543 LPVOID WindowsLibrary::GetPtrFromRVA(DWORD rva, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase) {
 544     LPVOID result = 0;
 545     PIMAGE_SECTION_HEADER pSectionHdr = GetEnclosingSectionHeader(rva, pNTHeader);
 546 
 547     if (pSectionHdr != NULL) {
 548         INT delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
 549         result = (PVOID)(imageBase + rva - delta);
 550     }
 551 
 552     return result;
 553 }
 554 
 555 std::vector<TString> WindowsLibrary::GetImportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader) {
 556     std::vector<TString> result;
 557 
 558     // Look up where the imports section is located. Normally in the .idata section,
 559     // but not necessarily so. Therefore, grab the RVA from the data dir.
 560     DWORD importsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
 561 
 562     if (importsStartRVA != NULL) {
 563         // Get the IMAGE_SECTION_HEADER that contains the imports. This is
 564         // usually the .idata section, but doesn't have to be.
 565         PIMAGE_SECTION_HEADER pSection = GetEnclosingSectionHeader(importsStartRVA, pNTHeader);
 566 
 567         if (pSection != NULL) {
 568             PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA(importsStartRVA, pNTHeader,base);
 569 
 570             if (importDesc != NULL) {
 571                 while (true)
 572                 {
 573                     // See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR
 574                     if ((importDesc->TimeDateStamp == 0) && (importDesc->Name == 0))
 575                         break;
 576 
 577                     std::string filename = (char*)GetPtrFromRVA(importDesc->Name, pNTHeader, base);
 578                     result.push_back(PlatformString(filename));
 579                     importDesc++;   // advance to next IMAGE_IMPORT_DESCRIPTOR
 580                 }
 581             }
 582         }
 583     }
 584 
 585     return result;
 586 }
 587 
 588 std::vector<TString> WindowsLibrary::DumpPEFile(PIMAGE_DOS_HEADER dosHeader) {
 589     std::vector<TString> result;
 590     PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(dosHeader) + (DWORD)(dosHeader->e_lfanew));
 591 
 592     // Verify that the e_lfanew field gave us a reasonable
 593     // pointer and the PE signature.
 594     // TODO: To really fix JDK-8131321 this condition needs to be changed. There is a matching change
 595     // in JavaVirtualMachine.cpp that also needs to be changed.
 596     if (pNTHeader->Signature == IMAGE_NT_SIGNATURE) {
 597         DWORD base = (DWORD)dosHeader;
 598         result = GetImportsSection(base, pNTHeader);
 599     }
 600 
 601     return result;
 602 }
 603 
 604 //--------------------------------------------------------------------------------------------------
 605 
 606 #include <TlHelp32.h>
 607 
 608 WindowsJob::WindowsJob() {
 609     FHandle = NULL;
 610 }
 611 
 612 WindowsJob::~WindowsJob() {
 613     if (FHandle != NULL) {
 614         CloseHandle(FHandle);
 615     }
 616 }
 617 
 618 HANDLE WindowsJob::GetHandle() {
 619     if (FHandle == NULL) {
 620         FHandle = CreateJobObject(NULL, NULL); // GLOBAL
 621 
 622         if (FHandle == NULL)
 623         {
 624             ::MessageBox( 0, _T("Could not create job object"), _T("TEST"), MB_OK);
 625         }
 626         else
 627         {
 628             JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
 629 
 630             // Configure all child processes associated with the job to terminate when the
 631             jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
 632             if (0 == SetInformationJobObject(FHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
 633             {
 634                 ::MessageBox( 0, _T("Could not SetInformationJobObject"), _T("TEST"), MB_OK);
 635             }
 636         }
 637     }
 638 
 639     return FHandle;
 640 }
 641 
 642 // Initialize static member of WindowsProcess
 643 WindowsJob WindowsProcess::FJob;
 644 
 645 WindowsProcess::WindowsProcess() : Process() {
 646     FRunning = false;
 647 }
 648 
 649 WindowsProcess::~WindowsProcess() {
 650     Terminate();
 651 }
 652 
 653 void WindowsProcess::Cleanup() {
 654     CloseHandle(FProcessInfo.hProcess);
 655     CloseHandle(FProcessInfo.hThread);
 656 }
 657 
 658 bool WindowsProcess::IsRunning() {
 659     bool result = false;
 660 
 661     HANDLE handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
 662     PROCESSENTRY32 process = { 0 };
 663     process.dwSize = sizeof(process);
 664 
 665     if (::Process32First(handle, &process)) {
 666         do {
 667             if (process.th32ProcessID == FProcessInfo.dwProcessId) {
 668                 result = true;
 669                 break;
 670             }
 671         }
 672         while (::Process32Next(handle, &process));
 673     }
 674 
 675     CloseHandle(handle);
 676 
 677     return result;
 678 }
 679 
 680 bool WindowsProcess::Terminate() {
 681     bool result = false;
 682 
 683     if (IsRunning() == true && FRunning == true) {
 684         FRunning = false;
 685     }
 686 
 687     return result;
 688 }
 689 
 690 bool WindowsProcess::Execute(const TString Application, const std::vector<TString> Arguments, bool AWait) {
 691     bool result = false;
 692 
 693     if (FRunning == false) {
 694         FRunning = true;
 695 
 696         STARTUPINFO startupInfo;
 697         ZeroMemory(&startupInfo, sizeof(startupInfo));
 698         startupInfo.cb = sizeof(startupInfo);
 699         ZeroMemory(&FProcessInfo, sizeof(FProcessInfo));
 700 
 701         TString command = Application;
 702 
 703         for (std::vector<TString>::const_iterator iterator = Arguments.begin(); iterator != Arguments.end(); iterator++) {
 704             command += TString(_T(" ")) + *iterator;
 705         }
 706 
 707         if (::CreateProcess(Application.data(), (wchar_t*)command.data(), NULL,
 708             NULL, FALSE, 0, NULL, NULL, &startupInfo, &FProcessInfo) == FALSE) {
 709             TString message = PlatformString::Format(_T("Error: Unable to create process %s"), Application.data());
 710             throw Exception(message);
 711         }
 712         else {
 713             if (FJob.GetHandle() != NULL) {
 714                 if (::AssignProcessToJobObject(FJob.GetHandle(), FProcessInfo.hProcess) == 0) {
 715                     // Failed to assign process to job. It doesn't prevent anything from continuing so continue.
 716                 }
 717             }
 718 
 719             // Wait until child process exits.
 720             if (AWait == true) {
 721                 Wait();
 722                 // Close process and thread handles.
 723                 Cleanup();
 724             }
 725         }
 726     }
 727 
 728     return result;
 729 }
 730 
 731 bool WindowsProcess::Wait() {
 732     bool result = false;
 733 
 734     WaitForSingleObject(FProcessInfo.hProcess, INFINITE);
 735     return result;
 736 }
 737 
 738 TProcessID WindowsProcess::GetProcessID() {
 739     return FProcessInfo.dwProcessId;
 740 }
 741 
 742 bool WindowsProcess::ReadOutput() {
 743     bool result = false;
 744     //TODO implement
 745     return result;
 746 }
 747 
 748 void WindowsProcess::SetInput(TString Value) {
 749     //TODO implement
 750 }
 751 
 752 std::list<TString> WindowsProcess::GetOutput() {
 753     ReadOutput();
 754     return Process::GetOutput();
 755 }
 756 
 757 #endif //WINDOWS