| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
| 6 #if defined(TARGET_OS_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
| 7 | 7 |
| 8 #include <process.h> // NOLINT | 8 #include <process.h> // NOLINT |
| 9 | 9 |
| 10 #include "bin/builtin.h" | 10 #include "bin/builtin.h" |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 L"%s_%s_%d", prefix, uuid_string, i + 1); | 392 L"%s_%s_%d", prefix, uuid_string, i + 1); |
| 393 } | 393 } |
| 394 status = RpcStringFreeW(&uuid_string); | 394 status = RpcStringFreeW(&uuid_string); |
| 395 if (status != RPC_S_OK) { | 395 if (status != RPC_S_OK) { |
| 396 return status; | 396 return status; |
| 397 } | 397 } |
| 398 return 0; | 398 return 0; |
| 399 } | 399 } |
| 400 | 400 |
| 401 | 401 |
| 402 class ProcessStarter { |
| 403 public: |
| 404 ProcessStarter(const char* path, |
| 405 char* arguments[], |
| 406 intptr_t arguments_length, |
| 407 const char* working_directory, |
| 408 char* environment[], |
| 409 intptr_t environment_length, |
| 410 ProcessStartMode mode, |
| 411 intptr_t* in, |
| 412 intptr_t* out, |
| 413 intptr_t* err, |
| 414 intptr_t* id, |
| 415 intptr_t* exit_handler, |
| 416 char** os_error_message) |
| 417 : path_(path), |
| 418 working_directory_(working_directory), |
| 419 mode_(mode), |
| 420 in_(in), |
| 421 out_(out), |
| 422 err_(err), |
| 423 id_(id), |
| 424 exit_handler_(exit_handler), |
| 425 os_error_message_(os_error_message) { |
| 426 stdin_handles_[kReadHandle] = INVALID_HANDLE_VALUE; |
| 427 stdin_handles_[kWriteHandle] = INVALID_HANDLE_VALUE; |
| 428 stdout_handles_[kReadHandle] = INVALID_HANDLE_VALUE; |
| 429 stdout_handles_[kWriteHandle] = INVALID_HANDLE_VALUE; |
| 430 stderr_handles_[kReadHandle] = INVALID_HANDLE_VALUE; |
| 431 stderr_handles_[kWriteHandle] = INVALID_HANDLE_VALUE; |
| 432 exit_handles_[kReadHandle] = INVALID_HANDLE_VALUE; |
| 433 exit_handles_[kWriteHandle] = INVALID_HANDLE_VALUE; |
| 434 |
| 435 // Transform input strings to system format. |
| 436 const wchar_t* system_path = StringUtils::Utf8ToWide(path_); |
| 437 wchar_t** system_arguments = new wchar_t*[arguments_length]; |
| 438 for (int i = 0; i < arguments_length; i++) { |
| 439 system_arguments[i] = StringUtils::Utf8ToWide(arguments[i]); |
| 440 } |
| 441 |
| 442 // Compute command-line length. |
| 443 int command_line_length = wcslen(system_path); |
| 444 for (int i = 0; i < arguments_length; i++) { |
| 445 command_line_length += wcslen(system_arguments[i]); |
| 446 } |
| 447 // Account for null termination and one space per argument. |
| 448 command_line_length += arguments_length + 1; |
| 449 |
| 450 // Put together command-line string. |
| 451 command_line_ = new wchar_t[command_line_length]; |
| 452 int len = 0; |
| 453 int remaining = command_line_length; |
| 454 int written = |
| 455 _snwprintf(command_line_ + len, remaining, L"%s", system_path); |
| 456 len += written; |
| 457 remaining -= written; |
| 458 ASSERT(remaining >= 0); |
| 459 for (int i = 0; i < arguments_length; i++) { |
| 460 written = |
| 461 _snwprintf( |
| 462 command_line_ + len, remaining, L" %s", system_arguments[i]); |
| 463 len += written; |
| 464 remaining -= written; |
| 465 ASSERT(remaining >= 0); |
| 466 } |
| 467 free(const_cast<wchar_t*>(system_path)); |
| 468 for (int i = 0; i < arguments_length; i++) free(system_arguments[i]); |
| 469 delete[] system_arguments; |
| 470 |
| 471 // Create environment block if an environment is supplied. |
| 472 environment_block_ = NULL; |
| 473 if (environment != NULL) { |
| 474 wchar_t** system_environment = new wchar_t*[environment_length]; |
| 475 // Convert environment strings to system strings. |
| 476 for (intptr_t i = 0; i < environment_length; i++) { |
| 477 system_environment[i] = StringUtils::Utf8ToWide(environment[i]); |
| 478 } |
| 479 |
| 480 // An environment block is a sequence of zero-terminated strings |
| 481 // followed by a block-terminating zero char. |
| 482 intptr_t block_size = 1; |
| 483 for (intptr_t i = 0; i < environment_length; i++) { |
| 484 block_size += wcslen(system_environment[i]) + 1; |
| 485 } |
| 486 environment_block_ = new wchar_t[block_size]; |
| 487 intptr_t block_index = 0; |
| 488 for (intptr_t i = 0; i < environment_length; i++) { |
| 489 intptr_t len = wcslen(system_environment[i]); |
| 490 intptr_t result = _snwprintf(environment_block_ + block_index, |
| 491 len, |
| 492 L"%s", |
| 493 system_environment[i]); |
| 494 ASSERT(result == len); |
| 495 block_index += len; |
| 496 environment_block_[block_index++] = '\0'; |
| 497 } |
| 498 // Block-terminating zero char. |
| 499 environment_block_[block_index++] = '\0'; |
| 500 ASSERT(block_index == block_size); |
| 501 for (intptr_t i = 0; i < environment_length; i++) { |
| 502 free(system_environment[i]); |
| 503 } |
| 504 delete[] system_environment; |
| 505 } |
| 506 |
| 507 system_working_directory_ = NULL; |
| 508 if (working_directory_ != NULL) { |
| 509 system_working_directory_ = StringUtils::Utf8ToWide(working_directory_); |
| 510 } |
| 511 |
| 512 attribute_list_ = NULL; |
| 513 } |
| 514 |
| 515 |
| 516 ~ProcessStarter() { |
| 517 // Deallocate command-line and environment block strings. |
| 518 delete[] command_line_; |
| 519 delete[] environment_block_; |
| 520 if (system_working_directory_ != NULL) { |
| 521 free(const_cast<wchar_t*>(system_working_directory_)); |
| 522 } |
| 523 if (attribute_list_ != NULL) { |
| 524 delete_proc_thread_attr_list(attribute_list_); |
| 525 free(attribute_list_); |
| 526 } |
| 527 } |
| 528 |
| 529 |
| 530 int Start() { |
| 531 // Create pipes required. |
| 532 int err = CreatePipes(); |
| 533 if (err != 0) return err; |
| 534 |
| 535 // Setup info structures. |
| 536 STARTUPINFOEXW startup_info; |
| 537 ZeroMemory(&startup_info, sizeof(startup_info)); |
| 538 startup_info.StartupInfo.cb = sizeof(startup_info); |
| 539 startup_info.StartupInfo.hStdInput = stdin_handles_[kReadHandle]; |
| 540 startup_info.StartupInfo.hStdOutput = stdout_handles_[kWriteHandle]; |
| 541 startup_info.StartupInfo.hStdError = stderr_handles_[kWriteHandle]; |
| 542 startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES; |
| 543 |
| 544 bool supports_proc_thread_attr_lists = EnsureInitialized(); |
| 545 if (supports_proc_thread_attr_lists) { |
| 546 // Setup the handles to inherit. We only want to inherit the three handles |
| 547 // for stdin, stdout and stderr. |
| 548 SIZE_T size = 0; |
| 549 // The call to determine the size of an attribute list always fails with |
| 550 // ERROR_INSUFFICIENT_BUFFER and that error should be ignored. |
| 551 if (!init_proc_thread_attr_list(NULL, 1, 0, &size) && |
| 552 GetLastError() != ERROR_INSUFFICIENT_BUFFER) { |
| 553 return CleanupAndReturnError(); |
| 554 } |
| 555 attribute_list_ = |
| 556 reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(malloc(size)); |
| 557 ZeroMemory(attribute_list_, size); |
| 558 if (!init_proc_thread_attr_list(attribute_list_, 1, 0, &size)) { |
| 559 return CleanupAndReturnError(); |
| 560 } |
| 561 static const int kNumInheritedHandles = 3; |
| 562 HANDLE inherited_handles[kNumInheritedHandles] = |
| 563 { stdin_handles_[kReadHandle], |
| 564 stdout_handles_[kWriteHandle], |
| 565 stderr_handles_[kWriteHandle] }; |
| 566 if (!update_proc_thread_attr(attribute_list_, |
| 567 0, |
| 568 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, |
| 569 inherited_handles, |
| 570 kNumInheritedHandles * sizeof(HANDLE), |
| 571 NULL, |
| 572 NULL)) { |
| 573 return CleanupAndReturnError(); |
| 574 } |
| 575 startup_info.lpAttributeList = attribute_list_; |
| 576 } |
| 577 |
| 578 PROCESS_INFORMATION process_info; |
| 579 ZeroMemory(&process_info, sizeof(process_info)); |
| 580 |
| 581 // Create process. |
| 582 DWORD creation_flags = |
| 583 EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT; |
| 584 if (mode_ != kNormal) { |
| 585 creation_flags |= DETACHED_PROCESS; |
| 586 } |
| 587 BOOL result = CreateProcessW(NULL, // ApplicationName |
| 588 command_line_, |
| 589 NULL, // ProcessAttributes |
| 590 NULL, // ThreadAttributes |
| 591 TRUE, // InheritHandles |
| 592 creation_flags, |
| 593 environment_block_, |
| 594 system_working_directory_, |
| 595 reinterpret_cast<STARTUPINFOW*>(&startup_info), |
| 596 &process_info); |
| 597 |
| 598 if (result == 0) { |
| 599 return CleanupAndReturnError(); |
| 600 } |
| 601 |
| 602 CloseHandle(stdin_handles_[kReadHandle]); |
| 603 CloseHandle(stdout_handles_[kWriteHandle]); |
| 604 CloseHandle(stderr_handles_[kWriteHandle]); |
| 605 if (mode_ == kNormal) { |
| 606 ProcessInfoList::AddProcess(process_info.dwProcessId, |
| 607 process_info.hProcess, |
| 608 exit_handles_[kWriteHandle]); |
| 609 } |
| 610 if (mode_ != kDetached) { |
| 611 // Connect the three stdio streams. |
| 612 FileHandle* stdin_handle = new FileHandle(stdin_handles_[kWriteHandle]); |
| 613 FileHandle* stdout_handle = new FileHandle(stdout_handles_[kReadHandle]); |
| 614 FileHandle* stderr_handle = new FileHandle(stderr_handles_[kReadHandle]); |
| 615 *in_ = reinterpret_cast<intptr_t>(stdout_handle); |
| 616 *out_ = reinterpret_cast<intptr_t>(stdin_handle); |
| 617 *err_ = reinterpret_cast<intptr_t>(stderr_handle); |
| 618 if (mode_ == kNormal) { |
| 619 FileHandle* exit_handle = new FileHandle(exit_handles_[kReadHandle]); |
| 620 *exit_handler_ = reinterpret_cast<intptr_t>(exit_handle); |
| 621 } |
| 622 } |
| 623 |
| 624 CloseHandle(process_info.hThread); |
| 625 |
| 626 // Return process id. |
| 627 *id_ = process_info.dwProcessId; |
| 628 return 0; |
| 629 } |
| 630 |
| 631 |
| 632 int CreatePipes() { |
| 633 // Generate unique pipe names for the four named pipes needed. |
| 634 wchar_t pipe_names[4][kMaxPipeNameSize]; |
| 635 int status = GenerateNames<4>(pipe_names); |
| 636 if (status != 0) { |
| 637 SetOsErrorMessage(os_error_message_); |
| 638 Log::PrintErr("UuidCreateSequential failed %d\n", status); |
| 639 return status; |
| 640 } |
| 641 |
| 642 if (mode_ != kDetached) { |
| 643 // Open pipes for stdin, stdout, stderr and for communicating the exit |
| 644 // code. |
| 645 if (!CreateProcessPipe(stdin_handles_, pipe_names[0], kInheritRead) || |
| 646 !CreateProcessPipe(stdout_handles_, pipe_names[1], kInheritWrite) || |
| 647 !CreateProcessPipe(stderr_handles_, pipe_names[2], kInheritWrite)) { |
| 648 return CleanupAndReturnError(); |
| 649 } |
| 650 // Only open exit code pipe for non detached processes. |
| 651 if (mode_ == kNormal) { |
| 652 if (!CreateProcessPipe(exit_handles_, pipe_names[3], kInheritNone)) { |
| 653 return CleanupAndReturnError(); |
| 654 } |
| 655 } |
| 656 } else { |
| 657 // Open NUL for stdin, stdout and stderr. |
| 658 if ((stdin_handles_[kReadHandle] = OpenNul()) == INVALID_HANDLE_VALUE || |
| 659 (stdout_handles_[kWriteHandle] = OpenNul()) == INVALID_HANDLE_VALUE || |
| 660 (stderr_handles_[kWriteHandle] = OpenNul()) == INVALID_HANDLE_VALUE) { |
| 661 return CleanupAndReturnError(); |
| 662 } |
| 663 } |
| 664 return 0; |
| 665 } |
| 666 |
| 667 |
| 668 int CleanupAndReturnError() { |
| 669 int error_code = SetOsErrorMessage(os_error_message_); |
| 670 CloseProcessPipes( |
| 671 stdin_handles_, stdout_handles_, stderr_handles_, exit_handles_); |
| 672 return error_code; |
| 673 } |
| 674 |
| 675 |
| 676 HANDLE stdin_handles_[2]; |
| 677 HANDLE stdout_handles_[2]; |
| 678 HANDLE stderr_handles_[2]; |
| 679 HANDLE exit_handles_[2]; |
| 680 |
| 681 const wchar_t* system_working_directory_; |
| 682 wchar_t* command_line_; |
| 683 wchar_t* environment_block_; |
| 684 LPPROC_THREAD_ATTRIBUTE_LIST attribute_list_; |
| 685 |
| 686 const char* path_; |
| 687 const char* working_directory_; |
| 688 ProcessStartMode mode_; |
| 689 intptr_t* in_; |
| 690 intptr_t* out_; |
| 691 intptr_t* err_; |
| 692 intptr_t* id_; |
| 693 intptr_t* exit_handler_; |
| 694 char** os_error_message_; |
| 695 }; |
| 696 |
| 697 |
| 402 int Process::Start(const char* path, | 698 int Process::Start(const char* path, |
| 403 char* arguments[], | 699 char* arguments[], |
| 404 intptr_t arguments_length, | 700 intptr_t arguments_length, |
| 405 const char* working_directory, | 701 const char* working_directory, |
| 406 char* environment[], | 702 char* environment[], |
| 407 intptr_t environment_length, | 703 intptr_t environment_length, |
| 408 bool detach, | 704 ProcessStartMode mode, |
| 409 intptr_t* in, | 705 intptr_t* in, |
| 410 intptr_t* out, | 706 intptr_t* out, |
| 411 intptr_t* err, | 707 intptr_t* err, |
| 412 intptr_t* id, | 708 intptr_t* id, |
| 413 intptr_t* exit_handler, | 709 intptr_t* exit_handler, |
| 414 char** os_error_message) { | 710 char** os_error_message) { |
| 415 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; | 711 ProcessStarter starter(path, |
| 416 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; | 712 arguments, |
| 417 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; | 713 arguments_length, |
| 418 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; | 714 working_directory, |
| 419 | 715 environment, |
| 420 // Generate unique pipe names for the four named pipes needed. | 716 environment_length, |
| 421 wchar_t pipe_names[4][kMaxPipeNameSize]; | 717 mode, |
| 422 int status = GenerateNames<4>(pipe_names); | 718 in, |
| 423 if (status != 0) { | 719 out, |
| 424 SetOsErrorMessage(os_error_message); | 720 err, |
| 425 Log::PrintErr("UuidCreateSequential failed %d\n", status); | 721 id, |
| 426 return status; | 722 exit_handler, |
| 427 } | 723 os_error_message); |
| 428 | 724 return starter.Start(); |
| 429 if (!detach) { | |
| 430 // Open pipes for stdin, stdout, stderr and for communicating the exit | |
| 431 // code. | |
| 432 if (!CreateProcessPipe(stdin_handles, pipe_names[0], kInheritRead)) { | |
| 433 int error_code = SetOsErrorMessage(os_error_message); | |
| 434 CloseProcessPipes( | |
| 435 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 436 return error_code; | |
| 437 } | |
| 438 if (!CreateProcessPipe(stdout_handles, pipe_names[1], kInheritWrite)) { | |
| 439 int error_code = SetOsErrorMessage(os_error_message); | |
| 440 CloseProcessPipes( | |
| 441 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 442 return error_code; | |
| 443 } | |
| 444 if (!CreateProcessPipe(stderr_handles, pipe_names[2], kInheritWrite)) { | |
| 445 int error_code = SetOsErrorMessage(os_error_message); | |
| 446 CloseProcessPipes( | |
| 447 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 448 return error_code; | |
| 449 } | |
| 450 if (!CreateProcessPipe(exit_handles, pipe_names[3], kInheritNone)) { | |
| 451 int error_code = SetOsErrorMessage(os_error_message); | |
| 452 CloseProcessPipes( | |
| 453 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 454 return error_code; | |
| 455 } | |
| 456 } else { | |
| 457 // Open NUL for stdin, stdout and stderr. | |
| 458 stdin_handles[kReadHandle] = OpenNul(); | |
| 459 if (stdin_handles[kReadHandle] == INVALID_HANDLE_VALUE) { | |
| 460 int error_code = SetOsErrorMessage(os_error_message); | |
| 461 CloseProcessPipes( | |
| 462 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 463 return error_code; | |
| 464 } | |
| 465 stdout_handles[kWriteHandle] = OpenNul(); | |
| 466 if (stdout_handles[kWriteHandle] == INVALID_HANDLE_VALUE) { | |
| 467 int error_code = SetOsErrorMessage(os_error_message); | |
| 468 CloseProcessPipes( | |
| 469 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 470 return error_code; | |
| 471 } | |
| 472 stderr_handles[kWriteHandle] = OpenNul(); | |
| 473 if (stderr_handles[kWriteHandle] == INVALID_HANDLE_VALUE) { | |
| 474 int error_code = SetOsErrorMessage(os_error_message); | |
| 475 CloseProcessPipes( | |
| 476 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 477 return error_code; | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 // Setup info structures. | |
| 482 STARTUPINFOEXW startup_info; | |
| 483 ZeroMemory(&startup_info, sizeof(startup_info)); | |
| 484 startup_info.StartupInfo.cb = sizeof(startup_info); | |
| 485 startup_info.StartupInfo.hStdInput = stdin_handles[kReadHandle]; | |
| 486 startup_info.StartupInfo.hStdOutput = stdout_handles[kWriteHandle]; | |
| 487 startup_info.StartupInfo.hStdError = stderr_handles[kWriteHandle]; | |
| 488 startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES; | |
| 489 | |
| 490 LPPROC_THREAD_ATTRIBUTE_LIST attribute_list = NULL; | |
| 491 | |
| 492 bool supports_proc_thread_attr_lists = EnsureInitialized(); | |
| 493 if (supports_proc_thread_attr_lists) { | |
| 494 // Setup the handles to inherit. We only want to inherit the three handles | |
| 495 // for stdin, stdout and stderr. | |
| 496 SIZE_T size = 0; | |
| 497 // The call to determine the size of an attribute list always fails with | |
| 498 // ERROR_INSUFFICIENT_BUFFER and that error should be ignored. | |
| 499 if (!init_proc_thread_attr_list(NULL, 1, 0, &size) && | |
| 500 GetLastError() != ERROR_INSUFFICIENT_BUFFER) { | |
| 501 int error_code = SetOsErrorMessage(os_error_message); | |
| 502 CloseProcessPipes( | |
| 503 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 504 return error_code; | |
| 505 } | |
| 506 attribute_list = | |
| 507 reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(malloc(size)); | |
| 508 ZeroMemory(attribute_list, size); | |
| 509 if (!init_proc_thread_attr_list(attribute_list, 1, 0, &size)) { | |
| 510 int error_code = SetOsErrorMessage(os_error_message); | |
| 511 CloseProcessPipes( | |
| 512 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 513 free(attribute_list); | |
| 514 return error_code; | |
| 515 } | |
| 516 static const int kNumInheritedHandles = 3; | |
| 517 HANDLE inherited_handles[kNumInheritedHandles] = | |
| 518 { stdin_handles[kReadHandle], | |
| 519 stdout_handles[kWriteHandle], | |
| 520 stderr_handles[kWriteHandle] }; | |
| 521 if (!update_proc_thread_attr(attribute_list, | |
| 522 0, | |
| 523 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, | |
| 524 inherited_handles, | |
| 525 kNumInheritedHandles * sizeof(HANDLE), | |
| 526 NULL, | |
| 527 NULL)) { | |
| 528 delete_proc_thread_attr_list(attribute_list); | |
| 529 int error_code = SetOsErrorMessage(os_error_message); | |
| 530 CloseProcessPipes( | |
| 531 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 532 free(attribute_list); | |
| 533 return error_code; | |
| 534 } | |
| 535 startup_info.lpAttributeList = attribute_list; | |
| 536 } | |
| 537 | |
| 538 PROCESS_INFORMATION process_info; | |
| 539 ZeroMemory(&process_info, sizeof(process_info)); | |
| 540 | |
| 541 // Transform input strings to system format. | |
| 542 const wchar_t* system_path = StringUtils::Utf8ToWide(path); | |
| 543 wchar_t** system_arguments = new wchar_t*[arguments_length]; | |
| 544 for (int i = 0; i < arguments_length; i++) { | |
| 545 system_arguments[i] = StringUtils::Utf8ToWide(arguments[i]); | |
| 546 } | |
| 547 | |
| 548 // Compute command-line length. | |
| 549 int command_line_length = wcslen(system_path); | |
| 550 for (int i = 0; i < arguments_length; i++) { | |
| 551 command_line_length += wcslen(system_arguments[i]); | |
| 552 } | |
| 553 // Account for null termination and one space per argument. | |
| 554 command_line_length += arguments_length + 1; | |
| 555 static const int kMaxCommandLineLength = 32768; | |
| 556 if (command_line_length > kMaxCommandLineLength) { | |
| 557 int error_code = SetOsErrorMessage(os_error_message); | |
| 558 CloseProcessPipes( | |
| 559 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 560 free(const_cast<wchar_t*>(system_path)); | |
| 561 for (int i = 0; i < arguments_length; i++) free(system_arguments[i]); | |
| 562 delete[] system_arguments; | |
| 563 if (supports_proc_thread_attr_lists) { | |
| 564 delete_proc_thread_attr_list(attribute_list); | |
| 565 free(attribute_list); | |
| 566 } | |
| 567 return error_code; | |
| 568 } | |
| 569 | |
| 570 // Put together command-line string. | |
| 571 wchar_t* command_line = new wchar_t[command_line_length]; | |
| 572 int len = 0; | |
| 573 int remaining = command_line_length; | |
| 574 int written = _snwprintf(command_line + len, remaining, L"%s", system_path); | |
| 575 len += written; | |
| 576 remaining -= written; | |
| 577 ASSERT(remaining >= 0); | |
| 578 for (int i = 0; i < arguments_length; i++) { | |
| 579 written = | |
| 580 _snwprintf(command_line + len, remaining, L" %s", system_arguments[i]); | |
| 581 len += written; | |
| 582 remaining -= written; | |
| 583 ASSERT(remaining >= 0); | |
| 584 } | |
| 585 free(const_cast<wchar_t*>(system_path)); | |
| 586 for (int i = 0; i < arguments_length; i++) free(system_arguments[i]); | |
| 587 delete[] system_arguments; | |
| 588 | |
| 589 // Create environment block if an environment is supplied. | |
| 590 wchar_t* environment_block = NULL; | |
| 591 if (environment != NULL) { | |
| 592 wchar_t** system_environment = new wchar_t*[environment_length]; | |
| 593 // Convert environment strings to system strings. | |
| 594 for (intptr_t i = 0; i < environment_length; i++) { | |
| 595 system_environment[i] = StringUtils::Utf8ToWide(environment[i]); | |
| 596 } | |
| 597 | |
| 598 // An environment block is a sequence of zero-terminated strings | |
| 599 // followed by a block-terminating zero char. | |
| 600 intptr_t block_size = 1; | |
| 601 for (intptr_t i = 0; i < environment_length; i++) { | |
| 602 block_size += wcslen(system_environment[i]) + 1; | |
| 603 } | |
| 604 environment_block = new wchar_t[block_size]; | |
| 605 intptr_t block_index = 0; | |
| 606 for (intptr_t i = 0; i < environment_length; i++) { | |
| 607 intptr_t len = wcslen(system_environment[i]); | |
| 608 intptr_t result = _snwprintf(environment_block + block_index, | |
| 609 len, | |
| 610 L"%s", | |
| 611 system_environment[i]); | |
| 612 ASSERT(result == len); | |
| 613 block_index += len; | |
| 614 environment_block[block_index++] = '\0'; | |
| 615 } | |
| 616 // Block-terminating zero char. | |
| 617 environment_block[block_index++] = '\0'; | |
| 618 ASSERT(block_index == block_size); | |
| 619 for (intptr_t i = 0; i < environment_length; i++) { | |
| 620 free(system_environment[i]); | |
| 621 } | |
| 622 delete[] system_environment; | |
| 623 } | |
| 624 | |
| 625 const wchar_t* system_working_directory = NULL; | |
| 626 if (working_directory != NULL) { | |
| 627 system_working_directory = StringUtils::Utf8ToWide(working_directory); | |
| 628 } | |
| 629 | |
| 630 // Create process. | |
| 631 DWORD creation_flags = | |
| 632 EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT; | |
| 633 if (detach) { | |
| 634 creation_flags |= DETACHED_PROCESS; | |
| 635 } | |
| 636 BOOL result = CreateProcessW(NULL, // ApplicationName | |
| 637 command_line, | |
| 638 NULL, // ProcessAttributes | |
| 639 NULL, // ThreadAttributes | |
| 640 TRUE, // InheritHandles | |
| 641 creation_flags, | |
| 642 environment_block, | |
| 643 system_working_directory, | |
| 644 reinterpret_cast<STARTUPINFOW*>(&startup_info), | |
| 645 &process_info); | |
| 646 // Deallocate command-line and environment block strings. | |
| 647 delete[] command_line; | |
| 648 delete[] environment_block; | |
| 649 if (system_working_directory != NULL) { | |
| 650 free(const_cast<wchar_t*>(system_working_directory)); | |
| 651 } | |
| 652 | |
| 653 if (supports_proc_thread_attr_lists) { | |
| 654 delete_proc_thread_attr_list(attribute_list); | |
| 655 free(attribute_list); | |
| 656 } | |
| 657 | |
| 658 if (result == 0) { | |
| 659 int error_code = SetOsErrorMessage(os_error_message); | |
| 660 CloseProcessPipes( | |
| 661 stdin_handles, stdout_handles, stderr_handles, exit_handles); | |
| 662 return error_code; | |
| 663 } | |
| 664 | |
| 665 CloseHandle(stdin_handles[kReadHandle]); | |
| 666 CloseHandle(stdout_handles[kWriteHandle]); | |
| 667 CloseHandle(stderr_handles[kWriteHandle]); | |
| 668 if (!detach) { | |
| 669 ProcessInfoList::AddProcess(process_info.dwProcessId, | |
| 670 process_info.hProcess, | |
| 671 exit_handles[kWriteHandle]); | |
| 672 | |
| 673 // Connect the three std streams. | |
| 674 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]); | |
| 675 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]); | |
| 676 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]); | |
| 677 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]); | |
| 678 *in = reinterpret_cast<intptr_t>(stdout_handle); | |
| 679 *out = reinterpret_cast<intptr_t>(stdin_handle); | |
| 680 *err = reinterpret_cast<intptr_t>(stderr_handle); | |
| 681 *exit_handler = reinterpret_cast<intptr_t>(exit_handle); | |
| 682 } | |
| 683 | |
| 684 CloseHandle(process_info.hThread); | |
| 685 | |
| 686 // Return process id. | |
| 687 *id = process_info.dwProcessId; | |
| 688 return 0; | |
| 689 } | 725 } |
| 690 | 726 |
| 691 | 727 |
| 692 class BufferList: public BufferListBase { | 728 class BufferList: public BufferListBase { |
| 693 public: | 729 public: |
| 694 BufferList() : read_pending_(true) { } | 730 BufferList() : read_pending_(true) { } |
| 695 | 731 |
| 696 // Indicate that data has been read into the buffer provided to | 732 // Indicate that data has been read into the buffer provided to |
| 697 // overlapped read. | 733 // overlapped read. |
| 698 void DataIsRead(intptr_t size) { | 734 void DataIsRead(intptr_t size) { |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 USE(SetConsoleCtrlHandler(SignalHandler, false)); | 1042 USE(SetConsoleCtrlHandler(SignalHandler, false)); |
| 1007 } | 1043 } |
| 1008 } | 1044 } |
| 1009 delete handler; | 1045 delete handler; |
| 1010 } | 1046 } |
| 1011 | 1047 |
| 1012 } // namespace bin | 1048 } // namespace bin |
| 1013 } // namespace dart | 1049 } // namespace dart |
| 1014 | 1050 |
| 1015 #endif // defined(TARGET_OS_WINDOWS) | 1051 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |