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