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