libmoost
/home/mhx/git/github/libmoost/include/moost/io/detail/helper_win32.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_IO_DETAIL_HELPER_WIN32_HPP__
00029 #define MOOST_IO_DETAIL_HELPER_WIN32_HPP__
00030 
00031 #include <boost/asio.hpp>
00032 #include <windows.h>
00033 #include <strsafe.h>
00034 
00035 namespace moost { namespace io { namespace detail {
00036 
00037 class helper
00038 {
00039 public:
00040    typedef HANDLE native_io_t;
00041    typedef boost::asio::windows::basic_stream_handle<> async_stream_t;
00042    typedef DWORD error_t;
00043 
00044    static native_io_t duplicate(native_io_t in)
00045    {
00046       native_io_t duped;
00047 
00048       if (!DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), &duped, 0, FALSE, DUPLICATE_SAME_ACCESS))
00049       {
00050          throw std::runtime_error("failed to duplicate handle");
00051       }
00052 
00053       return duped;
00054    }
00055 
00056    static bool close(native_io_t in)
00057    {
00058       return CloseHandle(in) == TRUE;
00059    }
00060 
00061    static void create_pipe(native_io_t& read_end, native_io_t& write_end)
00062    {
00063       /*
00064        *  For some strange reason, anonymous pipes, even though they're using named pipes under
00065        *  the hood according to the documentation, do not support asynchronous i/o.
00066        *  So I'm resorting to creating a named pipe with a unique name here.
00067        */
00068 
00069       unsigned int instance = 0;
00070       const unsigned int max_instances = 100;
00071       std::basic_string<TCHAR> pipename;
00072       native_io_t pipe_read, pipe_write;
00073 
00074       while (instance < max_instances)
00075       {
00076          std::basic_stringstream<TCHAR> ss;
00077          ss << TEXT("\\\\.\\pipe\\") << GetCurrentProcessId() << TEXT("\\iohelper") << instance;
00078          pipename = ss.str();
00079 
00080          pipe_write = CreateNamedPipe(pipename.c_str(), PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
00081                                         PIPE_TYPE_BYTE | PIPE_WAIT, 1, 64, 64, 0, NULL);
00082 
00083          if (pipe_write != INVALID_HANDLE_VALUE)
00084          {
00085             break;
00086          }
00087 
00088          ++instance;
00089       }
00090 
00091       if (pipe_write == INVALID_HANDLE_VALUE)
00092       {
00093          throw std::runtime_error("failed to create named pipe");
00094       }
00095 
00096       try
00097       {
00098          pipe_read = CreateFile(pipename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
00099 
00100          if (pipe_read == INVALID_HANDLE_VALUE)
00101          {
00102             throw std::runtime_error("failed to open named pipe");
00103          }
00104       }
00105       catch (...)
00106       {
00107          CloseHandle(pipe_write);
00108 
00109          throw;
00110       }
00111 
00112       read_end = pipe_read;
00113       write_end = pipe_write;
00114    }
00115 
00116    static bool write(native_io_t io, const void *data, size_t length, size_t *written)
00117    {
00118       DWORD wr;
00119 
00120       bool rv = ::WriteFile(io, data, length, &wr, NULL) == TRUE;
00121 
00122       if (written)
00123       {
00124          *written = rv ? static_cast<size_t>(wr) : 0;
00125       }
00126 
00127       return rv;
00128    }
00129 
00130    static error_t error()
00131    {
00132       return GetLastError();
00133    }
00134 };
00135 
00136 } } }
00137 
00138 #endif