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 |