| Index: test/win/win_multiprocess.h | 
| diff --git a/test/win/win_multiprocess.h b/test/win/win_multiprocess.h | 
| index 7624adabec09f61220e3faa8ef858f3f8b77c713..906fa5dd16574710048293f5bfda1c58eff399fa 100644 | 
| --- a/test/win/win_multiprocess.h | 
| +++ b/test/win/win_multiprocess.h | 
| @@ -18,6 +18,8 @@ | 
| #include <windows.h> | 
|  | 
| #include "base/basictypes.h" | 
| +#include "gtest/gtest.h" | 
| +#include "test/win/win_child_process.h" | 
| #include "util/file/file_io.h" | 
| #include "util/win/scoped_handle.h" | 
|  | 
| @@ -36,7 +38,34 @@ class WinMultiprocess { | 
| //! | 
| //! In the parent process, WinMultiprocessParent() is run, and in the child | 
| //! WinMultiprocessChild(). | 
| -  void Run(); | 
| +  template <class T> | 
| +  static void Run() { | 
| +    ASSERT_NO_FATAL_FAILURE( | 
| +        WinChildProcess::EntryPoint<ChildProcessHelper<T>>()); | 
| +    // If WinChildProcess::EntryPoint returns, we are in the parent process. | 
| +    scoped_ptr<WinChildProcess::Handles> child_handles = | 
| +        WinChildProcess::Launch(); | 
| +    ASSERT_TRUE(child_handles.get()); | 
| +    T parent_process; | 
| +    parent_process.child_handles_ = child_handles.get(); | 
| +    static_cast<WinMultiprocess*>(&parent_process)->WinMultiprocessParent(); | 
| + | 
| +    // Close our side of the handles now that we're done. The child can | 
| +    // use this to know when it's safe to complete. | 
| +    child_handles->read.reset(); | 
| +    child_handles->write.reset(); | 
| + | 
| +    // Wait for the child to complete. | 
| +    ASSERT_EQ(WAIT_OBJECT_0, | 
| +              WaitForSingleObject(child_handles->process.get(), INFINITE)); | 
| + | 
| +    DWORD exit_code; | 
| +    ASSERT_TRUE(GetExitCodeProcess(child_handles->process.get(), &exit_code)); | 
| +    ASSERT_EQ(parent_process.exit_code_, exit_code); | 
| +  } | 
| + | 
| + protected: | 
| +  virtual ~WinMultiprocess(); | 
|  | 
| //! \brief Sets the expected exit code of the child process. | 
| //! | 
| @@ -45,9 +74,6 @@ class WinMultiprocess { | 
| //! \param[in] code The expected exit status of the child. | 
| void SetExpectedChildExitCode(unsigned int exit_code); | 
|  | 
| - protected: | 
| -  virtual ~WinMultiprocess(); | 
| - | 
| //! \brief Returns the read pipe's file handle. | 
| //! | 
| //! This method may be called by either the parent or the child process. | 
| @@ -89,6 +115,42 @@ class WinMultiprocess { | 
| HANDLE ChildProcess() const; | 
|  | 
| private: | 
| +  // Implements an adapter to provide WinMultiprocess with access to the | 
| +  // anonymous pipe handles from WinChildProcess. | 
| +  class ChildProcessHelperBase : public WinChildProcess { | 
| +   public: | 
| +    ChildProcessHelperBase() {} | 
| +    ~ChildProcessHelperBase() override {} | 
| + | 
| +    void CloseWritePipeForwarder() { CloseWritePipe(); } | 
| +    void CloseReadPipeForwarder() { CloseReadPipe(); } | 
| +    FileHandle ReadPipeHandleForwarder() const { return ReadPipeHandle(); } | 
| +    FileHandle WritePipeHandleForwarder() const { return WritePipeHandle(); } | 
| + | 
| +   private: | 
| +    DISALLOW_COPY_AND_ASSIGN(ChildProcessHelperBase); | 
| +  }; | 
| + | 
| +  // Forwards WinChildProcess::Run to T::WinMultiprocessChild. | 
| +  template <class T> | 
| +  class ChildProcessHelper : public ChildProcessHelperBase { | 
| +   public: | 
| +    ChildProcessHelper() {} | 
| +    ~ChildProcessHelper() override {} | 
| + | 
| +   private: | 
| +    int Run() override { | 
| +      T child_process; | 
| +      child_process.child_process_helper_ = this; | 
| +      static_cast<WinMultiprocess*>(&child_process)->WinMultiprocessChild(); | 
| +      if (testing::Test::HasFailure()) | 
| +        return 255; | 
| +      return EXIT_SUCCESS; | 
| +    } | 
| + | 
| +    DISALLOW_COPY_AND_ASSIGN(ChildProcessHelper); | 
| +  }; | 
| + | 
| //! \brief The subclass-provided parent routine. | 
| //! | 
| //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | 
| @@ -111,12 +173,9 @@ class WinMultiprocess { | 
| //! method. | 
| virtual void WinMultiprocessChild() = 0; | 
|  | 
| -  ScopedFileHANDLE pipe_c2p_read_; | 
| -  ScopedFileHANDLE pipe_c2p_write_; | 
| -  ScopedFileHANDLE pipe_p2c_read_; | 
| -  ScopedFileHANDLE pipe_p2c_write_; | 
| -  ScopedKernelHANDLE child_handle_; | 
| unsigned int exit_code_; | 
| +  WinChildProcess::Handles* child_handles_; | 
| +  ChildProcessHelperBase* child_process_helper_; | 
|  | 
| DISALLOW_COPY_AND_ASSIGN(WinMultiprocess); | 
| }; | 
|  |